diff --git a/DEPS b/DEPS index 21df65c2..ee2538e 100644 --- a/DEPS +++ b/DEPS
@@ -133,11 +133,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': '3fd1841161d17c99a916da6fc0a2f8e5f06b962d', + 'skia_revision': '2f3637bf2ed44ef75966786ab4c2974d17c9f649', # 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': '5b1fde36ed3b4790d61938274cd83cfe88217ce4', + 'v8_revision': '982a060f43f1e9eb93494dada58919a86494e59b', # 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. @@ -145,11 +145,11 @@ # 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': '6f0c5b8dd5f2647131e345edea353419d5f35ed2', + 'angle_revision': '37860a7071638d55e1947fd0e17cb3fab3b9e6c3', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. - 'swiftshader_revision': 'bb12b0e41a091fe6b76003e66f08196b88290a81', + 'swiftshader_revision': 'ac8733475c13e04ce68357444295c56b5a8b3aee', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. @@ -256,7 +256,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. - 'spv_tools_revision': '5fc5303eeceb82df64abb6db4bbdf3b55a6cd591', + 'spv_tools_revision': 'eef11cdb7185e89108d1a7a0318278f363ebfb27', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -272,11 +272,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. - 'dawn_revision': 'f54bb68f47ec718ab9175a9956e44959d2976301', + 'dawn_revision': '8804bc541ebb71b1646bc1c842c65c85e46d9ef3', # 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': '2c2444e99d33294db4e067b4e8d42d123a460ba2', + 'quiche_revision': '5de87051f54ddaa1a78783edbda5f0bf473023b4', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ios_webkit # and whatever else without interference from each other. @@ -1028,7 +1028,7 @@ }, 'src/third_party/leveldatabase/src': - Var('chromium_git') + '/external/leveldb.git' + '@' + '506b1722ef1a58d87325575d9bbcd3c8869381c7', + Var('chromium_git') + '/external/leveldb.git' + '@' + '4bd052d7e8b0469b2b87664388e2a99cb212ecdb', 'src/third_party/libFuzzer/src': Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git' + '@' + Var('libfuzzer_revision'), @@ -1396,7 +1396,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@f3f53a5470410b6ca96542c03e04d185a984a099', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@d469f480e06dc7f9d591803f81cbbca5a50a9cce', 'condition': 'checkout_src_internal', },
diff --git a/ash/public/cpp/app_list/app_list_features.cc b/ash/public/cpp/app_list/app_list_features.cc index 9c580fd..d21c63f 100644 --- a/ash/public/cpp/app_list/app_list_features.cc +++ b/ash/public/cpp/app_list/app_list_features.cc
@@ -39,6 +39,8 @@ "EnableEmbeddedAssistantUI", base::FEATURE_DISABLED_BY_DEFAULT}; const base::Feature kEnableAppGridGhost{"EnableAppGridGhost", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kEnableAppListLaunchRecording{ + "EnableAppListLaunchRecording", base::FEATURE_DISABLED_BY_DEFAULT}; bool IsAnswerCardEnabled() { // Not using local static variable to allow tests to change this value. @@ -122,4 +124,8 @@ return std::string("MrfuAppLaunchPredictor"); } +bool IsAppListLaunchRecordingEnabled() { + return base::FeatureList::IsEnabled(kEnableAppListLaunchRecording); +} + } // namespace app_list_features
diff --git a/ash/public/cpp/app_list/app_list_features.h b/ash/public/cpp/app_list/app_list_features.h index e7fb92e..59682837 100644 --- a/ash/public/cpp/app_list/app_list_features.h +++ b/ash/public/cpp/app_list/app_list_features.h
@@ -63,6 +63,9 @@ // Enables ghosting in any AppsGridView (folder or root) when dragging an item. ASH_PUBLIC_EXPORT extern const base::Feature kEnableAppGridGhost; +// Enables hashed recording of a app list launches. +ASH_PUBLIC_EXPORT extern const base::Feature kEnableAppListLaunchRecording; + bool ASH_PUBLIC_EXPORT IsAnswerCardEnabled(); bool ASH_PUBLIC_EXPORT IsBackgroundBlurEnabled(); bool ASH_PUBLIC_EXPORT IsPlayStoreAppSearchEnabled(); @@ -77,6 +80,7 @@ bool ASH_PUBLIC_EXPORT IsAppReinstallZeroStateEnabled(); bool ASH_PUBLIC_EXPORT IsEmbeddedAssistantUIEnabled(); bool ASH_PUBLIC_EXPORT IsAppGridGhostEnabled(); +bool ASH_PUBLIC_EXPORT IsAppListLaunchRecordingEnabled(); std::string ASH_PUBLIC_EXPORT AnswerServerUrl(); std::string ASH_PUBLIC_EXPORT AnswerServerQuerySuffix();
diff --git a/ash/system/toast/toast_manager_unittest.cc b/ash/system/toast/toast_manager_unittest.cc index 8104f5e..34357920 100644 --- a/ash/system/toast/toast_manager_unittest.cc +++ b/ash/system/toast/toast_manager_unittest.cc
@@ -142,7 +142,8 @@ EXPECT_EQ(nullptr, GetCurrentOverlay()); } -TEST_F(ToastManagerTest, ShowAndCloseManuallyDuringAnimation) { +// TODO(crbug.com/959781): Test is flaky. +TEST_F(ToastManagerTest, DISABLED_ShowAndCloseManuallyDuringAnimation) { ui::ScopedAnimationDurationScaleMode slow_animation_duration( ui::ScopedAnimationDurationScaleMode::SLOW_DURATION); @@ -163,13 +164,15 @@ EXPECT_TRUE(GetCurrentOverlay() != nullptr); } -TEST_F(ToastManagerTest, NullMessageHasNoDismissButton) { +// TODO(crbug.com/959781): Test is flaky. +TEST_F(ToastManagerTest, DISABLED_NullMessageHasNoDismissButton) { ShowToastWithDismiss("DUMMY", 10, base::Optional<std::string>()); base::RunLoop().RunUntilIdle(); EXPECT_FALSE(GetDismissButton()); } -TEST_F(ToastManagerTest, QueueMessage) { +// TODO(crbug.com/959781): Test is flaky. +TEST_F(ToastManagerTest, DISABLED_QueueMessage) { ShowToast("DUMMY1", 10); ShowToast("DUMMY2", 10); ShowToast("DUMMY3", 10);
diff --git a/base/android/orderfile/BUILD.gn b/base/android/orderfile/BUILD.gn index 41a372f..682bcdce 100644 --- a/base/android/orderfile/BUILD.gn +++ b/base/android/orderfile/BUILD.gn
@@ -7,9 +7,15 @@ if (use_order_profiling && (target_cpu == "arm" || target_cpu == "arm64")) { static_library("orderfile_instrumentation") { sources = [ - "orderfile_instrumentation.cc", "orderfile_instrumentation.h", ] + + if (use_call_graph) { + sources += [ "orderfile_call_graph_instrumentation.cc" ] + } else { + sources += [ "orderfile_instrumentation.cc" ] + } + deps = [ "//base", ] @@ -17,18 +23,21 @@ executable("orderfile_instrumentation_perftest") { testonly = true - - sources = [ - "orderfile_instrumentation_perftest.cc", - ] - + if (use_call_graph) { + sources = [ + "orderfile_call_graph_instrumentation_perftest.cc", + ] + } else { + sources = [ + "orderfile_instrumentation_perftest.cc", + ] + } deps = [ ":orderfile_instrumentation", "//base", "//testing/gtest", "//testing/perf", ] - configs -= [ "//build/config/android:default_orderfile_instrumentation" ] } }
diff --git a/base/android/orderfile/orderfile_call_graph_instrumentation.cc b/base/android/orderfile/orderfile_call_graph_instrumentation.cc new file mode 100644 index 0000000..1cd297d --- /dev/null +++ b/base/android/orderfile/orderfile_call_graph_instrumentation.cc
@@ -0,0 +1,413 @@ +// 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/android/orderfile/orderfile_instrumentation.h" + +#include <time.h> +#include <unistd.h> + +#include <atomic> +#include <cstdio> +#include <cstring> +#include <string> +#include <thread> +#include <vector> + +#include "base/android/library_loader/anchor_functions.h" +#include "base/android/orderfile/orderfile_buildflags.h" +#include "base/files/file.h" +#include "base/format_macros.h" +#include "base/json/json_writer.h" +#include "base/logging.h" +#include "base/macros.h" +#include "base/strings/stringprintf.h" +#include "base/values.h" +#include "build/build_config.h" + +#if BUILDFLAG(DEVTOOLS_INSTRUMENTATION_DUMPING) +#include <sstream> + +#include "base/command_line.h" +#include "base/time/time.h" +#include "base/trace_event/memory_dump_manager.h" +#include "base/trace_event/memory_dump_provider.h" +#endif // BUILDFLAG(DEVTOOLS_INSTRUMENTATION_DUMPING) + +#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)) +#define INLINE_AND_NO_INSTRUMENT_FUNCTION \ + __attribute__((always_inline, no_instrument_function)) + +namespace base { +namespace android { +namespace orderfile { + +namespace { + +#if BUILDFLAG(DEVTOOLS_INSTRUMENTATION_DUMPING) +// This is defined in content/public/common/content_switches.h, which is not +// accessible in ::base. +constexpr const char kProcessTypeSwitch[] = "type"; +#else +// Constant used for StartDelayedDump(). +constexpr int kDelayInSeconds = 30; +#endif // BUILDFLAG(DEVTOOLS_INSTRUMENTATION_DUMPING) + +constexpr size_t kMaxTextSizeInBytes = 1 << 27; +constexpr size_t kMaxElements = kMaxTextSizeInBytes / 4; +// Native code currently have ~850k symbols, hence recording up to 1M symbols +// can cover all possible callee symbols. +constexpr size_t kMaxReachedSymbols = 1 << 20; +// 3 callers are recorded per callee. +constexpr size_t kCallerBuckets = 3; +// The last bucket is to count for misses and callers from outside the +// native code bounds. +constexpr size_t kMissesBucketIndex = 3; +constexpr size_t kTotalBuckets = 4; + +std::atomic<uint32_t> callee_map[kMaxElements]; +static_assert(sizeof(callee_map) == 128 * (1 << 20), ""); +// Contain caller offsets. 4 buckets of callers per callee where the +// last bucket is for misses. +std::atomic<uint32_t> g_caller_offset[kMaxReachedSymbols * kTotalBuckets]; +static_assert(sizeof(g_caller_offset) == 16 * (1 << 20), ""); +// Corresponding count of |g_caller_offset|. +std::atomic<uint32_t> g_caller_count[kMaxReachedSymbols * kTotalBuckets]; +static_assert(sizeof(g_caller_count) == 16 * (1 << 20), ""); +// Index for |g_caller_offset| and |g_caller_count|. +std::atomic<uint32_t> g_callers_index; +std::atomic<bool> g_disabled; + +#if BUILDFLAG(DEVTOOLS_INSTRUMENTATION_DUMPING) +// Dump offsets when a memory dump is requested. Used only if +// switches::kDevtoolsInstrumentationDumping is set. +class OrderfileMemoryDumpHook : public base::trace_event::MemoryDumpProvider { + NO_INSTRUMENT_FUNCTION bool OnMemoryDump( + const base::trace_event::MemoryDumpArgs& args, + base::trace_event::ProcessMemoryDump* pmd) override { + if (!Disable()) + return true; // A dump has already been started. + + std::string process_type = + base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( + kProcessTypeSwitch); + if (process_type.empty()) + process_type = "browser"; + + Dump(process_type); + return true; // If something goes awry, a fatal error will be created + // internally. + } +}; +#endif // BUILDFLAG(DEVTOOLS_INSTRUMENTATION_DUMPING) + +// This is not racy. It is guaranteed that any number of threads concurrently +// calling this function in any order, will always end up with the same count +// at the end. It returns |element|'s value before the increment. +INLINE_AND_NO_INSTRUMENT_FUNCTION uint32_t +AtomicIncrement(std::atomic<uint32_t>* element) { + return element->fetch_add(1, std::memory_order_relaxed); +} + +// Increment the miss bucket for a callee. |index| is the first bucket of +// callers for this callee. +INLINE_AND_NO_INSTRUMENT_FUNCTION void RecordMiss(size_t index) { + AtomicIncrement(g_caller_count + index + kMissesBucketIndex); +} + +// Increment the caller count if it has previously been registered. +// If it hasn't, search for an empty bucket and register the caller. +// Otherwise, return false. +// |index| is the first bucket to register callers for a certain callee. +INLINE_AND_NO_INSTRUMENT_FUNCTION bool RecordCaller(size_t index, + size_t caller_offset) { + for (size_t i = index; i < index + kCallerBuckets; i++) { + auto offset = g_caller_offset[i].load(std::memory_order_relaxed); + // This check is racy, a write could have happened between the load and the + // check. + if (offset == caller_offset) { + // Caller already recorded, increment the count. + AtomicIncrement(g_caller_count + i); + return true; + } + } + + for (size_t i = index; i < index + kCallerBuckets; i++) { + auto offset = g_caller_offset[i].load(std::memory_order_relaxed); + size_t expected = 0; + if (!offset) { + // This is not racy as the compare and exchange is done atomically. + // It is impossible to reset a bucket if it has already been set. It + // exchanges the value in |g_caller_offset[i]| with |caller_offset| if + // the value in |g_caller_offset[i] == expected|. + // Otherwise, returns false and set |expected = g_caller_offset[i]|. + if (g_caller_offset[i].compare_exchange_strong( + expected, caller_offset, std::memory_order_relaxed, + std::memory_order_relaxed)) { + AtomicIncrement(g_caller_count + i); + return true; + } + } + // This will decrease the chances that we miss something due to unseen + // changes made by another thread. + if (offset == caller_offset || expected == caller_offset) { + AtomicIncrement(g_caller_count + i); + return true; + } + } + return false; +} + +template <bool for_testing> +__attribute__((always_inline, no_instrument_function)) void RecordAddress( + size_t callee_address, + size_t caller_address) { + bool disabled = g_disabled.load(std::memory_order_relaxed); + if (disabled) + return; + + const size_t start = + for_testing ? kStartOfTextForTesting : base::android::kStartOfText; + const size_t end = + for_testing ? kEndOfTextForTesting : base::android::kEndOfText; + + if (UNLIKELY(callee_address < start || callee_address > end)) { + // Only the code in the native library is instrumented. Callees are expected + // to be within the native library bounds. + Disable(); + IMMEDIATE_CRASH(); + } + + size_t offset = callee_address - start; + static_assert(sizeof(int) == 4, + "Collection and processing code assumes that sizeof(int) == 4"); + + size_t offset_index = offset / 4; + + if (UNLIKELY(offset_index >= kMaxElements)) + return; + + std::atomic<uint32_t>* element = callee_map + offset_index; + uint32_t callers_index = element->load(std::memory_order_relaxed); + + // Racy check. + if (callers_index == 0) { + // Fragmentation is possible as we increment the |insertion_index| based on + // a racy check. + uint32_t insertion_index = AtomicIncrement(&g_callers_index) + 1; + if (UNLIKELY(insertion_index >= kMaxReachedSymbols)) + return; + + uint32_t expected = 0; + // Exchanges the value in |element| with |insertion_index| if the value in + // |element == expected|. Otherwise, set |expected = element|. + element->compare_exchange_strong(expected, insertion_index, + std::memory_order_relaxed, + std::memory_order_relaxed); + // If expected is set, then this callee has previously been seen and already + // has a corresponding index in the callers array. + callers_index = expected == 0 ? insertion_index : expected; + } + + callers_index *= kTotalBuckets; + if (caller_address <= start || caller_address > end || + !RecordCaller(callers_index, caller_address - start)) { + // Record as a Miss, if the caller is not within the bounds of the native + // code or there are no empty buckets to record one more caller for this + // callee. + RecordMiss(callers_index); + } +} + +NO_INSTRUMENT_FUNCTION bool DumpToFile(const base::FilePath& path) { + auto file = + base::File(path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); + if (!file.IsValid()) { + PLOG(ERROR) << "Could not open " << path; + return false; + } + + if (g_callers_index == 0) { + LOG(ERROR) << "No entries to dump"; + return false; + } + + // This can get very large as it constructs the whole data structure in + // memory before dumping it to the file. + ListValue root; + for (size_t i = 0; i < kMaxElements; i++) { + auto caller_index = + callee_map[i].load(std::memory_order_relaxed) * kTotalBuckets; + if (!caller_index) + // This callee was never called. + continue; + + DictionaryValue callee_element; + uint32_t callee_offset = i * 4; + callee_element.SetStringKey("index", + base::StringPrintf("%" PRIuS, caller_index)); + callee_element.SetStringKey("callee_offset", + base::StringPrintf("%" PRIu32, callee_offset)); + std::string offset_str = ""; + ListValue callers_list; + for (size_t j = 0; j < kTotalBuckets; j++) { + uint32_t caller_offset = + g_caller_offset[caller_index + j].load(std::memory_order_relaxed); + + // The last bucket is for misses or callers outside the native library, + // the caller_offset for this bucket is 0. + if (j != kMissesBucketIndex && !caller_offset) + continue; + + uint32_t count = + g_caller_count[caller_index + j].load(std::memory_order_relaxed); + // The count can only be 0 for the misses bucket. Otherwise, + // if |caller_offset| is set then the count must be >= 1. + CHECK_EQ(count || j == kMissesBucketIndex, true); + if (!count) + // No misses. + continue; + + DictionaryValue caller_count; + caller_count.SetStringKey("caller_offset", + base::StringPrintf("%" PRIu32, caller_offset)); + caller_count.SetStringKey("count", base::StringPrintf("%" PRIu32, count)); + callers_list.GetList().push_back(std::move(caller_count)); + } + callee_element.SetKey("caller_and_count", std::move(callers_list)); + root.GetList().push_back(std::move(callee_element)); + } + + std::string output_js; + if (!JSONWriter::WriteWithOptions(root, JSONWriter::OPTIONS_PRETTY_PRINT, + &output_js)) { + LOG(FATAL) << "Error getting JSON string"; + } + if (file.WriteAtCurrentPos(output_js.c_str(), + static_cast<int>(output_js.size())) < 0) { + // If the file could be opened, but writing has failed, it's likely that + // data was partially written. Producing incomplete profiling data would + // lead to a poorly performing orderfile, but might not be otherwised + // noticed. So we crash instead. + LOG(FATAL) << "Error writing profile data"; + } + return true; +} + +// Stops recording, and outputs the data to |path|. +NO_INSTRUMENT_FUNCTION void StopAndDumpToFile(int pid, + uint64_t start_ns_since_epoch, + const std::string& tag) { + std::string tag_str; + if (!tag.empty()) + tag_str = base::StringPrintf("%s-", tag.c_str()); + auto path = base::StringPrintf( + "/data/local/tmp/chrome/orderfile/profile-hitmap-%s%d-%" PRIu64 ".txt", + tag_str.c_str(), pid, start_ns_since_epoch); + + if (!DumpToFile(base::FilePath(path))) { + LOG(ERROR) << "Problem with dump (" << tag << ")"; + } +} + +} // namespace + +// It is safe to call any function after |Disable()| has been called. No risk of +// infinite recursion. +NO_INSTRUMENT_FUNCTION bool Disable() { + bool disabled = g_disabled.exchange(true, std::memory_order_relaxed); + std::atomic_thread_fence(std::memory_order_seq_cst); + return !disabled; +} + +NO_INSTRUMENT_FUNCTION void StartDelayedDump() { +#if BUILDFLAG(DEVTOOLS_INSTRUMENTATION_DUMPING) + static auto* g_orderfile_memory_dump_hook = new OrderfileMemoryDumpHook(); + base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( + g_orderfile_memory_dump_hook, "Orderfile", nullptr); +// Return, letting devtools tracing handle any dumping. +#else + // Using std::thread and not using base::TimeTicks() in order to to not call + // too many base:: symbols that would pollute the reached symbol dumps. + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC, &ts)) + PLOG(FATAL) << "clock_gettime."; + uint64_t start_ns_since_epoch = + static_cast<uint64_t>(ts.tv_sec) * 1000 * 1000 * 1000 + ts.tv_nsec; + int pid = getpid(); + std::thread([pid, start_ns_since_epoch]() { + sleep(kDelayInSeconds); + if (Disable()) + StopAndDumpToFile(pid, start_ns_since_epoch, ""); + }).detach(); +#endif // BUILDFLAG(DEVTOOLS_INSTRUMENTATION_DUMPING) +} + +NO_INSTRUMENT_FUNCTION void Dump(const std::string& tag) { + // As profiling has been disabled, none of the uses of ::base symbols below + // will enter the symbol dump. + StopAndDumpToFile( + getpid(), (base::Time::Now() - base::Time::UnixEpoch()).InNanoseconds(), + tag); +} + +NO_INSTRUMENT_FUNCTION void ResetForTesting() { + Disable(); + memset(reinterpret_cast<uint32_t*>(callee_map), 0, + sizeof(uint32_t) * kMaxElements); + memset(reinterpret_cast<uint32_t*>(g_caller_offset), 0, + sizeof(uint32_t) * kMaxReachedSymbols * kTotalBuckets); + memset(reinterpret_cast<uint32_t*>(g_caller_count), 0, + sizeof(uint32_t) * kMaxReachedSymbols * kTotalBuckets); + g_callers_index = 0; + g_disabled = false; +} + +NO_INSTRUMENT_FUNCTION void RecordAddressForTesting(size_t callee_address, + size_t caller_address) { + return RecordAddress<true>(callee_address, caller_address); +} + +// Returns a flattened vector where each callee is allocated 9 buckets. +// First bucket -> callee offset +// 8 buckets -> [caller offset, count, ...] +NO_INSTRUMENT_FUNCTION std::vector<size_t> GetOrderedOffsetsForTesting() { + std::vector<size_t> result; + for (size_t i = 0; i < kMaxElements; i++) { + auto caller_index = + callee_map[i].load(std::memory_order_relaxed) * kTotalBuckets; + if (!caller_index) + continue; + + result.push_back(i * 4); + for (size_t j = 0; j < kTotalBuckets; j++) { + uint32_t count = + g_caller_count[caller_index + j].load(std::memory_order_relaxed); + + uint32_t caller_offset = + g_caller_offset[caller_index + j].load(std::memory_order_relaxed); + result.push_back(caller_offset); + result.push_back(count); + } + } + return result; +} + +} // namespace orderfile +} // namespace android +} // namespace base + +extern "C" { + +NO_INSTRUMENT_FUNCTION void __cyg_profile_func_enter_bare() { + base::android::orderfile::RecordAddress<false>( + reinterpret_cast<size_t>(__builtin_return_address(0)), + reinterpret_cast<size_t>(__builtin_return_address(1))); +} + +} // extern "C"
diff --git a/base/android/orderfile/orderfile_call_graph_instrumentation_perftest.cc b/base/android/orderfile/orderfile_call_graph_instrumentation_perftest.cc new file mode 100644 index 0000000..5d7f274 --- /dev/null +++ b/base/android/orderfile/orderfile_call_graph_instrumentation_perftest.cc
@@ -0,0 +1,155 @@ +// 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 "base/android/orderfile/orderfile_instrumentation.h" + +#include <thread> + +#include "base/android/library_loader/anchor_functions.h" +#include "base/strings/stringprintf.h" +#include "base/time/time.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/perf/perf_test.h" + +namespace base { +namespace android { +namespace orderfile { + +namespace { +const size_t kStep = sizeof(int); + +void CallRecordAddress(int iterations, size_t addr_count) { + for (int i = 0; i < iterations; i++) { + for (size_t caller_addr = kStartOfTextForTesting + kStep; + caller_addr < addr_count; caller_addr += kStep) { + for (size_t callee_addr = caller_addr + kStep; callee_addr < addr_count; + callee_addr += kStep) { + RecordAddressForTesting(callee_addr, caller_addr); + } + } + } +} + +void RunBenchmark(size_t iterations, size_t addresses_count, int threads) { + ResetForTesting(); + auto iterate = [iterations, addresses_count]() { + CallRecordAddress(iterations, addresses_count); + }; + if (threads != 1) { + for (int i = 0; i < threads - 1; ++i) + std::thread(iterate).detach(); + } + auto tick = base::TimeTicks::Now(); + iterate(); + auto tock = base::TimeTicks::Now(); + double nanos = static_cast<double>((tock - tick).InNanoseconds()); + size_t addresses = (addresses_count - kStartOfTextForTesting - 1) / kStep; + double calls_count = (addresses * (addresses - 1)) / 2; + auto ns_per_call = nanos / (iterations * calls_count); + auto modifier = + base::StringPrintf("_%zu_%zu_%d", iterations, addresses_count, threads); + perf_test::PrintResult("RecordAddressCostPerCall", modifier, "", ns_per_call, + "ns", true); +} + +void CheckValid(size_t iterations, size_t addr_count) { + // |reached| is expected to be ordered by callee offset + auto reached = GetOrderedOffsetsForTesting(); + size_t buckets_per_callee = 9; // kTotalBuckets * 2 + 1. + size_t callers_per_callee = 3; + size_t addresses = (addr_count - kStartOfTextForTesting - 1) / kStep; + EXPECT_EQ((addresses - 1) * buckets_per_callee, reached.size()); + size_t expected_callee = kStartOfTextForTesting + 2 * kStep; + + for (size_t i = 0; i < reached.size(); i += buckets_per_callee) { + EXPECT_EQ(reached[i] / 4, (expected_callee - kStartOfTextForTesting) / 4); + size_t callee_index = i / buckets_per_callee; + for (size_t j = 0; j < callers_per_callee; j++) { + EXPECT_EQ(reached[i + j * 2 + 1], + j > callee_index ? 0UL : (j + 1) * kStep); + EXPECT_EQ(reached[i + j * 2 + 2], j > callee_index ? 0UL : iterations); + } + size_t misses = callee_index > 2 ? (callee_index - 2) * iterations : 0UL; + EXPECT_EQ(reached[i + 7], 0UL); + EXPECT_EQ(reached[i + 8], misses); + expected_callee += kStep; + } +} + +} // namespace + +class OrderfileInstrumentationTest : public ::testing::Test { + // Any tests need to run ResetForTesting() when they start. Because this + // perftest is built with instrumentation enabled, all code including + // ::testing::Test is instrumented. If ResetForTesting() is called earlier, + // for example in setUp(), any test harness code between setUp() and the + // actual test will change the instrumentation offset record in unpredictable + // ways and make these tests unreliable. +}; + +TEST_F(OrderfileInstrumentationTest, SequentialTest_10_5000) { + size_t iterations = 10; + size_t addr_count = 5000; + ResetForTesting(); + CallRecordAddress(iterations, addr_count); + Disable(); + CheckValid(iterations, addr_count); +} + +TEST_F(OrderfileInstrumentationTest, SequentialTest_10_10000) { + size_t iterations = 10; + size_t addr_count = 10000; + ResetForTesting(); + CallRecordAddress(iterations, addr_count); + Disable(); + CheckValid(iterations, addr_count); +} + +TEST_F(OrderfileInstrumentationTest, OutOfBoundsCaller) { + ResetForTesting(); + RecordAddressForTesting(1234, kStartOfTextForTesting); + RecordAddressForTesting(1234, kEndOfTextForTesting + 1); + Disable(); + auto reached = GetOrderedOffsetsForTesting(); + EXPECT_EQ(reached.size(), 9UL); + EXPECT_EQ(reached[0] / 4, (1234 - kStartOfTextForTesting) / 4); + for (size_t i = 1; i < 8; i++) { + EXPECT_EQ(reached[i], 0UL); + } + EXPECT_EQ(reached[8], 2UL); +} + +TEST(OrderfileInstrumentationPerfTest, RecordAddress_10_2000) { + RunBenchmark(10, 2000, 1); +} + +TEST(OrderfileInstrumentationPerfTest, RecordAddress_100_2000) { + RunBenchmark(100, 2000, 1); +} + +TEST(OrderfileInstrumentationPerfTest, RecordAddress_1000_2000_2) { + RunBenchmark(100, 2000, 2); +} + +TEST(OrderfileInstrumentationPerfTest, RecordAddress_1000_2000_3) { + RunBenchmark(100, 2000, 3); +} + +TEST(OrderfileInstrumentationPerfTest, RecordAddress_1000_2000_4) { + RunBenchmark(100, 2000, 4); +} + +TEST(OrderfileInstrumentationPerfTest, RecordAddress_1000_2000_6) { + RunBenchmark(100, 2000, 6); +} + +} // namespace orderfile +} // namespace android +} // namespace base + +// Custom runner implementation since base's one requires JNI on Android. +int main(int argc, char** argv) { + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +}
diff --git a/base/android/orderfile/orderfile_instrumentation.h b/base/android/orderfile/orderfile_instrumentation.h index 8db1943..e8f65c2 100644 --- a/base/android/orderfile/orderfile_instrumentation.h +++ b/base/android/orderfile/orderfile_instrumentation.h
@@ -25,9 +25,6 @@ // Stop recording. Returns false if recording was already disabled. bool Disable(); -// CHECK()s that the offsets are correctly set up. -void SanityChecks(); - // Switches to the next recording phase. If called from the last phase, dumps // the data to disk, and returns |true|. |pid| is the current process pid, and // |start_ns_since_epoch| the process start timestamp. @@ -44,6 +41,10 @@ // Record an |address|, if recording is enabled. Only for testing. void RecordAddressForTesting(size_t address); +// Record |callee_address, caller_address|, if recording is enabled. +// Only for testing. +void RecordAddressForTesting(size_t callee_address, size_t caller_address); + // Resets the state. Only for testing. void ResetForTesting();
diff --git a/base/metrics/persistent_histogram_allocator.cc b/base/metrics/persistent_histogram_allocator.cc index b44baec..6bd8559d 100644 --- a/base/metrics/persistent_histogram_allocator.cc +++ b/base/metrics/persistent_histogram_allocator.cc
@@ -719,13 +719,12 @@ // Old "active" becomes "base". if (!base::ReplaceFile(active_path, base_path, nullptr)) base::DeleteFile(base_path, /*recursive=*/false); - DCHECK(!base::PathExists(active_path)); + if (base::PathExists(active_path)) + return false; // Move any "spare" into "active". Okay to continue if file doesn't exist. - if (!spare_path.empty()) { + if (!spare_path.empty()) base::ReplaceFile(spare_path, active_path, nullptr); - DCHECK(!base::PathExists(spare_path)); - } return base::GlobalHistogramAllocator::CreateWithFile(active_path, size, id, name);
diff --git a/build/config/android/abi.gni b/build/config/android/abi.gni index 79e98b8a..5f02b07 100644 --- a/build/config/android/abi.gni +++ b/build/config/android/abi.gni
@@ -23,6 +23,10 @@ # See base::android::orderfile::StartDelayedDump for more information. devtools_instrumentation_dumping = false + # Only effective if use_order_profiling = true. When this is true the call + # graph based instrumentation is used. + use_call_graph = false + # Builds secondary abi for APKs, supports build 32-bit arch as secondary # abi in 64-bit Monochrome and WebView. build_apk_secondary_abi = true @@ -30,6 +34,8 @@ assert(!devtools_instrumentation_dumping || use_order_profiling, "devtools_instrumentation_dumping requires use_order_profiling") +assert(!use_call_graph || use_order_profiling, + "use_call_graph requires use_order_profiling") if (current_cpu == "x86") { android_app_abi = "x86"
diff --git a/build/config/compiler/compiler.gni b/build/config/compiler/compiler.gni index 077482d..c351d6ba 100644 --- a/build/config/compiler/compiler.gni +++ b/build/config/compiler/compiler.gni
@@ -128,7 +128,10 @@ # but overall shrinks binaries considerably by avoiding huge unwind # tables. (current_cpu == "x86" && !exclude_unwind_tables && optimize_for_size) || - using_sanitizer + using_sanitizer || + # For caller-callee instrumentation version which needs frame pointers to + # get the caller address. + use_call_graph } else { # Explicitly ask for frame pointers, otherwise: # * Stacks may be missing for sanitizer and profiling builds.
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1 index 67b540d..e77f2b5 100644 --- a/build/fuchsia/linux.sdk.sha1 +++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@ -8914296474736728352 \ No newline at end of file +8914210209779993824 \ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1 index 255f976..ac3b4b33e 100644 --- a/build/fuchsia/mac.sdk.sha1 +++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@ -8914296671689431792 \ No newline at end of file +8914215077935238080 \ No newline at end of file
diff --git a/build/vs_toolchain.py b/build/vs_toolchain.py index 79b39e6..15e385e6 100755 --- a/build/vs_toolchain.py +++ b/build/vs_toolchain.py
@@ -5,7 +5,6 @@ from __future__ import print_function -import collections import glob import json import os @@ -23,11 +22,9 @@ script_dir = os.path.dirname(os.path.realpath(__file__)) json_data_file = os.path.join(script_dir, 'win_toolchain.json') -# VS versions are listed in descending order of priority (highest first). -TOOLCHAIN_VERSIONS = collections.OrderedDict([ - ('2017', '15.0'), - ('2019', '16.0'), -]) + +# Use MSVS2017 as the default toolchain. +CURRENT_DEFAULT_TOOLCHAIN_VERSION = '2017' def SetEnvironmentAndGetRuntimeDllDirs(): @@ -132,40 +129,9 @@ def GetVisualStudioVersion(): - """Return best available version of Visual Studio. + """Return GYP_MSVS_VERSION of Visual Studio. """ - - supported_versions = TOOLCHAIN_VERSIONS.keys() - supported_versions_str = ', '.join('{} ({})'.format(v,k) - for k,v in TOOLCHAIN_VERSIONS.items()) - available_versions = [] - for version in supported_versions: - for path in ( - os.environ.get('vs%s_install' % version), - os.path.expandvars('%ProgramFiles(x86)%' + - '/Microsoft Visual Studio/%s' % version)): - if path and os.path.exists(path): - available_versions.append(version) - break - - if not available_versions: - if bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', '1'))): - return TOOLCHAIN_VERSIONS.keys()[0] - raise Exception(('No supported Visual Studio can be found.' - ' Supported versions are: %s.') % supported_versions_str) - - env_version = os.environ.get('GYP_MSVS_VERSION') - if env_version: - if env_version not in supported_versions: - raise Exception(('Visual Studio version %s (from GYP_MSVS_VERSION)' - ' is not supported. Supported versions are: %s.') - % (env_version, supported_versions_str)) - if env_version not in available_versions: - raise Exception(('Visual Studio version %s (from GYP_MSVS_VERSION)' - ' is not available.') % env_version) - return env_version - - return available_versions[0] + return os.environ.get('GYP_MSVS_VERSION', CURRENT_DEFAULT_TOOLCHAIN_VERSION) def DetectVisualStudioPath(): @@ -175,6 +141,14 @@ # Note that this code is used from # build/toolchain/win/setup_toolchain.py as well. version_as_year = GetVisualStudioVersion() + year_to_version = { + '2017': '15.0', + '2019': '16.0', + } + if version_as_year not in year_to_version: + raise Exception(('Visual Studio version %s (from GYP_MSVS_VERSION)' + ' not supported. Supported versions are: %s') % ( + version_as_year, ', '.join(year_to_version.keys()))) # The VC++ >=2017 install location needs to be located using COM instead of # the registry. For details see: @@ -293,7 +267,7 @@ version number part changes frequently so the highest version number found is used. """ - + assert GetVisualStudioVersion() in ['2017', '2019'] SetEnvironmentAndGetRuntimeDllDirs() assert ('GYP_MSVS_OVERRIDE_PATH' in os.environ) vc_component_msvc_root = os.path.join(os.environ['GYP_MSVS_OVERRIDE_PATH'],
diff --git a/chrome/VERSION b/chrome/VERSION index 8bfed3d..50c5dbd 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=76 MINOR=0 -BUILD=3786 +BUILD=3787 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index 885bac0a..433b25f 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -2372,7 +2372,6 @@ sources = [ # Files under a feature's public/ dir are included in chrome_java's source # files, so include these files in chrome_jni_headers. - "features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantClient.java", "java/src/org/chromium/chrome/browser/AfterStartupTaskUtils.java", "java/src/org/chromium/chrome/browser/AppHooks.java", "java/src/org/chromium/chrome/browser/ApplicationLifetime.java",
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni index dedea7b..a7203439 100644 --- a/chrome/android/chrome_java_sources.gni +++ b/chrome/android/chrome_java_sources.gni
@@ -206,7 +206,6 @@ "java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchQuickActionControl.java", "java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchTermControl.java", "java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabBarControl.java", - "java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabCaptionControl.java", "java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabPanel.java", "java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabTitleControl.java", "java/src/org/chromium/chrome/browser/compositor/layouts/EmptyOverviewModeObserver.java",
diff --git a/chrome/android/features/autofill_assistant/BUILD.gn b/chrome/android/features/autofill_assistant/BUILD.gn index 195c403..e07149b 100644 --- a/chrome/android/features/autofill_assistant/BUILD.gn +++ b/chrome/android/features/autofill_assistant/BUILD.gn
@@ -74,7 +74,8 @@ "java/src/org/chromium/chrome/browser/autofill_assistant/AssistantPeekHeightCoordinator.java", "java/src/org/chromium/chrome/browser/autofill_assistant/AssistantSnackbar.java", "java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java", - "java/src/org/chromium/chrome/browser/autofill_assistant/DynamicModuleCheckImpl.java", + "java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantClient.java", + "java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryFactoryImpl.java", "java/src/org/chromium/chrome/browser/autofill_assistant/EditDistance.java", "java/src/org/chromium/chrome/browser/autofill_assistant/SizeListenableLinearLayout.java", "java/src/org/chromium/chrome/browser/autofill_assistant/carousel/AssistantActionsCarouselCoordinator.java", @@ -121,6 +122,7 @@ generate_jni("jni_headers") { sources = [ "java/src/org/chromium/chrome/browser/autofill_assistant/AssistantModel.java", + "java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantClient.java", "java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java", "java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetails.java", "java/src/org/chromium/chrome/browser/autofill_assistant/details/AssistantDetailsModel.java",
diff --git a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantClient.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantClient.java similarity index 97% rename from chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantClient.java rename to chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantClient.java index 9cff9c5..c3c20c3d 100644 --- a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantClient.java +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantClient.java
@@ -26,7 +26,7 @@ * This mainly a bridge to autofill_assistant::ClientAndroid. */ @JNINamespace("autofill_assistant") -class AutofillAssistantClient { +class AutofillAssistantClient implements AutofillAssistantModuleEntry { /** OAuth2 scope that RPCs require. */ private static final String AUTH_TOKEN_TYPE = "oauth2:https://www.googleapis.com/auth/userinfo.profile"; @@ -66,9 +66,7 @@ mNativeClientAndroid = nativeClientAndroid; } - /** - * Show the onboarding screen and run {@code onAccept} if user agreed to proceed. - */ + @Override public void showOnboarding(String experimentIds, Runnable onAccept) { checkNativeClientIsAliveOrThrow(); nativeShowOnboarding(mNativeClientAndroid, experimentIds, onAccept); @@ -80,9 +78,7 @@ } } - /** - * Launches Autofill Assistant on the current web contents, expecting autostart. - */ + @Override public void start(String initialUrl, Map<String, String> parameters, String experimentIds, Bundle intentExtras) { checkNativeClientIsAliveOrThrow();
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryFactoryImpl.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryFactoryImpl.java new file mode 100644 index 0000000..a36a25f --- /dev/null +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryFactoryImpl.java
@@ -0,0 +1,22 @@ +// 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.autofill_assistant; + +import org.chromium.base.annotations.UsedByReflection; +import org.chromium.content_public.browser.WebContents; + +/** + * Factory implementation to create AutofillAssistantClient as + * as AutofillAssistantModuleEntry to serve as interface between + * base module and assistant DFM. + */ +@UsedByReflection("AutofillAssistantModuleEntryProvider.java") +public class AutofillAssistantModuleEntryFactoryImpl + implements AutofillAssistantModuleEntryFactory { + @Override + public AutofillAssistantModuleEntry createEntry(WebContents webContents) { + return AutofillAssistantClient.fromWebContents(webContents); + } +} \ No newline at end of file
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/DynamicModuleCheckImpl.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/DynamicModuleCheckImpl.java deleted file mode 100644 index 38c33235..0000000 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/DynamicModuleCheckImpl.java +++ /dev/null
@@ -1,11 +0,0 @@ -// 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.autofill_assistant; - -import org.chromium.base.annotations.UsedByReflection; - -/** {@link DynamicModuleCheck} implementation if the autofill_assistant module is available. */ -@UsedByReflection("AutofillAssistantFacade.java") -public class DynamicModuleCheckImpl implements DynamicModuleCheck {}
diff --git a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java index d338b16..fe92dc1 100644 --- a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java +++ b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java
@@ -9,16 +9,10 @@ import android.os.Bundle; import android.support.annotation.Nullable; -import org.chromium.base.Callback; -import org.chromium.chrome.R; -import org.chromium.chrome.browser.ActivityTabProvider; import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.autofill_assistant.metrics.DropOutReason; import org.chromium.chrome.browser.metrics.UmaSessionStats; -import org.chromium.chrome.browser.modules.ModuleInstallUi; -import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.util.IntentUtils; -import org.chromium.components.module_installer.ModuleInstaller; import java.net.URLDecoder; import java.util.HashMap; @@ -92,24 +86,22 @@ // Have an "attempted starts" baseline for the drop out histogram. AutofillAssistantMetrics.recordDropOut(DropOutReason.AA_START); - checkAndLoadDynamicModuleIfNeeded(activity, (success) -> { - if (success) { - if (canStart(activity.getInitialIntent())) { - getTab(activity, tab -> startNow(activity, tab)); - return; - } - if (AutofillAssistantPreferencesUtil.getShowOnboarding()) { - getTab(activity, tab -> { - AutofillAssistantClient client = - AutofillAssistantClient.fromWebContents(tab.getWebContents()); - client.showOnboarding( - getExperimentIds(activity.getInitialIntent().getExtras()), - () -> startNow(activity, tab)); - }); - return; - } - } else { + AutofillAssistantModuleEntryProvider.getModuleEntry(activity, (moduleEntry) -> { + if (moduleEntry == null) { AutofillAssistantMetrics.recordDropOut(DropOutReason.DFM_CANCELLED); + return; + } + // Starting autofill assistant without onboarding. + if (canStart(activity.getInitialIntent())) { + startNow(activity, moduleEntry); + return; + } + // Starting autofill assistant with onboarding. + if (AutofillAssistantPreferencesUtil.getShowOnboarding()) { + moduleEntry.showOnboarding( + getExperimentIds(activity.getInitialIntent().getExtras()), + () -> startNow(activity, moduleEntry)); + return; } }); } @@ -140,86 +132,16 @@ return experiments.toString(); } - /** - * Checks if classes from DFM can be loaded, if not try loading it with default UI provided - * by DFM. - * @param callback is called with 'true' when DFM is already loaded or loading DFM was - * successful, it is called with 'false' if DFM cannot be loaded and aborted by user. - */ - private static void checkAndLoadDynamicModuleIfNeeded( - ChromeActivity activity, Callback<Boolean> callback) { - // Required to access resources in DFM using this activity as context. - ModuleInstaller.initActivity(activity); - if (AutofillAssistantModule.isInstalled()) { - callback.onResult(true); - return; - } - getTab(activity, tab -> { loadDynamicModuleWithUi(activity, tab, callback); }); - } - - private static void loadDynamicModuleWithUi( - ChromeActivity activity, Tab tab, Callback<Boolean> callback) { - ModuleInstallUi ui = new ModuleInstallUi(tab, R.string.autofill_assistant_module_title, - new ModuleInstallUi.FailureUiListener() { - @Override - public void onRetry() { - loadDynamicModuleWithUi(activity, tab, callback); - } - - @Override - public void onCancel() { - callback.onResult(false); - } - }); - // Shows toast informing user about install start. - ui.showInstallStartUi(); - ModuleInstaller.install("autofill_assistant", (success) -> { - if (success) { - // Clean install of chrome will have issues here without initializing - // after installation of DFM. - ModuleInstaller.initActivity(activity); - // Don't show success UI from DFM, transition to autobot UI directly. - callback.onResult(true); - return; - } - // Show inforbar to ask user if they want to retry or cancel. - ui.showInstallFailureUi(); - }); - } - - private static void startNow(ChromeActivity activity, Tab tab) { + private static void startNow(ChromeActivity activity, AutofillAssistantModuleEntry entry) { Bundle bundleExtras = activity.getInitialIntent().getExtras(); Map<String, String> parameters = extractParameters(bundleExtras); parameters.remove(PARAMETER_ENABLED); String initialUrl = activity.getInitialIntent().getDataString(); - AutofillAssistantClient client = - AutofillAssistantClient.fromWebContents(tab.getWebContents()); - - client.start(initialUrl, parameters, getExperimentIds(bundleExtras), + entry.start(initialUrl, parameters, getExperimentIds(bundleExtras), activity.getInitialIntent().getExtras()); } - private static void getTab(ChromeActivity activity, Callback<Tab> callback) { - if (activity.getActivityTab() != null - && activity.getActivityTab().getWebContents() != null) { - callback.onResult(activity.getActivityTab()); - return; - } - - // The tab is not yet available. We need to register as listener and wait for it. - activity.getActivityTabProvider().addObserverAndTrigger( - new ActivityTabProvider.HintlessActivityTabObserver() { - @Override - public void onActivityTabChanged(Tab tab) { - if (tab == null) return; - activity.getActivityTabProvider().removeObserver(this); - assert tab.getWebContents() != null; - callback.onResult(tab); - } - }); - } - /** Return the value if the given boolean parameter from the extras. */ private static boolean getBooleanParameter(@Nullable Bundle extras, String parameterName) { return extras != null
diff --git a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntry.java b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntry.java new file mode 100644 index 0000000..0aaf6df --- /dev/null +++ b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntry.java
@@ -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. + +package org.chromium.chrome.browser.autofill_assistant; + +import android.os.Bundle; + +import java.util.Map; + +/** + * Interface for base module to start the autofill assistant + * experience in dynamic feature module. + */ +interface AutofillAssistantModuleEntry { + /** + * Show the onboarding screen and run {@code onAccept} if user agreed to proceed. + */ + void showOnboarding(String experimentIds, Runnable onAccept); + + /** + * Launches Autofill Assistant on the current web contents, expecting autostart. + */ + void start(String initialUrl, Map<String, String> parameters, String experimentIds, + Bundle intentExtras); +} \ No newline at end of file
diff --git a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryFactory.java b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryFactory.java new file mode 100644 index 0000000..045c6b8 --- /dev/null +++ b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryFactory.java
@@ -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. + +package org.chromium.chrome.browser.autofill_assistant; + +import org.chromium.components.module_installer.ModuleInterface; +import org.chromium.content_public.browser.WebContents; + +/** + * Interface to create AutofillAssistantModuleEntry as inferface + * between base module and assistant DFM. + */ +@ModuleInterface(module = "autofill_assistant", + impl = "org.chromium.chrome.browser.autofill_assistant." + + "AutofillAssistantModuleEntryFactoryImpl") +interface AutofillAssistantModuleEntryFactory { + AutofillAssistantModuleEntry createEntry(WebContents webContents); +} \ No newline at end of file
diff --git a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryProvider.java b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryProvider.java new file mode 100644 index 0000000..5f2bc783 --- /dev/null +++ b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryProvider.java
@@ -0,0 +1,91 @@ +// 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.autofill_assistant; + +import org.chromium.base.Callback; +import org.chromium.chrome.R; +import org.chromium.chrome.browser.ActivityTabProvider; +import org.chromium.chrome.browser.ChromeActivity; +import org.chromium.chrome.browser.modules.ModuleInstallUi; +import org.chromium.chrome.browser.tab.Tab; +import org.chromium.components.module_installer.ModuleInstaller; + +/** + * Manages the loading of autofill assistant DFM, and provides implementation of + * AutofillAssistantModuleEntry. + */ +class AutofillAssistantModuleEntryProvider { + /** + * Returns AutofillAssistantModuleEntry by using it as argument to the + * passed in callback, or null if DFM loading fails. + */ + /* package */ static void getModuleEntry( + ChromeActivity activity, Callback<AutofillAssistantModuleEntry> callback) { + getTab(activity, tab -> { + // Required to access resources in DFM using this activity as context. + ModuleInstaller.initActivity(activity); + if (AutofillAssistantModule.isInstalled()) { + callback.onResult(createEntry(tab)); + return; + } + loadDynamicModuleWithUi(activity, tab, callback); + }); + } + + private static AutofillAssistantModuleEntry createEntry(Tab tab) { + AutofillAssistantModuleEntryFactory factory = AutofillAssistantModule.getImpl(); + return factory.createEntry(tab.getWebContents()); + } + + private static void loadDynamicModuleWithUi( + ChromeActivity activity, Tab tab, Callback<AutofillAssistantModuleEntry> callback) { + ModuleInstallUi ui = new ModuleInstallUi(tab, R.string.autofill_assistant_module_title, + new ModuleInstallUi.FailureUiListener() { + @Override + public void onRetry() { + loadDynamicModuleWithUi(activity, tab, callback); + } + + @Override + public void onCancel() { + callback.onResult(null); + } + }); + // Shows toast informing user about install start. + ui.showInstallStartUi(); + ModuleInstaller.install("autofill_assistant", (success) -> { + if (success) { + // Clean install of chrome will have issues here without initializing + // after installation of DFM. + ModuleInstaller.initActivity(activity); + // Don't show success UI from DFM, transition to autobot UI directly. + callback.onResult(createEntry(tab)); + return; + } + // Show inforbar to ask user if they want to retry or cancel. + ui.showInstallFailureUi(); + }); + } + + private static void getTab(ChromeActivity activity, Callback<Tab> callback) { + if (activity.getActivityTab() != null + && activity.getActivityTab().getWebContents() != null) { + callback.onResult(activity.getActivityTab()); + return; + } + + // The tab is not yet available. We need to register as listener and wait for it. + activity.getActivityTabProvider().addObserverAndTrigger( + new ActivityTabProvider.HintlessActivityTabObserver() { + @Override + public void onActivityTabChanged(Tab tab) { + if (tab == null) return; + activity.getActivityTabProvider().removeObserver(this); + assert tab.getWebContents() != null; + callback.onResult(tab); + } + }); + } +}
diff --git a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/DynamicModuleCheck.java b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/DynamicModuleCheck.java deleted file mode 100644 index 1de9713..0000000 --- a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/DynamicModuleCheck.java +++ /dev/null
@@ -1,16 +0,0 @@ -// 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.autofill_assistant; - -import org.chromium.components.module_installer.ModuleInterface; - -/** - * An interface whose implementation is in dynamic module. The - * implementation is loaded via reflection from base module to check - * if dynamic module is installed. - */ -@ModuleInterface(module = "autofill_assistant", - impl = "org.chromium.chrome.browser.autofill_assistant.DynamicModuleCheckImpl") -public interface DynamicModuleCheck {}
diff --git a/chrome/android/features/autofill_assistant/public/java_sources.gni b/chrome/android/features/autofill_assistant/public/java_sources.gni index 55cabdc..1d79e4d 100644 --- a/chrome/android/features/autofill_assistant/public/java_sources.gni +++ b/chrome/android/features/autofill_assistant/public/java_sources.gni
@@ -3,9 +3,10 @@ # found in the LICENSE file. public_autofill_assistant_java_sources = [ - "//chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantClient.java", "//chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java", "//chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantMetrics.java", + "//chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntry.java", + "//chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryFactory.java", + "//chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryProvider.java", "//chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPreferencesUtil.java", - "//chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/DynamicModuleCheck.java", ]
diff --git a/chrome/android/java/res/drawable-hdpi/open_in_new_tab.png b/chrome/android/java/res/drawable-hdpi/open_in_new_tab.png new file mode 100644 index 0000000..2ee464b --- /dev/null +++ b/chrome/android/java/res/drawable-hdpi/open_in_new_tab.png Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/open_in_new_tab.png b/chrome/android/java/res/drawable-mdpi/open_in_new_tab.png new file mode 100644 index 0000000..b75f7b3b --- /dev/null +++ b/chrome/android/java/res/drawable-mdpi/open_in_new_tab.png Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/open_in_new_tab.png b/chrome/android/java/res/drawable-xhdpi/open_in_new_tab.png new file mode 100644 index 0000000..f098a23 --- /dev/null +++ b/chrome/android/java/res/drawable-xhdpi/open_in_new_tab.png Binary files differ
diff --git a/chrome/android/java/res/drawable-xxhdpi/open_in_new_tab.png b/chrome/android/java/res/drawable-xxhdpi/open_in_new_tab.png new file mode 100644 index 0000000..479830b1 --- /dev/null +++ b/chrome/android/java/res/drawable-xxhdpi/open_in_new_tab.png Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/open_in_new_tab.png b/chrome/android/java/res/drawable-xxxhdpi/open_in_new_tab.png new file mode 100644 index 0000000..96ed8c6 --- /dev/null +++ b/chrome/android/java/res/drawable-xxxhdpi/open_in_new_tab.png Binary files differ
diff --git a/chrome/android/java/res/drawable/drag_handlebar.xml b/chrome/android/java/res/drawable/drag_handlebar.xml new file mode 100644 index 0000000..bbe86c3 --- /dev/null +++ b/chrome/android/java/res/drawable/drag_handlebar.xml
@@ -0,0 +1,13 @@ +<?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. --> + +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <size android:height="4dp" + android:width="40dp"/> + <corners + android:radius="2dp" /> + <solid android:color="@color/drag_handlebar_color" /> +</shape>
diff --git a/chrome/android/java/res/layout/ephemeral_tab_caption_view.xml b/chrome/android/java/res/layout/ephemeral_tab_caption_view.xml deleted file mode 100644 index 6a4e61b..0000000 --- a/chrome/android/java/res/layout/ephemeral_tab_caption_view.xml +++ /dev/null
@@ -1,15 +0,0 @@ -<?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. --> - -<!-- Ephemeral Tab caption view where we display 'Open in new tab'. Hidden in - peeked state, and gets visible only when being expanded to maximized state. --> -<FrameLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/ephemeral_tab_caption_view" - style="@style/ContextualSearchTextViewLayout" > - <TextView - android:id="@+id/ephemeral_tab_caption" - style="@style/ContextualSearchCaptionTextView" /> -</FrameLayout>
diff --git a/chrome/android/java/res/values/colors.xml b/chrome/android/java/res/values/colors.xml index ae8779a..96ab6cb 100644 --- a/chrome/android/java/res/values/colors.xml +++ b/chrome/android/java/res/values/colors.xml
@@ -193,5 +193,6 @@ <color name="search_box_hint">@color/default_text_color_secondary</color> <color name="thumbnail_placeholder_on_primary_bg">@color/modern_secondary_color</color> <color name="tab_layout_selected_tab_color">@color/default_text_color_blue</color> + <color name="drag_handlebar_color">#D9DBDF</color> </resources>
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml index 4d0f3a3d..ac83a6e 100644 --- a/chrome/android/java/res/values/dimens.xml +++ b/chrome/android/java/res/values/dimens.xml
@@ -120,7 +120,7 @@ <dimen name="contextual_search_text_layer_min_height">38dp</dimen> <dimen name="contextual_search_term_caption_spacing">1.5dp</dimen> <!-- This is the offset of the divider from the end of the bar. --> - <dimen name="contextual_search_end_button_width">48dp</dimen> + <dimen name="contextual_search_end_button_width">84dp</dimen> <dimen name="contextual_search_divider_line_width">1dp</dimen> <dimen name="contextual_search_divider_line_height">24dp</dimen> <dimen name="contextual_search_bubble_y_inset">-3dp</dimen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanel.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanel.java index cf0dd32..d149f0d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanel.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanel.java
@@ -650,6 +650,16 @@ } /** + * @param x The x coordinate in dp. + * @return Whether the given |x| coordinate is inside the close button. + */ + protected boolean isCoordinateInsideOpenTabButton(float x) { + float width = getOpenTabIconDimension() + CLOSE_BUTTON_TOUCH_SLOP_DP; + return getOpenTabIconX() - CLOSE_BUTTON_TOUCH_SLOP_DP <= x + && x <= getOpenTabIconX() + width; + } + + /** * Handles the click gesture. * * @param x The x coordinate of the gesture.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelBase.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelBase.java index 6ab4b68..1661b45 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelBase.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelBase.java
@@ -6,6 +6,7 @@ import android.content.Context; import android.content.res.Resources; +import android.graphics.drawable.Drawable; import android.support.annotation.ColorInt; import android.support.annotation.Nullable; import android.view.ViewGroup; @@ -27,6 +28,9 @@ /** The side padding of Bar icons in dps. */ private static final float BAR_ICON_SIDE_PADDING_DP = 12.f; + /** The top padding of Bar icons in dps. */ + private static final float BAR_ICON_TOP_PADDING_DP = 10.f; + /** The height of the Bar's border in dps. */ private static final float BAR_BORDER_HEIGHT_DP = 1.f; @@ -110,6 +114,9 @@ /** The tint used for icons (e.g. arrow icon, close icon). */ private final @ColorInt int mIconColor; + /** The tint used for drag handlebar. */ + private final @ColorInt int mDragHandlebarColor; + /** * The Y coordinate to apply to the Base Page in order to keep the selection * in view when the Overlay Panel is in its EXPANDED state. @@ -140,6 +147,7 @@ mBarHeightExpanded = Math.round((mBarHeightPeeking + mBarHeightMaximized) / 2.f); mBarMarginSide = BAR_ICON_SIDE_PADDING_DP; + mBarMarginTop = BAR_ICON_TOP_PADDING_DP; mProgressBarHeight = PROGRESS_BAR_HEIGHT_DP; mBarBorderHeight = BAR_BORDER_HEIGHT_DP; @@ -149,6 +157,8 @@ mBarBackgroundColor = ApiCompatibilityUtils.getColor( resources, R.color.overlay_panel_bar_background_color); mIconColor = ApiCompatibilityUtils.getColor(resources, R.color.default_icon_color); + mDragHandlebarColor = + ApiCompatibilityUtils.getColor(resources, R.color.drag_handlebar_color); } // ============================================================================================ @@ -396,6 +406,7 @@ // Panel Bar states // -------------------------------------------------------------------------------------------- private float mBarMarginSide; + private float mBarMarginTop; private float mBarHeight; private boolean mIsBarBorderVisible; private float mBarBorderHeight; @@ -408,6 +419,8 @@ private float mCloseIconOpacity; private float mCloseIconWidth; + private float mOpenTabIconWidth; + /** * @return The side margin of the Bar. */ @@ -416,6 +429,13 @@ } /** + * @return The top margin of the Bar. + */ + public float getBarMarginTop() { + return mBarMarginTop; + } + + /** * @return The height of the Bar in dp. */ public float getBarHeight() { @@ -465,6 +485,13 @@ } /** + * @return The tint used for drag handlebar. + */ + public int getDragHandlebarColor() { + return mDragHandlebarColor; + } + + /** * @return The opacity of the arrow icon. */ public float getArrowIconOpacity() { @@ -507,6 +534,30 @@ } } + /** + * @return The width/height of the open tab icon. + */ + public float getOpenTabIconDimension() { + if (mOpenTabIconWidth == 0) { + Drawable icon = ApiCompatibilityUtils.getDrawable( + mContext.getResources(), R.drawable.open_in_new_tab); + mOpenTabIconWidth = icon.getIntrinsicWidth() * mPxToDp; + } + return mOpenTabIconWidth; + } + + /** + * @return The left X coordinate of the open new tab icon. + */ + public float getOpenTabIconX() { + float offset = getCloseIconDimension() + getBarMarginSide(); + if (LocalizationUtils.isLayoutRtl()) { + return getCloseIconX() + offset; + } else { + return getCloseIconX() - offset; + } + } + // -------------------------------------------------------------------------------------------- // Base Page states // --------------------------------------------------------------------------------------------
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchBarControl.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchBarControl.java index 957331e..d95a01d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchBarControl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchBarControl.java
@@ -147,8 +147,7 @@ mImageControl = new ContextualSearchImageControl(panel); mContextControl = new ContextualSearchContextControl(panel, context, container, loader); mSearchTermControl = new ContextualSearchTermControl(panel, context, container, loader); - mCaptionControl = new ContextualSearchCaptionControl(panel, context, container, loader, - mCanPromoteToNewTab); + mCaptionControl = new ContextualSearchCaptionControl(panel, context, container, loader); mQuickActionControl = new ContextualSearchQuickActionControl(context, loader); mCardIconControl = new ContextualSearchCardIconControl(context, loader);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchCaptionControl.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchCaptionControl.java index 4541c6f04..b63cec99 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchCaptionControl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchCaptionControl.java
@@ -11,7 +11,6 @@ import android.view.animation.Interpolator; import android.widget.TextView; -import org.chromium.base.VisibleForTesting; import org.chromium.chrome.R; import org.chromium.chrome.browser.compositor.animation.CompositorAnimator; import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel; @@ -26,16 +25,9 @@ public class ContextualSearchCaptionControl extends OverlayPanelTextViewInflater { private static final float ANIMATION_PERCENTAGE_ZERO = 0.f; private static final float ANIMATION_PERCENTAGE_COMPLETE = 1.f; - private static final float EXPANDED_CAPTION_THRESHOLD = 0.5f; private static final Interpolator ANIMATION_INTERPOLATOR = new FastOutSlowInInterpolator(); /** - * The resource id for the string to display when the Bar is expanded. - */ - @VisibleForTesting - public static final int EXPANED_CAPTION_ID = R.string.contextmenu_open_in_new_tab; - - /** * The caption View. */ private TextView mCaption; @@ -51,16 +43,6 @@ private boolean mHasPeekingCaption; /** - * Whether the caption for the expanded Bar is showing. - */ - private boolean mShowingExpandedCaption; - - /** - * Whether the expanded caption should be shown. - */ - private final boolean mShouldShowExpandedCaption; - - /** * The caption visibility. */ private boolean mIsVisible; @@ -86,14 +68,11 @@ * @param context The Android Context used to inflate the View. * @param container The container View used to inflate the View. * @param resourceLoader The resource loader that will handle the snapshot capturing. - * @param shouldShowExpandedCaption Whether the "Open in new tab" caption should be shown - * when the panel is expanded. */ public ContextualSearchCaptionControl(OverlayPanel panel, Context context, ViewGroup container, - DynamicResourceLoader resourceLoader, boolean shouldShowExpandedCaption) { + DynamicResourceLoader resourceLoader) { super(panel, R.layout.contextual_search_caption_view, R.id.contextual_search_caption_view, context, container, resourceLoader); - mShouldShowExpandedCaption = shouldShowExpandedCaption; } /** @@ -108,8 +87,6 @@ mPeekingCaptionText = sanitizeText(caption); mHasPeekingCaption = true; - if (mShowingExpandedCaption) return; - mDidCapture = false; inflate(); @@ -125,47 +102,9 @@ * @param percentage The percentage to the more opened state. */ public void onUpdateFromPeekToExpand(float percentage) { - if (!mShouldShowExpandedCaption) { - if (mHasPeekingCaption) { - if (mTransitionAnimator != null) mTransitionAnimator.cancel(); - mAnimationPercentage = 1.f - percentage; - } - return; - } - if (mHasPeekingCaption) { - if (percentage < EXPANDED_CAPTION_THRESHOLD && mShowingExpandedCaption) { - // Start showing the peeking caption again. - mShowingExpandedCaption = false; - mCaption.setText(mPeekingCaptionText); - invalidate(); - } else if (percentage >= EXPANDED_CAPTION_THRESHOLD && !mShowingExpandedCaption) { - // Start showing the expanded caption. - mShowingExpandedCaption = true; - mCaption.setText(EXPANED_CAPTION_ID); - invalidate(); - } - - // If the peeking caption gets set while the bar is expanding, mAnimationPercentage - // will stop getting updated. Set mAnimationPercentage to its complete value. - mAnimationPercentage = ANIMATION_PERCENTAGE_COMPLETE; - } else { - // If the expanded caption is not showing, set the caption text to the expanded - // caption. - if (!mShowingExpandedCaption && percentage > 0.f) { - mShowingExpandedCaption = true; - // Inflate the caption view if it has not already been inflated - if (mCaption == null) { - inflate(); - } - - mCaption.setText(EXPANED_CAPTION_ID); - invalidate(); - show(); - } - - mAnimationPercentage = percentage; - if (mAnimationPercentage == ANIMATION_PERCENTAGE_ZERO) mShowingExpandedCaption = false; + if (mTransitionAnimator != null) mTransitionAnimator.cancel(); + mAnimationPercentage = 1.f - percentage; } } @@ -173,10 +112,8 @@ * Hides the caption. */ public void hide() { - if (!mShowingExpandedCaption) { - mIsVisible = false; - mAnimationPercentage = ANIMATION_PERCENTAGE_ZERO; - } + mIsVisible = false; + mAnimationPercentage = ANIMATION_PERCENTAGE_ZERO; mHasPeekingCaption = false; } @@ -245,7 +182,7 @@ mDidCapture = true; - if (!mShowingExpandedCaption) animateTransitionIn(); + animateTransitionIn(); } // ============================================================================================
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java index 807da0f3..3343368 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java
@@ -280,7 +280,7 @@ } else if (isExpanded() || isMaximized()) { if (isCoordinateInsideCloseButton(x)) { closePanel(StateChangeReason.CLOSE_BUTTON, true); - } else if (canPromoteToNewTab()) { + } else if (isCoordinateInsideOpenTabButton(x) && canPromoteToNewTab()) { mManagementDelegate.promoteToTab(); } } @@ -937,7 +937,7 @@ /** * @return Whether the panel content can be displayed in a new tab. */ - boolean canPromoteToNewTab() { + public boolean canPromoteToNewTab() { return !mActivity.isCustomTab() && canDisplayContentInPanel(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabBarControl.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabBarControl.java index 66ca809..15f58cb 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabBarControl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabBarControl.java
@@ -21,11 +21,9 @@ private static final float SOLID_TRANSPARENT = 0.0f; private final EphemeralTabTitleControl mTitle; - private final EphemeralTabCaptionControl mCaption; // Dimensions used for laying out the controls in the bar. private final float mTextLayerMinHeight; - private final float mTitleCaptionSpacing; /** * @param panel The panel. @@ -36,13 +34,8 @@ public EphemeralTabBarControl(EphemeralTabPanel panel, Context context, ViewGroup container, DynamicResourceLoader loader) { mTitle = new EphemeralTabTitleControl(panel, context, container, loader); - mCaption = panel.canPromoteToNewTab() - ? new EphemeralTabCaptionControl(panel, context, container, loader) - : null; mTextLayerMinHeight = context.getResources().getDimension( R.dimen.contextual_search_text_layer_min_height); - mTitleCaptionSpacing = - context.getResources().getDimension(R.dimen.contextual_search_term_caption_spacing); } /** @@ -54,32 +47,6 @@ } /** - * Returns the spacing that should be placed between the title and the caption. - */ - public float getTitleCaptionSpacing() { - return mTitleCaptionSpacing; - } - - /** - * Updates this bar when in transition to closed/peeked states. - * @param percentage The percentage to the more opened state. - */ - public void updateForCloseOrPeek(float percentage) { - if (percentage == SOLID_OPAQUE) updateForMaximize(SOLID_TRANSPARENT); - - // When the panel is completely closed the caption should be hidden. - if (percentage == SOLID_TRANSPARENT && mCaption != null) mCaption.hide(); - } - - /** - * Updates this bar when in transition to maximized states. - * @param percentage The percentage to the more opened state. - */ - public void updateForMaximize(float percentage) { - if (mCaption != null) mCaption.updatePanelForMaximization(percentage); - } - - /** * Set the text in the panel. * @param text The string to set the text to. */ @@ -95,27 +62,9 @@ } /** - * @return {@link EphemeralTabCaptionControl} object. - */ - public EphemeralTabCaptionControl getCaptionControl() { - return mCaption; - } - - /** - * Gets the current animation percentage for the Caption control, which guides the vertical - * position and opacity of the caption. - * @return The animation percentage ranging from 0.0 to 1.0. - * - */ - public float getCaptionAnimationPercentage() { - return mCaption != null ? mCaption.getAnimationPercentage() : 0; - } - - /** * Removes the bottom bar views from the parent container. */ public void destroy() { mTitle.destroy(); - if (mCaption != null) mCaption.destroy(); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabPanel.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabPanel.java index 83653174..9c0dc94f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabPanel.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabPanel.java
@@ -194,8 +194,8 @@ @Override public SceneOverlayLayer getUpdatedSceneOverlayTree(RectF viewport, RectF visibleViewport, LayerTitleCache layerTitleCache, ResourceManager resourceManager, float yOffset) { - mSceneLayer.update(resourceManager, this, getBarControl(), - getBarControl().getTitleControl(), getBarControl().getCaptionControl()); + mSceneLayer.update( + resourceManager, this, getBarControl(), getBarControl().getTitleControl()); return mSceneLayer; } @@ -213,19 +213,22 @@ super.handleBarClick(x, y); if (isCoordinateInsideCloseButton(x)) { closePanel(StateChangeReason.CLOSE_BUTTON, true); - } else { - if (isPeeking()) { - maximizePanel(StateChangeReason.SEARCH_BAR_TAP); - } else if (canPromoteToNewTab() && mUrl != null) { + } else if (isCoordinateInsideOpenTabButton(x)) { + if (canPromoteToNewTab() && mUrl != null) { closePanel(StateChangeReason.TAB_PROMOTION, false); mActivity.getCurrentTabCreator().createNewTab( new LoadUrlParams(mUrl, PageTransition.LINK), TabLaunchType.FROM_LINK, mActivity.getActivityTabProvider().get()); } + } else if (isPeeking()) { + maximizePanel(StateChangeReason.SEARCH_BAR_TAP); } } - boolean canPromoteToNewTab() { + /** + * @return Whether the panel content can be displayed in a new tab. + */ + public boolean canPromoteToNewTab() { return !mActivity.isCustomTab(); } @@ -253,18 +256,6 @@ if (mSceneLayer != null) mSceneLayer.hideTree(); } - @Override - protected void updatePanelForCloseOrPeek(float percentage) { - super.updatePanelForCloseOrPeek(percentage); - getBarControl().updateForCloseOrPeek(percentage); - } - - @Override - protected void updatePanelForMaximization(float percentage) { - super.updatePanelForMaximization(percentage); - getBarControl().updateForMaximize(percentage); - } - /** * Request opening the ephemeral tab panel when triggered from context menu. * @param url URL of the content to open in the panel
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ContextualSearchSceneLayer.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ContextualSearchSceneLayer.java index be12b6f..91f6fcd 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ContextualSearchSceneLayer.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ContextualSearchSceneLayer.java
@@ -61,6 +61,7 @@ int searchContextViewId = searchBarControl.getSearchContextViewId(); int searchTermViewId = searchBarControl.getSearchTermViewId(); int searchCaptionViewId = searchBarControl.getCaptionViewId(); + int openNewTabIconId = panel.canPromoteToNewTab() ? R.drawable.open_in_new_tab : -1; int searchPromoViewId = promoControl.getViewId(); boolean searchPromoVisible = promoControl.isVisible(); @@ -91,6 +92,7 @@ float searchPanelHeight = panel.getHeight(); float searchBarMarginSide = panel.getBarMarginSide(); + float searchBarMarginTop = panel.getBarMarginTop(); float searchBarHeight = panel.getBarHeight(); float searchContextOpacity = searchBarControl.getSearchBarContextOpacity(); @@ -106,6 +108,7 @@ float searchBarShadowOpacity = panel.getBarShadowOpacity(); final int iconColor = panel.getIconColor(); + final int dragHandlebarColor = panel.getDragHandlebarColor(); float arrowIconOpacity = panel.getArrowIconOpacity(); float arrowIconRotation = panel.getArrowIconRotation(); @@ -134,6 +137,7 @@ searchBarBackgroundColor, searchContextViewId, searchTermViewId, searchCaptionViewId, R.drawable.modern_toolbar_shadow, R.drawable.ic_logo_googleg_24dp, quickActionIconResId, R.drawable.breadcrumb_arrow, + R.drawable.drag_handlebar, openNewTabIconId, ContextualSearchPanel.CLOSE_ICON_DRAWABLE_ID, R.drawable.progress_bar_background, R.drawable.progress_bar_foreground, searchPromoViewId, R.drawable.contextual_search_promo_ripple, searchBarBannerTextViewId, mDpToPx, @@ -144,17 +148,19 @@ searchBarBannerPaddingPx, searchBarBannerRippleWidthPx, searchBarBannerRippleOpacity, searchBarBannerTextOpacity, searchPanelX * mDpToPx, searchPanelY * mDpToPx, searchPanelWidth * mDpToPx, searchPanelHeight * mDpToPx, - searchBarMarginSide * mDpToPx, searchBarHeight * mDpToPx, searchContextOpacity, + searchBarMarginSide * mDpToPx, searchBarMarginTop * mDpToPx, + searchBarHeight * mDpToPx, searchContextOpacity, searchBarControl.getTextLayerMinHeight(), searchTermOpacity, searchBarControl.getSearchTermCaptionSpacing(), searchCaptionAnimationPercentage, searchCaptionVisible, searchBarBorderVisible, searchBarBorderHeight * mDpToPx, searchBarShadowVisible, searchBarShadowOpacity, quickActionIconVisible, thumbnailVisible, thumbnailUrl, customImageVisibilityPercentage, barImageSize, - iconColor, arrowIconOpacity, arrowIconRotation, closeIconOpacity, - isProgressBarVisible, progressBarHeight * mDpToPx, progressBarOpacity, - progressBarCompletion, dividerLineVisibilityPercentage, dividerLineWidth, - dividerLineHeight, dividerLineColor, dividerLineXOffset, touchHighlightVisible, - touchHighlightXOffset, touchHighlightWidth, Profile.getLastUsedProfile()); + iconColor, dragHandlebarColor, arrowIconOpacity, arrowIconRotation, + closeIconOpacity, isProgressBarVisible, progressBarHeight * mDpToPx, + progressBarOpacity, progressBarCompletion, dividerLineVisibilityPercentage, + dividerLineWidth, dividerLineHeight, dividerLineColor, dividerLineXOffset, + touchHighlightVisible, touchHighlightXOffset, touchHighlightWidth, + Profile.getLastUsedProfile()); } @CalledByNative @@ -206,27 +212,28 @@ int searchBarBackgroundResourceId, int searchBarBackgroundColor, int searchContextResourceId, int searchTermResourceId, int searchCaptionResourceId, int searchBarShadowResourceId, int searchProviderIconResourceId, - int quickActionIconResourceId, int arrowUpResourceId, int closeIconResourceId, - int progressBarBackgroundResourceId, int progressBarResourceId, - int searchPromoResourceId, int barBannerRippleResourceId, int barBannerTextResourceId, - float dpToPx, float layoutWidth, float layoutHeight, float basePageBrightness, - float basePageYOffset, WebContents webContents, boolean searchPromoVisible, - float searchPromoHeight, float searchPromoOpacity, int searchPromoBackgroundColor, - boolean searchBarBannerVisible, float searchBarBannerHeight, - float searchBarBannerPaddingPx, float searchBarBannerRippleWidth, - float searchBarBannerRippleOpacity, float searchBarBannerTextOpacity, - float searchPanelX, float searchPanelY, float searchPanelWidth, float searchPanelHeight, - float searchBarMarginSide, float searchBarHeight, float searchContextOpacity, + int quickActionIconResourceId, int arrowUpResourceId, int dragHandlebarResourceId, + int openTabIconResourceId, int closeIconResourceId, int progressBarBackgroundResourceId, + int progressBarResourceId, int searchPromoResourceId, int barBannerRippleResourceId, + int barBannerTextResourceId, float dpToPx, float layoutWidth, float layoutHeight, + float basePageBrightness, float basePageYOffset, WebContents webContents, + boolean searchPromoVisible, float searchPromoHeight, float searchPromoOpacity, + int searchPromoBackgroundColor, boolean searchBarBannerVisible, + float searchBarBannerHeight, float searchBarBannerPaddingPx, + float searchBarBannerRippleWidth, float searchBarBannerRippleOpacity, + float searchBarBannerTextOpacity, float searchPanelX, float searchPanelY, + float searchPanelWidth, float searchPanelHeight, float searchBarMarginSide, + float searchBarMarginTop, float searchBarHeight, float searchContextOpacity, float searchTextLayerMinHeight, float searchTermOpacity, float searchTermCaptionSpacing, float searchCaptionAnimationPercentage, boolean searchCaptionVisible, boolean searchBarBorderVisible, float searchBarBorderHeight, boolean searchBarShadowVisible, float searchBarShadowOpacity, boolean quickActionIconVisible, boolean thumbnailVisible, String thumbnailUrl, float customImageVisibilityPercentage, int barImageSize, int iconColor, - float arrowIconOpacity, float arrowIconRotation, float closeIconOpacity, - boolean isProgressBarVisible, float progressBarHeight, float progressBarOpacity, - int progressBarCompletion, float dividerLineVisibilityPercentage, - float dividerLineWidth, float dividerLineHeight, int dividerLineColor, - float dividerLineXOffset, boolean touchHighlightVisible, float touchHighlightXOffset, - float toucHighlightWidth, Profile profile); + int dragHandlebarColor, float arrowIconOpacity, float arrowIconRotation, + float closeIconOpacity, boolean isProgressBarVisible, float progressBarHeight, + float progressBarOpacity, int progressBarCompletion, + float dividerLineVisibilityPercentage, float dividerLineWidth, float dividerLineHeight, + int dividerLineColor, float dividerLineXOffset, boolean touchHighlightVisible, + float touchHighlightXOffset, float toucHighlightWidth, Profile profile); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/EphemeralTabSceneLayer.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/EphemeralTabSceneLayer.java index d2091e2..2806fcf 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/EphemeralTabSceneLayer.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/EphemeralTabSceneLayer.java
@@ -4,12 +4,9 @@ package org.chromium.chrome.browser.compositor.scene_layer; -import android.support.annotation.Nullable; - import org.chromium.base.annotations.JNINamespace; import org.chromium.chrome.R; import org.chromium.chrome.browser.compositor.bottombar.ephemeraltab.EphemeralTabBarControl; -import org.chromium.chrome.browser.compositor.bottombar.ephemeraltab.EphemeralTabCaptionControl; import org.chromium.chrome.browser.compositor.bottombar.ephemeraltab.EphemeralTabPanel; import org.chromium.chrome.browser.compositor.bottombar.ephemeraltab.EphemeralTabTitleControl; import org.chromium.content_public.browser.WebContents; @@ -42,11 +39,9 @@ * @param panel The OverlayPanel to render. * @param bar {@link EphemeralTabBarControl} object. * @param title {@link EphemeralTabTitleControl} object. - * @param caption {@link EphemeralTabCaptionControl} object. */ public void update(ResourceManager resourceManager, EphemeralTabPanel panel, - EphemeralTabBarControl bar, EphemeralTabTitleControl title, - @Nullable EphemeralTabCaptionControl caption) { + EphemeralTabBarControl bar, EphemeralTabTitleControl title) { // Don't try to update the layer if not initialized or showing. if (resourceManager == null || !panel.isShowing()) return; if (!mIsInitialized) { @@ -55,36 +50,30 @@ // TODO(jinsukkim): Find the right icon/background resource for the tab bar. nativeSetResourceIds(mNativePtr, title.getViewId(), R.drawable.contextual_search_bar_background, R.drawable.modern_toolbar_shadow, - R.drawable.infobar_chrome, R.drawable.btn_close); + R.drawable.infobar_chrome, R.drawable.drag_handlebar, + panel.canPromoteToNewTab() ? R.drawable.open_in_new_tab : -1, + R.drawable.btn_close); mIsInitialized = true; } int titleViewId = title.getViewId(); - int captionViewId = 0; - float captionAnimationPercentage = 0.f; - boolean captionVisible = false; - if (caption != null) { - captionViewId = caption.getViewId(); - captionAnimationPercentage = caption.getAnimationPercentage(); - captionVisible = caption.getIsVisible(); - } boolean isProgressBarVisible = panel.isProgressBarVisible(); float progressBarHeight = panel.getProgressBarHeight(); float progressBarOpacity = panel.getProgressBarOpacity(); int progressBarCompletion = panel.getProgressBarCompletion(); WebContents panelWebContents = panel.getWebContents(); - nativeUpdate(mNativePtr, titleViewId, captionViewId, captionAnimationPercentage, - bar.getTextLayerMinHeight(), bar.getTitleCaptionSpacing(), captionVisible, + nativeUpdate(mNativePtr, titleViewId, bar.getTextLayerMinHeight(), R.drawable.progress_bar_background, R.drawable.progress_bar_foreground, mDpToPx, panel.getBasePageBrightness(), panel.getBasePageY() * mDpToPx, panelWebContents, panel.getOffsetX() * mDpToPx, panel.getOffsetY() * mDpToPx, panel.getWidth() * mDpToPx, panel.getHeight() * mDpToPx, panel.getBarBackgroundColor(), panel.getBarMarginSide() * mDpToPx, - panel.getBarHeight() * mDpToPx, panel.isBarBorderVisible(), - panel.getBarBorderHeight() * mDpToPx, panel.getBarShadowVisible(), - panel.getBarShadowOpacity(), panel.getIconColor(), isProgressBarVisible, - progressBarHeight * mDpToPx, progressBarOpacity, progressBarCompletion); + panel.getBarMarginTop() * mDpToPx, panel.getBarHeight() * mDpToPx, + panel.isBarBorderVisible(), panel.getBarBorderHeight() * mDpToPx, + panel.getBarShadowVisible(), panel.getBarShadowOpacity(), panel.getIconColor(), + panel.getDragHandlebarColor(), isProgressBarVisible, progressBarHeight * mDpToPx, + progressBarOpacity, progressBarCompletion); } @Override @@ -126,15 +115,15 @@ private native void nativeHideTree(long nativeEphemeralTabSceneLayer); private native void nativeSetResourceIds(long nativeEphemeralTabSceneLayer, int barTextResourceId, int barBackgroundResourceId, int barShadowResourceId, - int panelIconResourceId, int closeIconResourceId); + int panelIconResourceId, int dragHandlebarResourceId, int openTabIconResourceId, + int closeIconResourceId); private native void nativeUpdate(long nativeEphemeralTabSceneLayer, int titleViewId, - int captionViewId, float captionAnimationPercentage, float textLayerMinHeight, - float titleCaptionSpacing, boolean captionVisible, int progressBarBackgroundResourceId, + float textLayerMinHeight, int progressBarBackgroundResourceId, int progressBarResourceId, float dpToPx, float basePageBrightness, float basePageYOffset, WebContents webContents, float panelX, float panelY, float panelWidth, float panelHeight, int barBackgroundColor, float barMarginSide, - float barHeight, boolean barBorderVisible, float barBorderHeight, - boolean barShadowVisible, float barShadowOpacity, int iconColor, + float barMarginTop, float barHeight, boolean barBorderVisible, float barBorderHeight, + boolean barShadowVisible, float barShadowOpacity, int iconColor, int dragHandlebarColor, boolean isProgressBarVisible, float progressBarHeight, float progressBarOpacity, int progressBarCompletion); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/ProvidedByWebApkSplashDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/ProvidedByWebApkSplashDelegate.java index 0fb59ac..45c376c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/ProvidedByWebApkSplashDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/ProvidedByWebApkSplashDelegate.java
@@ -21,12 +21,18 @@ /** Delegate which uses splash screen screenshot from the WebAPK's content provider. */ public class ProvidedByWebApkSplashDelegate implements SplashDelegate { + private WebappInfo mWebappInfo; + + public ProvidedByWebApkSplashDelegate(WebappInfo webappInfo) { + mWebappInfo = webappInfo; + } + @Override - public View buildSplashView(WebappInfo webappInfo) { + public View buildSplashView() { Context appContext = ContextUtils.getApplicationContext(); ImageView splashView = new ImageView(appContext); - int backgroundColor = - ColorUtils.getOpaqueColor(webappInfo.backgroundColor(ApiCompatibilityUtils.getColor( + int backgroundColor = ColorUtils.getOpaqueColor( + mWebappInfo.backgroundColor(ApiCompatibilityUtils.getColor( appContext.getResources(), R.color.webapp_default_bg))); splashView.setBackgroundColor(backgroundColor); @@ -34,7 +40,7 @@ try (StrictModeContext smc = StrictModeContext.allowDiskReads()) { splashBitmap = FileUtils.queryBitmapFromContentProvider(appContext, Uri.parse(WebApkCommonUtils.generateSplashContentProviderUri( - webappInfo.webApkPackageName()))); + mWebappInfo.webApkPackageName()))); } if (splashBitmap != null) { splashView.setScaleType(ImageView.ScaleType.FIT_CENTER); @@ -51,6 +57,12 @@ } @Override + public int getSplashHideAnimationDurationMs() { + // TODO(pkotwicz) implement. + return 0; + } + + @Override public boolean shouldWaitForSubsequentPageLoadToHideSplash() { return false; }
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 295ee12..45098048 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
@@ -30,6 +30,7 @@ * activity). */ public class SameActivityWebappSplashDelegate implements SplashDelegate, NativeInitObserver { + public static final int HIDE_ANIMATION_DURATION_MS = 300; public static final String HISTOGRAM_SPLASHSCREEN_DURATION = "Webapp.Splashscreen.Duration"; public static final String HISTOGRAM_SPLASHSCREEN_HIDES = "Webapp.Splashscreen.Hides"; @@ -48,18 +49,17 @@ public SameActivityWebappSplashDelegate(Activity activity, ActivityLifecycleDispatcher lifecycleDispatcher, - TabObserverRegistrar tabObserverRegistrar) { + TabObserverRegistrar tabObserverRegistrar, WebappInfo webappInfo) { mActivity = activity; mLifecycleDispatcher = lifecycleDispatcher; mTabObserverRegistrar = tabObserverRegistrar; + mWebappInfo = webappInfo; mLifecycleDispatcher.register(this); } @Override - public View buildSplashView(WebappInfo webappInfo) { - mWebappInfo = webappInfo; - + public View buildSplashView() { if (mWebappInfo.isForWebApk()) { mWebApkNetworkErrorObserver = new WebApkSplashNetworkErrorObserver(mActivity, mWebappInfo.name()); @@ -67,29 +67,29 @@ } Context context = ContextUtils.getApplicationContext(); - final int backgroundColor = ColorUtils.getOpaqueColor(webappInfo.backgroundColor( + final int backgroundColor = ColorUtils.getOpaqueColor(mWebappInfo.backgroundColor( ApiCompatibilityUtils.getColor(context.getResources(), R.color.webapp_default_bg))); ViewGroup splashScreen = new FrameLayout(context); splashScreen.setBackgroundColor(backgroundColor); - if (webappInfo.isForWebApk()) { - initializeLayout(webappInfo, splashScreen, backgroundColor, - ((WebApkInfo) webappInfo).splashIcon()); + if (mWebappInfo.isForWebApk()) { + initializeLayout( + splashScreen, backgroundColor, ((WebApkInfo) mWebappInfo).splashIcon()); return splashScreen; } WebappDataStorage storage = - WebappRegistry.getInstance().getWebappDataStorage(webappInfo.id()); + WebappRegistry.getInstance().getWebappDataStorage(mWebappInfo.id()); if (storage == null) { - initializeLayout(webappInfo, splashScreen, backgroundColor, null); + initializeLayout(splashScreen, backgroundColor, null); return splashScreen; } storage.getSplashScreenImage(new WebappDataStorage.FetchCallback<Bitmap>() { @Override public void onDataRetrieved(Bitmap splashImage) { - initializeLayout(webappInfo, splashScreen, backgroundColor, splashImage); + initializeLayout(splashScreen, backgroundColor, splashImage); } }); return splashScreen; @@ -117,14 +117,18 @@ } @Override + public int getSplashHideAnimationDurationMs() { + return HIDE_ANIMATION_DURATION_MS; + } + + @Override public boolean shouldWaitForSubsequentPageLoadToHideSplash() { return mWebApkNetworkErrorObserver != null && mWebApkNetworkErrorObserver.isNetworkErrorDialogVisible(); } /** Sets the splash screen layout and sets the splash screen's title and icon. */ - private void initializeLayout(WebappInfo webappInfo, ViewGroup splashScreen, - int backgroundColor, Bitmap splashImage) { + private void initializeLayout(ViewGroup splashScreen, int backgroundColor, Bitmap splashImage) { Context context = ContextUtils.getApplicationContext(); Resources resources = context.getResources(); @@ -132,20 +136,19 @@ boolean selectedIconGenerated = false; boolean selectedIconAdaptive = false; if (selectedIcon == null) { - selectedIcon = webappInfo.icon(); - selectedIconGenerated = webappInfo.isIconGenerated(); - selectedIconAdaptive = webappInfo.isIconAdaptive(); + selectedIcon = mWebappInfo.icon(); + selectedIconGenerated = mWebappInfo.isIconGenerated(); + selectedIconAdaptive = mWebappInfo.isIconAdaptive(); } @SplashLayout.IconClassification int selectedIconClassification = SplashLayout.classifyIcon( context.getResources(), selectedIcon, selectedIconGenerated); SplashLayout.createLayout(context, splashScreen, selectedIcon, selectedIconAdaptive, - selectedIconClassification, webappInfo.name(), + selectedIconClassification, mWebappInfo.name(), ColorUtils.shouldUseLightForegroundOnBackground(backgroundColor)); - recordUma(resources, webappInfo, selectedIconClassification, selectedIcon, - (splashImage != null)); + recordUma(resources, selectedIconClassification, selectedIcon, (splashImage != null)); } /** Called once the splash screen is hidden to record UMA metrics. */ @@ -161,20 +164,19 @@ /** * Records splash screen UMA metrics. * @param resources - * @param webappInfo * @param selectedIconClassification. * @param selectedIcon The icon used on the splash screen. * @param usingDedicatedIcon Whether the PWA provides different icons for the splash screen and * for the app icon. */ - private void recordUma(Resources resources, WebappInfo webappInfo, + private void recordUma(Resources resources, @SplashLayout.IconClassification int selectedIconClassification, Bitmap selectedIcon, boolean usingDedicatedIcon) { mUmaCache = new SameActivityWebappUmaCache(); - mUmaCache.recordSplashscreenBackgroundColor(webappInfo.hasValidBackgroundColor() + mUmaCache.recordSplashscreenBackgroundColor(mWebappInfo.hasValidBackgroundColor() ? SameActivityWebappUmaCache.SplashColorStatus.CUSTOM : SameActivityWebappUmaCache.SplashColorStatus.DEFAULT); - mUmaCache.recordSplashscreenThemeColor(webappInfo.hasValidThemeColor() + mUmaCache.recordSplashscreenThemeColor(mWebappInfo.hasValidThemeColor() ? SameActivityWebappUmaCache.SplashColorStatus.CUSTOM : SameActivityWebappUmaCache.SplashColorStatus.DEFAULT);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/SplashController.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/SplashController.java index 08ab76cb..407bdf6 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/SplashController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/SplashController.java
@@ -4,6 +4,7 @@ package org.chromium.chrome.browser.webapps; +import android.app.Activity; import android.os.SystemClock; import android.support.annotation.IntDef; import android.view.View; @@ -15,6 +16,8 @@ import org.chromium.base.VisibleForTesting; import org.chromium.chrome.browser.WarmupManager; import org.chromium.chrome.browser.compositor.CompositorView; +import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; +import org.chromium.chrome.browser.lifecycle.InflationObserver; import org.chromium.chrome.browser.tab.EmptyTabObserver; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabObserverRegistrar; @@ -23,7 +26,7 @@ import java.lang.annotation.RetentionPolicy; /** Shows and hides splash screen. */ -public class SplashController extends EmptyTabObserver { +public class SplashController extends EmptyTabObserver implements InflationObserver { private static class SingleShotOnDrawListener implements ViewTreeObserver.OnDrawListener { private final View mView; private final Runnable mAction; @@ -61,8 +64,11 @@ int NUM_ENTRIES = 4; } + private final ActivityLifecycleDispatcher mLifecycleDispatcher; private final TabObserverRegistrar mTabObserverRegistrar; + private final Activity mActivity; + private SplashDelegate mDelegate; /** View to which the splash screen is added. */ @@ -70,6 +76,8 @@ private View mSplashView; + private boolean mDidPreInflationStartup; + /** Whether the splash hide animation was started. */ private boolean mWasSplashHideAnimationStarted; @@ -78,21 +86,22 @@ private ObserverList<SplashscreenObserver> mObservers; - public SplashController(TabObserverRegistrar tabObserverRegistrar) { + public SplashController(Activity activity, ActivityLifecycleDispatcher lifecycleDispatcher, + TabObserverRegistrar tabObserverRegistrar) { + mActivity = activity; + mLifecycleDispatcher = lifecycleDispatcher; mTabObserverRegistrar = tabObserverRegistrar; - mTabObserverRegistrar.registerTabObserver(this); mObservers = new ObserverList<>(); + + mLifecycleDispatcher.register(this); + mTabObserverRegistrar.registerTabObserver(this); } - /** Shows the splash screen. */ - public void showSplash( - SplashDelegate delegate, ViewGroup parentView, final WebappInfo webappInfo) { + public void setDelegate(SplashDelegate delegate) { mDelegate = delegate; - mParentView = parentView; - mSplashShownTimestamp = SystemClock.elapsedRealtime(); - - mSplashView = mDelegate.buildSplashView(webappInfo); - mParentView.addView(mSplashView); + if (mDidPreInflationStartup) { + showSplash(); + } } /** @@ -112,6 +121,17 @@ } @Override + public void onPreInflationStartup() { + mDidPreInflationStartup = true; + if (mDelegate != null) { + showSplash(); + } + } + + @Override + public void onPostInflationStartup() {} + + @Override public void didFirstVisuallyNonEmptyPaint(Tab tab) { if (canHideSplashScreen()) { hideSplash(tab, SplashHidesReason.PAINT); @@ -137,7 +157,16 @@ hideSplash(tab, SplashHidesReason.CRASH); } - protected boolean canHideSplashScreen() { + private void showSplash() { + mSplashShownTimestamp = SystemClock.elapsedRealtime(); + try (TraceEvent te = TraceEvent.scoped("SplashScreen.build")) { + mSplashView = mDelegate.buildSplashView(); + } + mParentView = (ViewGroup) mActivity.findViewById(android.R.id.content); + mParentView.addView(mSplashView); + } + + private boolean canHideSplashScreen() { return !mDelegate.shouldWaitForSubsequentPageLoadToHideSplash(); } @@ -164,7 +193,14 @@ recordTraceEventsStartedHidingSplash(); - mSplashView.animate().alpha(0f).withEndAction(() -> { hideSplashNow(tab, reason); }); + int animationDurationMs = mDelegate.getSplashHideAnimationDurationMs(); + if (animationDurationMs == 0) { + hideSplashNow(tab, reason); + return; + } + mSplashView.animate().alpha(0f).setDuration(animationDurationMs).withEndAction(() -> { + hideSplashNow(tab, reason); + }); } private void hideSplashNow(Tab tab, @SplashHidesReason int reason) { @@ -177,6 +213,8 @@ mDelegate.onSplashHidden(tab, reason, mSplashShownTimestamp, splashHiddenTimestamp); notifySplashscreenHidden(mSplashShownTimestamp, splashHiddenTimestamp); + mLifecycleDispatcher.unregister(this); + mDelegate = null; mSplashView = null; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/SplashDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/SplashDelegate.java index 47915f5..9ad08ce 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/SplashDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/SplashDelegate.java
@@ -11,7 +11,7 @@ /** Delegate for {@link SplashController}. */ interface SplashDelegate { /** Builds the splash view. */ - View buildSplashView(WebappInfo webappInfo); + View buildSplashView(); /** * Called when splash screen has been hidden. @@ -23,6 +23,9 @@ void onSplashHidden(Tab tab, @SplashController.SplashHidesReason int reason, long startTimestamp, long endTimestamp); + /** Returns the duration for the splash hide animation. */ + int getSplashHideAnimationDurationMs(); + /** Returns whether to wait for a subsequent page load to hide the splash screen. */ boolean shouldWaitForSubsequentPageLoadToHideSplash(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java index 3f2709f..da0cf4ca 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java
@@ -152,7 +152,9 @@ } @Override - protected void showSplash() { + protected void initSplash() { + super.initSplash(); + // Decide whether to record startup UMA histograms. This is a similar check to the one done // in ChromeTabbedActivity.performPreInflationStartup refer to the comment there for why. if (!LibraryLoader.getInstance().isInitialized()) { @@ -166,7 +168,5 @@ addSplashscreenObserver(new WebApkSplashscreenMetrics(shellLaunchTimestampMs)); } } - - super.showSplash(); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java index cb87a24..843f0fa 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappActivity.java
@@ -25,7 +25,6 @@ import org.chromium.base.ApiCompatibilityUtils; import org.chromium.base.ApplicationStatus; import org.chromium.base.Log; -import org.chromium.base.TraceEvent; import org.chromium.base.VisibleForTesting; import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.metrics.RecordUserAction; @@ -139,7 +138,8 @@ mWebappInfo = createWebappInfo(null); mDirectoryManager = new WebappDirectoryManager(); mTabObserverRegistrar = new TabObserverRegistrar(getLifecycleDispatcher()); - mSplashController = new SplashController(mTabObserverRegistrar); + mSplashController = + new SplashController(this, getLifecycleDispatcher(), mTabObserverRegistrar); mDisclosureSnackbarController = new WebappDisclosureSnackbarController(); } @@ -311,7 +311,7 @@ enterImmersiveMode(); } - showSplash(); + initSplash(); } @Override @@ -885,17 +885,14 @@ return false; } - /** Shows the splash screen. */ - protected void showSplash() { - try (TraceEvent te = TraceEvent.scoped("WebappActivity.showSplash")) { - ViewGroup contentView = (ViewGroup) findViewById(android.R.id.content); - SplashDelegate delegate = mWebappInfo.isSplashProvidedByWebApk() - ? new ProvidedByWebApkSplashDelegate() - : new SameActivityWebappSplashDelegate( - this, getLifecycleDispatcher(), mTabObserverRegistrar); - - mSplashController.showSplash(delegate, contentView, mWebappInfo); - } + /** Inits the splash screen */ + protected void initSplash() { + SplashDelegate delegate = mWebappInfo.isSplashProvidedByWebApk() + ? new ProvidedByWebApkSplashDelegate(mWebappInfo) + : new SameActivityWebappSplashDelegate( + this, getLifecycleDispatcher(), mTabObserverRegistrar, mWebappInfo); + // Splash screen is shown after preInflationStartup() is run and the delegate is set. + mSplashController.setDelegate(delegate); } /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java index 745b6ce4..a079a11 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
@@ -57,7 +57,6 @@ import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.PanelState; import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.StateChangeReason; import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchBarControl; -import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchCaptionControl; import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchImageControl; import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchPanel; import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchQuickActionControl; @@ -932,14 +931,14 @@ // TODO(pedrosimonetti): This is not reliable. Find a better approach. // This taps on the panel in an area that will be selected if the "intelligence" node has // been tap-selected, and that will cause it to be long-press selected. - // We use the far right side (x == 0.9f) to prevent simulating a tap on top of an + // We use the far right side (x == 0.95f) to prevent simulating a tap on top of an // existing long-press selection (the pins are a tap target). This might not work on RTL. // We are using y == 0.35f because otherwise it will fail for long press cases. // It might be better to get the position of the Panel and tap just about outside // the Panel. I suspect some Flaky tests are caused by this problem (ones involving // long press and trying to close with the bar peeking, with a long press selection // established). - tapBasePage(0.9f, 0.35f); + tapBasePage(0.95f, 0.35f); waitForPanelToClose(); } @@ -1032,16 +1031,13 @@ } /** - * Force the Panel to handle a click in the Bar. + * Force the Panel to handle a click on open-in-a-new-tab icon. * @throws InterruptedException */ - private void forcePanelToHandleBarClick() throws InterruptedException { - InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { - @Override - public void run() { - // TODO(donnd): provide better time and x,y data to make this more broadly useful. - mPanel.handleBarClick(0, 0); - } + private void forceOpenTabIconClick() throws InterruptedException { + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + mPanel.handleBarClick(mPanel.getOpenTabIconX() + mPanel.getOpenTabIconDimension() / 2, + mPanel.getBarHeight() / 2); }); } @@ -1599,13 +1595,13 @@ } /* - * Test that tapping on the Search Bar before having a resolved search term does not + * Test that tapping on the open-new-tab icon before having a resolved search term does not * promote to a tab, and that after the resolution it does promote to a tab. */ @Test @SmallTest @Feature({"ContextualSearch"}) - public void testTapSearchBarPromotesToTab() throws InterruptedException, TimeoutException { + public void testPromotesToTab() throws InterruptedException, TimeoutException { // -------- SET UP --------- // Track Tab creation with this helper. final CallbackHelper tabCreatedHelper = new CallbackHelper(); @@ -1624,8 +1620,8 @@ flingPanelUpToTop(); waitForPanelToMaximize(); - // A click in the Bar should not promote since we are still waiting to Resolve. - forcePanelToHandleBarClick(); + // A click on the open-tab icon should not promote since we are still waiting to Resolve. + forceOpenTabIconClick(); // Assert that the Panel is still maximized. waitForPanelToMaximize(); @@ -1633,8 +1629,8 @@ // Let the Search Term Resolution finish. simulateSlowResolveFinished(); - // Now a click in the Bar should promote to a separate tab. - forcePanelToHandleBarClick(); + // Now a click on the icon should promote to a separate tab. + forceOpenTabIconClick(); // The Panel should now be closed. waitForPanelToClose(); @@ -2904,11 +2900,7 @@ TestThreadUtils.runOnUiThreadBlocking(() -> mPanel.simulateTapOnEndButton()); waitForPanelToExpand(); - // Check that the expanded bar is showing the correct image and caption. - Assert.assertTrue(barControl.getCaptionVisible()); - Assert.assertEquals(mActivityTestRule.getActivity().getResources().getString( - ContextualSearchCaptionControl.EXPANED_CAPTION_ID), - barControl.getCaptionText()); + // Check that the expanded bar is showing the correct image. Assert.assertEquals(0.f, imageControl.getCustomImageVisibilityPercentage(), 0); // Go back to peeking.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchFlowTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchFlowTest.java index 6fb074ce..c858186 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchFlowTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchFlowTest.java
@@ -19,6 +19,7 @@ import org.chromium.base.ContextUtils; import org.chromium.base.test.util.CallbackHelper; import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.RetryOnFailure; import org.chromium.chrome.browser.ChromeActivity; @@ -252,6 +253,7 @@ @Test @MediumTest @Feature({"OfflinePrefetch"}) + @DisabledTest public void testPrefetchPageReadyLater() throws Throwable { final String url1 = "http://suggestion1.com/main"; mSuggestionsService.addSuggestion("Suggestion 1", url1, imageUrlBase() + "suggestion1");
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp index f0ebb635..e7b43a6 100644 --- a/chrome/app/settings_strings.grdp +++ b/chrome/app/settings_strings.grdp
@@ -1740,6 +1740,9 @@ <message name="IDS_SETTINGS_INTERNET_CONFIG_SHARE" desc="Settings > Internet > Network config: Label for setting allowing other device users to use the network configuration."> Allow other users of this device to use this network </message> + <message name="IDS_SETTINGS_HIDDEN_NETWORK_WARNING" desc="Settings > Internet > Network config: Text shown when auto connect to the WiFi network is enabled, warning about the dangers of auto-connecting to hidden networks."> + Automatically connecting to a hidden network allows others to see your device and some network settings, and is not recommended. + </message> <message name="IDS_SETTINGS_INTERNET_CONFIG_SAVE_CREDENTIALS" desc="Settings > Internet > Network config: Label for the setting to save identity and password."> Save identity and password </message>
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_HIDDEN_NETWORK_WARNING.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_HIDDEN_NETWORK_WARNING.png.sha1 new file mode 100644 index 0000000..fd39eb1 --- /dev/null +++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_HIDDEN_NETWORK_WARNING.png.sha1
@@ -0,0 +1 @@ +7b67f22ff91633353d0c6e3e61cd2bdfd75aab9a \ No newline at end of file
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 6fda5c2..ec52e2b 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -3734,6 +3734,10 @@ flag_descriptions::kNativeFileSystemAPIDescription, kOsAll, FEATURE_VALUE_TYPE(blink::features::kNativeFileSystemAPI)}, + {"file-handling-api", flag_descriptions::kFileHandlingAPIName, + flag_descriptions::kFileHandlingAPIDescription, kOsCrOS, + FEATURE_VALUE_TYPE(blink::features::kFileHandlingAPI)}, + #if !defined(OS_ANDROID) {"enable-intent-picker", flag_descriptions::kIntentPickerName, flag_descriptions::kIntentPickerDescription, kOsMac | kOsWin | kOsLinux,
diff --git a/chrome/browser/android/compositor/layer/contextual_search_layer.cc b/chrome/browser/android/compositor/layer/contextual_search_layer.cc index 7bd1b3f1..5879f929 100644 --- a/chrome/browser/android/compositor/layer/contextual_search_layer.cc +++ b/chrome/browser/android/compositor/layer/contextual_search_layer.cc
@@ -43,6 +43,8 @@ int search_provider_icon_resource_id, int quick_action_icon_resource_id, int arrow_up_resource_id, + int drag_handlebar_resource_id, + int open_tab_icon_resource_id, int close_icon_resource_id, int progress_bar_background_resource_id, int progress_bar_resource_id, @@ -66,6 +68,7 @@ float search_panel_width, float search_panel_height, float search_bar_margin_side, + float search_bar_margin_top, float search_bar_height, float search_context_opacity, float search_text_layer_min_height, @@ -82,6 +85,7 @@ float custom_image_visibility_percentage, int bar_image_size, int icon_color, + int drag_handlebar_color, float arrow_icon_opacity, float arrow_icon_rotation, float close_icon_opacity, @@ -108,6 +112,7 @@ OverlayPanelLayer::SetResourceIds( search_term_resource_id, panel_shadow_resource_id, search_bar_shadow_resource_id, search_provider_icon_resource_id, + drag_handlebar_resource_id, open_tab_icon_resource_id, close_icon_resource_id); float content_view_top = search_bar_bottom + search_promo_height; @@ -120,9 +125,10 @@ OverlayPanelLayer::SetProperties( dp_to_px, content_layer, content_view_top, search_panel_x, search_panel_y, search_panel_width, search_panel_height, search_bar_background_color, - search_bar_margin_side, search_bar_height, search_bar_top, - search_term_opacity, should_render_bar_border, search_bar_border_height, - search_bar_shadow_visible, search_bar_shadow_opacity, icon_color, + search_bar_margin_side, search_bar_margin_top, search_bar_height, + search_bar_top, search_term_opacity, should_render_bar_border, + search_bar_border_height, search_bar_shadow_visible, + search_bar_shadow_opacity, icon_color, drag_handlebar_color, close_icon_opacity); bool is_rtl = l10n_util::IsLayoutRtl();
diff --git a/chrome/browser/android/compositor/layer/contextual_search_layer.h b/chrome/browser/android/compositor/layer/contextual_search_layer.h index 0af820d1..94b25985 100644 --- a/chrome/browser/android/compositor/layer/contextual_search_layer.h +++ b/chrome/browser/android/compositor/layer/contextual_search_layer.h
@@ -40,6 +40,8 @@ int search_provider_icon_resource_id, int quick_action_icon_resource_id, int arrow_up_resource_id, + int drag_handlebar_resource_id, + int open_tab_icon_resource_id, int close_icon_resource_id, int progress_bar_background_resource_id, int progress_bar_resource_id, @@ -63,6 +65,7 @@ float search_panel_width, float search_panel_height, float search_bar_margin_side, + float search_bar_margin_top, float search_bar_height, float search_context_opacity, float search_text_layer_min_height, @@ -79,6 +82,7 @@ float custom_image_visibility_percentage, int bar_image_size, int icon_color, + int drag_handlebar_color, float arrow_icon_opacity, float arrow_icon_rotation, float close_icon_opacity,
diff --git a/chrome/browser/android/compositor/layer/ephemeral_tab_layer.cc b/chrome/browser/android/compositor/layer/ephemeral_tab_layer.cc index e9984b82..3e2745c 100644 --- a/chrome/browser/android/compositor/layer/ephemeral_tab_layer.cc +++ b/chrome/browser/android/compositor/layer/ephemeral_tab_layer.cc
@@ -20,11 +20,7 @@ void EphemeralTabLayer::SetProperties( int title_view_resource_id, - int caption_view_resource_id, - jfloat caption_animation_percentage, jfloat text_layer_min_height, - jfloat title_caption_spacing, - jboolean caption_visible, int progress_bar_background_resource_id, int progress_bar_resource_id, float dp_to_px, @@ -35,12 +31,14 @@ float panel_height, int bar_background_color, float bar_margin_side, + float bar_margin_top, float bar_height, bool bar_border_visible, float bar_border_height, bool bar_shadow_visible, float bar_shadow_opacity, int icon_color, + int drag_handlebar_color, bool progress_bar_visible, float progress_bar_height, float progress_bar_opacity, @@ -50,19 +48,16 @@ float bar_top = 0.f; float bar_bottom = bar_top + bar_height; - // Title needs no rendering in the base layer as it can be rendered - // together with caption below. Make it invisible. float title_opacity = 0.f; OverlayPanelLayer::SetProperties( dp_to_px, content_layer, bar_height, panel_x, panel_y, panel_width, - panel_height, bar_background_color, bar_margin_side, bar_height, 0.0f, - title_opacity, bar_border_visible, bar_border_height, bar_shadow_visible, - bar_shadow_opacity, icon_color, 1.0f /* icon opacity */); + panel_height, bar_background_color, bar_margin_side, bar_margin_top, + bar_height, 0.0f, title_opacity, bar_border_visible, bar_border_height, + bar_shadow_visible, bar_shadow_opacity, icon_color, drag_handlebar_color, + 1.0f /* icon opacity */); SetupTextLayer(bar_top, bar_height, text_layer_min_height, - caption_view_resource_id, caption_animation_percentage, - caption_visible, title_view_resource_id, - title_caption_spacing); + title_view_resource_id); OverlayPanelLayer::SetProgressBar( progress_bar_background_resource_id, progress_bar_resource_id, @@ -73,17 +68,12 @@ void EphemeralTabLayer::SetupTextLayer(float bar_top, float bar_height, float text_layer_min_height, - int caption_resource_id, - float animation_percentage, - bool caption_visible, - int title_resource_id, - float title_caption_spacing) { + int title_resource_id) { // --------------------------------------------------------------------------- // Setup the Drawing Hierarchy // --------------------------------------------------------------------------- DCHECK(text_layer_.get()); - DCHECK(caption_.get()); DCHECK(title_.get()); // Title @@ -94,39 +84,13 @@ title_->SetBounds(title_resource->size()); } - // Caption - ui::Resource* caption_resource = nullptr; - if (caption_visible) { - // Grabs the dynamic Search Caption resource so we can get a snapshot. - caption_resource = resource_manager_->GetResource( - ui::ANDROID_RESOURCE_TYPE_DYNAMIC, caption_resource_id); - } - - if (animation_percentage != 0.f) { - if (caption_->parent() != text_layer_) { - text_layer_->AddChild(caption_); - } - if (caption_resource) { - caption_->SetUIResourceId(caption_resource->ui_resource()->id()); - caption_->SetBounds(caption_resource->size()); - } - } else if (caption_->parent()) { - caption_->RemoveFromParent(); - } - // --------------------------------------------------------------------------- // Calculate Text Layer Size // --------------------------------------------------------------------------- - // The caption_ may not have had its resource set by this point, if so - // the bounds will be zero and everything will still work. float title_height = title_->bounds().height(); - float caption_height = caption_->bounds().height(); - float layer_height = - std::max(text_layer_min_height, - title_height + caption_height + title_caption_spacing); - float layer_width = - std::max(title_->bounds().width(), caption_->bounds().width()); + float layer_height = std::max(text_layer_min_height, title_height); + float layer_width = title_->bounds().width(); float layer_top = bar_top + (bar_height - layer_height) / 2; text_layer_->SetBounds(gfx::Size(layer_width, layer_height)); @@ -140,57 +104,23 @@ // // ---Top of Text Layer--- <- layer_top // } remaining_height / 2 - // Title } title_height - // } title_caption_spacing - // Caption } caption_height - // } remaining_height / 2 + // Title } title_height // --Bottom of Text Layer- // // --Bottom of Panel Bar- - // If the Caption is not visible the Title is centered in this space, when - // the Caption becomes visible it is animated sliding up into it's position - // with the spacings determined by UI. - // If there is no caption, just vertically center the title. float title_top = (layer_height - title_height) / 2; - - // If we aren't displaying the caption we're done. - if (animation_percentage == 0.f || !caption_resource) { - title_->SetPosition(gfx::PointF(0.f, title_top)); - return; - } - - // Calculate the positions for the Title and Caption when the Caption - // animation is complete. - float remaining_height = - layer_height - title_height - title_caption_spacing - caption_height; - - float title_top_end = remaining_height / 2; - float caption_top_end = title_top_end + title_height + title_caption_spacing; - - // Interpolate between the animation start and end positions (short cut - // if the animation is at the end or start). - title_top = title_top * (1.f - animation_percentage) + - title_top_end * animation_percentage; - - // The Caption starts off the bottom of the Text Layer. - float caption_top = layer_height * (1.f - animation_percentage) + - caption_top_end * animation_percentage; - title_->SetPosition(gfx::PointF(0.f, title_top)); - caption_->SetPosition(gfx::PointF(0.f, caption_top)); } EphemeralTabLayer::EphemeralTabLayer(ui::ResourceManager* resource_manager) : OverlayPanelLayer(resource_manager), title_(cc::UIResourceLayer::Create()), - caption_(cc::UIResourceLayer::Create()), text_layer_(cc::UIResourceLayer::Create()) { // Content layer text_layer_->SetIsDrawable(true); title_->SetIsDrawable(true); - caption_->SetIsDrawable(true); AddBarTextLayer(text_layer_); text_layer_->AddChild(title_);
diff --git a/chrome/browser/android/compositor/layer/ephemeral_tab_layer.h b/chrome/browser/android/compositor/layer/ephemeral_tab_layer.h index 0efb300..3b6c64ee 100644 --- a/chrome/browser/android/compositor/layer/ephemeral_tab_layer.h +++ b/chrome/browser/android/compositor/layer/ephemeral_tab_layer.h
@@ -23,11 +23,7 @@ static scoped_refptr<EphemeralTabLayer> Create( ui::ResourceManager* resource_manager); void SetProperties(int title_view_resource_id, - int caption_view_resource_id, - jfloat caption_animation_percentage, jfloat text_layer_min_height, - jfloat title_caption_spacing, - jboolean caption_visible, int progress_bar_background_resource_id, int progress_bar_resource_id, float dp_to_px, @@ -38,12 +34,14 @@ float panel_height, int bar_background_color, float bar_margin_side, + float bar_margin_top, float bar_height, bool bar_border_visible, float bar_border_height, bool bar_shadow_visible, float bar_shadow_opacity, int icon_color, + int drag_handlebar_color, bool progress_bar_visible, float progress_bar_height, float progress_bar_opacity, @@ -51,11 +49,7 @@ void SetupTextLayer(float bar_top, float bar_height, float text_layer_min_height, - int caption_resource_id, - float animation_percentage, - bool caption_visible, - int context_resource_id, - float title_caption_spacing); + int context_resource_id); protected: explicit EphemeralTabLayer(ui::ResourceManager* resource_manager); @@ -63,7 +57,6 @@ private: scoped_refptr<cc::UIResourceLayer> title_; - scoped_refptr<cc::UIResourceLayer> caption_; scoped_refptr<cc::UIResourceLayer> text_layer_; };
diff --git a/chrome/browser/android/compositor/layer/overlay_panel_layer.cc b/chrome/browser/android/compositor/layer/overlay_panel_layer.cc index 1da13e28..9905c7b5 100644 --- a/chrome/browser/android/compositor/layer/overlay_panel_layer.cc +++ b/chrome/browser/android/compositor/layer/overlay_panel_layer.cc
@@ -48,11 +48,15 @@ int panel_shadow_resource_id, int bar_shadow_resource_id, int panel_icon_resource_id, + int drag_handlebar_resource_id, + int open_tab_icon_resource_id, int close_icon_resource_id) { bar_text_resource_id_ = bar_text_resource_id; panel_shadow_resource_id_ = panel_shadow_resource_id; bar_shadow_resource_id_ = bar_shadow_resource_id; panel_icon_resource_id_ = panel_icon_resource_id; + drag_handlebar_resource_id_ = drag_handlebar_resource_id; + open_tab_icon_resource_id_ = open_tab_icon_resource_id; close_icon_resource_id_ = close_icon_resource_id; } @@ -66,6 +70,7 @@ float panel_height, int bar_background_color, float bar_margin_side, + float bar_margin_top, float bar_height, float bar_offset_y, float bar_text_opacity, @@ -74,7 +79,8 @@ bool bar_shadow_visible, float bar_shadow_opacity, int icon_tint, - float close_icon_opacity) { + int drag_handlebar_tint, + float icon_opacity) { // Grabs required static resources. ui::NinePatchResource* panel_shadow_resource = ui::NinePatchResource::From(resource_manager_->GetResource( @@ -158,6 +164,22 @@ } // --------------------------------------------------------------------------- + // Drag Handlerbar + // --------------------------------------------------------------------------- + ui::Resource* drag_handlebar_resource = + resource_manager_->GetStaticResourceWithTint(drag_handlebar_resource_id_, + drag_handlebar_tint); + drag_handlebar_->SetUIResourceId( + drag_handlebar_resource->ui_resource()->id()); + drag_handlebar_->SetBounds(drag_handlebar_resource->size()); + float drag_handlebar_left = + panel_width / 2 - drag_handlebar_resource->size().width() / 2; + float drag_handlebar_top = + bar_top + bar_margin_top - drag_handlebar_resource->size().height() / 2; + drag_handlebar_->SetPosition( + gfx::PointF(drag_handlebar_left, drag_handlebar_top)); + + // --------------------------------------------------------------------------- // Close Icon // --------------------------------------------------------------------------- // Grab the Close Icon resource. @@ -182,7 +204,33 @@ close_icon_->SetBounds(close_icon_resource->size()); close_icon_->SetPosition( gfx::PointF(close_icon_left, close_icon_top)); - close_icon_->SetOpacity(close_icon_opacity); + close_icon_->SetOpacity(icon_opacity); + + // --------------------------------------------------------------------------- + // Open Tab icon + // --------------------------------------------------------------------------- + if (open_tab_icon_resource_id_ != -1) { + ui::Resource* open_tab_icon_resource = + resource_manager_->GetStaticResourceWithTint(open_tab_icon_resource_id_, + icon_tint); + + // Positions the icon at the end of the bar. + float open_tab_top = close_icon_top; + float open_tab_left; + float margin_from_close_icon = + close_icon_resource->size().width() + bar_margin_side; + if (is_rtl) { + open_tab_left = close_icon_left + margin_from_close_icon; + } else { + open_tab_left = close_icon_left - margin_from_close_icon; + } + + open_tab_icon_->SetUIResourceId( + open_tab_icon_resource->ui_resource()->id()); + open_tab_icon_->SetBounds(open_tab_icon_resource->size()); + open_tab_icon_->SetPosition(gfx::PointF(open_tab_left, open_tab_top)); + open_tab_icon_->SetOpacity(icon_opacity); + } // --------------------------------------------------------------------------- // Content @@ -315,6 +363,8 @@ bar_text_(cc::UIResourceLayer::Create()), bar_shadow_(cc::UIResourceLayer::Create()), panel_icon_(cc::UIResourceLayer::Create()), + drag_handlebar_(cc::UIResourceLayer::Create()), + open_tab_icon_(cc::UIResourceLayer::Create()), close_icon_(cc::UIResourceLayer::Create()), content_container_(cc::SolidColorLayer::Create()), text_container_(cc::Layer::Create()), @@ -346,6 +396,14 @@ // The container that any text in the bar will be added to. text_container_->SetIsDrawable(true); + // Drag Handlebar + drag_handlebar_->SetIsDrawable(true); + layer_->AddChild(drag_handlebar_); + + // Open Tab Icon + open_tab_icon_->SetIsDrawable(true); + layer_->AddChild(open_tab_icon_); + // Close Icon close_icon_->SetIsDrawable(true); layer_->AddChild(close_icon_);
diff --git a/chrome/browser/android/compositor/layer/overlay_panel_layer.h b/chrome/browser/android/compositor/layer/overlay_panel_layer.h index dfe2719..14c84b9 100644 --- a/chrome/browser/android/compositor/layer/overlay_panel_layer.h +++ b/chrome/browser/android/compositor/layer/overlay_panel_layer.h
@@ -28,6 +28,8 @@ int panel_shadow_resource_id, int bar_shadow_resource_id, int panel_icon_resource_id, + int drag_handlebar_resource_id, + int open_tab_resource_id, int close_icon_resource_id); void SetProperties(float dp_to_px, @@ -39,6 +41,7 @@ float panel_height, int bar_background_color, float bar_margin_side, + float bar_margin_top, float bar_height, float bar_offset_y, float bar_text_opacity, @@ -47,7 +50,8 @@ bool bar_shadow_visible, float bar_shadow_opacity, int icon_tint, - float close_icon_opacity); + int drag_handlebar_tint, + float icon_opacity); void SetProgressBar(int progress_bar_background_resource_id, int progress_bar_resource_id, @@ -75,6 +79,8 @@ scoped_refptr<cc::UIResourceLayer> bar_text_; scoped_refptr<cc::UIResourceLayer> bar_shadow_; scoped_refptr<cc::UIResourceLayer> panel_icon_; + scoped_refptr<cc::UIResourceLayer> drag_handlebar_; + scoped_refptr<cc::UIResourceLayer> open_tab_icon_; scoped_refptr<cc::UIResourceLayer> close_icon_; scoped_refptr<cc::Layer> content_container_; scoped_refptr<cc::Layer> text_container_; @@ -86,6 +92,8 @@ int bar_text_resource_id_; int panel_shadow_resource_id_; int bar_shadow_resource_id_; + int drag_handlebar_resource_id_; + int open_tab_icon_resource_id_; int close_icon_resource_id_; };
diff --git a/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc b/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc index a43f781..70137a5 100644 --- a/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc +++ b/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc
@@ -77,6 +77,8 @@ jint search_provider_icon_resource_id, jint quick_action_icon_resource_id, jint arrow_up_resource_id, + jint drag_handlebar_resource_id, + jint open_tab_icon_resource_id, jint close_icon_resource_id, jint progress_bar_background_resource_id, jint progress_bar_resource_id, @@ -104,6 +106,7 @@ jfloat search_panel_width, jfloat search_panel_height, jfloat search_bar_margin_side, + jfloat search_bar_margin_top, jfloat search_bar_height, jfloat search_context_opacity, jfloat search_text_layer_min_height, @@ -121,6 +124,7 @@ jfloat custom_image_visibility_percentage, jint bar_image_size, jint icon_color, + jint drag_handlebar_color, jfloat arrow_icon_opacity, jfloat arrow_icon_rotation, jfloat close_icon_opacity, @@ -167,7 +171,8 @@ search_context_resource_id, search_term_resource_id, search_caption_resource_id, search_bar_shadow_resource_id, search_provider_icon_resource_id, quick_action_icon_resource_id, - arrow_up_resource_id, close_icon_resource_id, + arrow_up_resource_id, drag_handlebar_resource_id, + open_tab_icon_resource_id, close_icon_resource_id, progress_bar_background_resource_id, progress_bar_resource_id, search_promo_resource_id, bar_banner_ripple_resource_id, bar_banner_text_resource_id, dp_to_px, content_layer, @@ -177,19 +182,19 @@ search_bar_banner_ripple_width, search_bar_banner_ripple_opacity, search_bar_banner_text_opacity, search_panel_x, search_panel_y, search_panel_width, search_panel_height, search_bar_margin_side, - search_bar_height, search_context_opacity, search_text_layer_min_height, - search_term_opacity, search_term_caption_spacing, - search_caption_animation_percentage, search_caption_visible, - search_bar_border_visible, search_bar_border_height, - search_bar_shadow_visible, search_bar_shadow_opacity, - quick_action_icon_visible, thumbnail_visible, + search_bar_margin_top, search_bar_height, search_context_opacity, + search_text_layer_min_height, search_term_opacity, + search_term_caption_spacing, search_caption_animation_percentage, + search_caption_visible, search_bar_border_visible, + search_bar_border_height, search_bar_shadow_visible, + search_bar_shadow_opacity, quick_action_icon_visible, thumbnail_visible, custom_image_visibility_percentage, bar_image_size, icon_color, - arrow_icon_opacity, arrow_icon_rotation, close_icon_opacity, - progress_bar_visible, progress_bar_height, progress_bar_opacity, - progress_bar_completion, divider_line_visibility_percentage, - divider_line_width, divider_line_height, divider_line_color, - divider_line_x_offset, touch_highlight_visible, touch_highlight_x_offset, - touch_highlight_width); + drag_handlebar_color, arrow_icon_opacity, arrow_icon_rotation, + close_icon_opacity, progress_bar_visible, progress_bar_height, + progress_bar_opacity, progress_bar_completion, + divider_line_visibility_percentage, divider_line_width, + divider_line_height, divider_line_color, divider_line_x_offset, + touch_highlight_visible, touch_highlight_x_offset, touch_highlight_width); // Make the layer visible if it is not already. contextual_search_layer_->layer()->SetHideLayerAndSubtree(false);
diff --git a/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.h b/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.h index 3b5317c..c36d125 100644 --- a/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.h +++ b/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.h
@@ -48,6 +48,8 @@ jint search_provider_icon_resource_id, jint quick_action_icon_resource_id, jint arrow_up_resource_id, + jint drag_handlebar_resource_id, + jint open_tab_icon_resource_id, jint close_icon_resource_id, jint progress_bar_background_resource_id, jint progress_bar_resource_id, @@ -75,6 +77,7 @@ jfloat search_panel_width, jfloat search_panel_height, jfloat search_bar_margin_side, + jfloat search_bar_margin_top, jfloat search_bar_height, jfloat search_context_opacity, jfloat search_text_layer_min_height, @@ -92,6 +95,7 @@ jfloat custom_image_visibility_percentage, jint bar_image_size, jint icon_color, + jint drag_handlebar_color, jfloat arrow_icon_opacity, jfloat arrow_icon_rotation, jfloat close_icon_opacity,
diff --git a/chrome/browser/android/compositor/scene_layer/ephemeral_tab_scene_layer.cc b/chrome/browser/android/compositor/scene_layer/ephemeral_tab_scene_layer.cc index 49fbfa6..990a017d 100644 --- a/chrome/browser/android/compositor/scene_layer/ephemeral_tab_scene_layer.cc +++ b/chrome/browser/android/compositor/scene_layer/ephemeral_tab_scene_layer.cc
@@ -51,20 +51,19 @@ jint bar_background_resource_id, jint bar_shadow_resource_id, jint panel_icon_resource_id, + jint drag_handlebar_resource_id, + jint open_tab_icon_resource_id, jint close_icon_resource_id) { ephemeral_tab_layer_->SetResourceIds( text_resource_id, bar_background_resource_id, bar_shadow_resource_id, - panel_icon_resource_id, close_icon_resource_id); + panel_icon_resource_id, drag_handlebar_resource_id, + open_tab_icon_resource_id, close_icon_resource_id); } void EphemeralTabSceneLayer::Update(JNIEnv* env, const JavaParamRef<jobject>& object, jint title_view_resource_id, - jint caption_view_resource_id, - jfloat caption_animation_percentage, jfloat text_layer_min_height, - jfloat title_caption_spacing, - jboolean caption_visible, jint progress_bar_background_resource_id, jint progress_bar_resource_id, jfloat dp_to_px, @@ -77,12 +76,14 @@ jfloat panel_height, jint bar_background_color, jfloat bar_margin_side, + jfloat bar_margin_top, jfloat bar_height, jboolean bar_border_visible, jfloat bar_border_height, jboolean bar_shadow_visible, jfloat bar_shadow_opacity, jint icon_color, + jint drag_handlebar_color, jboolean progress_bar_visible, jfloat progress_bar_height, jfloat progress_bar_opacity, @@ -107,13 +108,12 @@ // Move the base page contents up. content_container_->SetPosition(gfx::PointF(0.0f, base_page_offset)); ephemeral_tab_layer_->SetProperties( - title_view_resource_id, caption_view_resource_id, - caption_animation_percentage, text_layer_min_height, - title_caption_spacing, caption_visible, + title_view_resource_id, text_layer_min_height, progress_bar_background_resource_id, progress_bar_resource_id, dp_to_px, content_layer, panel_x, panel_y, panel_width, panel_height, - bar_background_color, bar_margin_side, bar_height, bar_border_visible, - bar_border_height, bar_shadow_visible, bar_shadow_opacity, icon_color, + bar_background_color, bar_margin_side, bar_margin_top, bar_height, + bar_border_visible, bar_border_height, bar_shadow_visible, + bar_shadow_opacity, icon_color, drag_handlebar_color, progress_bar_visible, progress_bar_height, progress_bar_opacity, progress_bar_completion); // Make the layer visible if it is not already.
diff --git a/chrome/browser/android/compositor/scene_layer/ephemeral_tab_scene_layer.h b/chrome/browser/android/compositor/scene_layer/ephemeral_tab_scene_layer.h index 30df0a2..0113e57 100644 --- a/chrome/browser/android/compositor/scene_layer/ephemeral_tab_scene_layer.h +++ b/chrome/browser/android/compositor/scene_layer/ephemeral_tab_scene_layer.h
@@ -41,16 +41,14 @@ jint bar_background_resource_id, jint bar_shadow_resource_id, jint panel_icon_resource_id, + jint drag_handlebar_resource_id, + jint open_tab_icon_resource_id, jint close_icon_resource_id); void Update(JNIEnv* env, const base::android::JavaParamRef<jobject>& object, jint title_view_resource_id, - jint caption_view_resource_id, - jfloat caption_animation_percentage, jfloat text_layer_min_height, - jfloat term_caption_spacing, - jboolean caption_visible, jint progress_bar_background_resource_id, jint progress_bar_resource_id, jfloat dp_to_px, @@ -63,12 +61,14 @@ jfloat panel_height, jint bar_background_color, jfloat bar_margin_side, + jfloat bar_margin_top, jfloat bar_height, jboolean bar_border_visible, jfloat bar_border_height, jboolean bar_shadow_visible, jfloat bar_shadow_opacity, jint icon_color, + jint drag_handlebar_color, jboolean progress_bar_visible, jfloat progress_bar_height, jfloat progress_bar_opacity,
diff --git a/chrome/browser/apps/app_service/extension_apps.cc b/chrome/browser/apps/app_service/extension_apps.cc index 27eded7..05cc292 100644 --- a/chrome/browser/apps/app_service/extension_apps.cc +++ b/chrome/browser/apps/app_service/extension_apps.cc
@@ -22,8 +22,8 @@ #include "chrome/browser/ui/app_list/extension_uninstaller.h" #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/chrome_pages.h" +#include "chrome/browser/web_applications/components/externally_installed_web_app_prefs.h" #include "chrome/browser/web_applications/components/web_app_constants.h" -#include "chrome/browser/web_applications/extensions/web_app_extension_ids_map.h" #include "chrome/common/extensions/extension_metrics.h" #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" #include "chrome/services/app_service/public/mojom/types.mojom.h" @@ -446,14 +446,14 @@ const Profile* profile, const extensions::Extension* extension) { if (extensions::Manifest::IsComponentLocation(extension->location()) || - web_app::ExtensionIdsMap::HasExtensionIdWithInstallSource( + web_app::ExternallyInstalledWebAppPrefs::HasAppIdWithInstallSource( profile->GetPrefs(), extension->id(), web_app::InstallSource::kSystemInstalled)) { return apps::mojom::InstallSource::kSystem; } if (extensions::Manifest::IsPolicyLocation(extension->location()) || - web_app::ExtensionIdsMap::HasExtensionIdWithInstallSource( + web_app::ExternallyInstalledWebAppPrefs::HasAppIdWithInstallSource( profile->GetPrefs(), extension->id(), web_app::InstallSource::kExternalPolicy)) { return apps::mojom::InstallSource::kPolicy; @@ -464,7 +464,7 @@ } if (extension->was_installed_by_default() || - web_app::ExtensionIdsMap::HasExtensionIdWithInstallSource( + web_app::ExternallyInstalledWebAppPrefs::HasAppIdWithInstallSource( profile->GetPrefs(), extension->id(), web_app::InstallSource::kExternalDefault)) { return apps::mojom::InstallSource::kDefault;
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index 53e92dc..60ec33c 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -1497,6 +1497,8 @@ "platform_keys/platform_keys_service.h", "platform_keys/platform_keys_service_factory.cc", "platform_keys/platform_keys_service_factory.h", + "plugin_vm/plugin_vm_files.cc", + "plugin_vm/plugin_vm_files.h", "plugin_vm/plugin_vm_image_download_client.cc", "plugin_vm/plugin_vm_image_download_client.h", "plugin_vm/plugin_vm_image_manager.cc",
diff --git a/chrome/browser/chromeos/apps/apk_web_app_installer.cc b/chrome/browser/chromeos/apps/apk_web_app_installer.cc index 964de94..caf0747 100644 --- a/chrome/browser/chromeos/apps/apk_web_app_installer.cc +++ b/chrome/browser/chromeos/apps/apk_web_app_installer.cc
@@ -11,9 +11,9 @@ #include "base/strings/utf_string_conversions.h" #include "chrome/browser/installable/installable_metrics.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/web_applications/components/externally_installed_web_app_prefs.h" #include "chrome/browser/web_applications/components/install_manager.h" #include "chrome/browser/web_applications/components/web_app_constants.h" -#include "chrome/browser/web_applications/extensions/web_app_extension_ids_map.h" #include "chrome/browser/web_applications/web_app_provider.h" #include "content/public/browser/browser_thread.h" #include "content/public/common/service_manager_connection.h" @@ -135,7 +135,7 @@ // Otherwise, insert this web app into the extensions ID map so it is not // removed automatically. TODO(crbug.com/910008): have a less bad way of doing // this. - web_app::ExtensionIdsMap(profile_->GetPrefs()) + web_app::ExternallyInstalledWebAppPrefs(profile_->GetPrefs()) .Insert(app_url, app_id, web_app::InstallSource::kArc); CompleteInstallation(app_id, code); }
diff --git a/chrome/browser/chromeos/apps/apk_web_app_service.cc b/chrome/browser/chromeos/apps/apk_web_app_service.cc index 3d5b40ed..ebb9861 100644 --- a/chrome/browser/chromeos/apps/apk_web_app_service.cc +++ b/chrome/browser/chromeos/apps/apk_web_app_service.cc
@@ -10,8 +10,8 @@ #include "chrome/browser/chromeos/apps/apk_web_app_service_factory.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/web_applications/components/externally_installed_web_app_prefs.h" #include "chrome/browser/web_applications/components/web_app_constants.h" -#include "chrome/browser/web_applications/extensions/web_app_extension_ids_map.h" #include "components/arc/common/app.mojom.h" #include "components/arc/session/connection_holder.h" #include "components/pref_registry/pref_registry_syncable.h" @@ -85,7 +85,7 @@ } void ApkWebAppService::UninstallWebApp(const web_app::AppId& web_app_id) { - if (!web_app::ExtensionIdsMap::HasExtensionIdWithInstallSource( + if (!web_app::ExternallyInstalledWebAppPrefs::HasAppIdWithInstallSource( profile_->GetPrefs(), web_app_id, web_app::InstallSource::kArc)) { // Do not uninstall a web app that was not installed via ApkWebAppInstaller. return;
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc index 8dd50a11..b0ae8a1 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc
@@ -303,21 +303,23 @@ return base::StrCat(query_pieces); } -std::vector<base::FilePath> SearchByPattern(const base::FilePath& root, - const std::string& query, - size_t max_results) { - std::vector<base::FilePath> prefix_matches; - std::vector<base::FilePath> other_matches; +std::vector<std::pair<base::FilePath, bool>> SearchByPattern( + const base::FilePath& root, + const std::string& query, + size_t max_results) { + std::vector<std::pair<base::FilePath, bool>> prefix_matches; + std::vector<std::pair<base::FilePath, bool>> other_matches; base::FileEnumerator enumerator( - root, true, base::FileEnumerator::FILES, CreateFnmatchQuery(query), - base::FileEnumerator::FolderSearchPolicy::ALL); + root, true, + base::FileEnumerator::DIRECTORIES | base::FileEnumerator::FILES, + CreateFnmatchQuery(query), base::FileEnumerator::FolderSearchPolicy::ALL); for (base::FilePath path = enumerator.Next(); !path.empty(); path = enumerator.Next()) { if (base::StartsWith(path.BaseName().value(), query, base::CompareCase::INSENSITIVE_ASCII)) { - prefix_matches.push_back(path); + prefix_matches.emplace_back(path, enumerator.GetInfo().IsDirectory()); if (max_results && prefix_matches.size() == max_results) { return prefix_matches; } @@ -325,7 +327,7 @@ } if (!max_results || prefix_matches.size() + other_matches.size() < max_results) { - other_matches.push_back(path); + other_matches.emplace_back(path, enumerator.GetInfo().IsDirectory()); } } prefix_matches.insert( @@ -1199,7 +1201,7 @@ } void FileManagerPrivateSearchFilesFunction::OnSearchByPattern( - const std::vector<base::FilePath>& results) { + const std::vector<std::pair<base::FilePath, bool>>& results) { auto my_files_path = file_manager::util::GetMyFilesFolderForProfile( chrome_details_.GetProfile()); @@ -1217,16 +1219,16 @@ auto entries = std::make_unique<base::ListValue>(); entries->GetList().reserve(results.size()); - for (const auto& path : results) { + for (const auto& result : results) { base::FilePath fs_path("/"); - if (!my_files_path.AppendRelativePath(path, &fs_path)) { + if (!my_files_path.AppendRelativePath(result.first, &fs_path)) { continue; } base::DictionaryValue entry; entry.SetKey("fileSystemName", base::Value(fs_name)); entry.SetKey("fileSystemRoot", base::Value(fs_root)); entry.SetKey("fileFullPath", base::Value(fs_path.AsUTF8Unsafe())); - entry.SetKey("fileIsDirectory", base::Value(false)); + entry.SetKey("fileIsDirectory", base::Value(result.second)); entries->GetList().emplace_back(std::move(entry)); }
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.h b/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.h index d916d5c..570d7b96ad 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.h +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.h
@@ -378,7 +378,8 @@ // ExtensionFunction overrides. ResponseAction Run() override; - void OnSearchByPattern(const std::vector<base::FilePath>& results); + void OnSearchByPattern( + const std::vector<std::pair<base::FilePath, bool>>& results); const ChromeExtensionFunctionDetails chrome_details_; };
diff --git a/chrome/browser/chromeos/file_manager/url_util_unittest.cc b/chrome/browser/chromeos/file_manager/url_util_unittest.cc index ed054f9e..21cfe4f 100644 --- a/chrome/browser/chromeos/file_manager/url_util_unittest.cc +++ b/chrome/browser/chromeos/file_manager/url_util_unittest.cc
@@ -23,9 +23,7 @@ // Parse a JSON query string into a base::Value. base::Value ParseJsonQueryString(const std::string& query) { - const std::string json = net::UnescapeURLComponent( - query, net::UnescapeRule::SPACES | net::UnescapeRule::PATH_SEPARATORS | - net::UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS); + const std::string json = net::UnescapeBinaryURLComponent(query); std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(json); return value ? std::move(*value) : base::Value(); }
diff --git a/chrome/browser/chromeos/plugin_vm/plugin_vm_files.cc b/chrome/browser/chromeos/plugin_vm/plugin_vm_files.cc new file mode 100644 index 0000000..a82a899 --- /dev/null +++ b/chrome/browser/chromeos/plugin_vm/plugin_vm_files.cc
@@ -0,0 +1,53 @@ +// 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 "chrome/browser/chromeos/plugin_vm/plugin_vm_files.h" + +#include <utility> + +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/location.h" +#include "base/task/post_task.h" +#include "chrome/browser/chromeos/file_manager/path_util.h" +#include "chrome/browser/chromeos/plugin_vm/plugin_vm_util.h" +#include "chrome/browser/profiles/profile.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" + +namespace { + +void DirExistsResult(bool result, base::OnceCallback<void(bool)> callback) { + std::move(callback).Run(result); +} + +void EnsureDirExistsOnIOThread(base::FilePath dir, + base::OnceCallback<void(bool)> callback) { + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + base::File::Error error = base::File::FILE_OK; + bool result = base::CreateDirectoryAndGetError(dir, &error); + if (!result) { + LOG(ERROR) << "Failed to create PluginVm shared dir " << dir.value() << ": " + << base::File::ErrorToString(error); + } + base::PostTaskWithTraits( + FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(&DirExistsResult, result, std::move(callback))); +} + +} // namespace + +namespace plugin_vm { + +void EnsureDefaultSharedDirExists(Profile* profile, + base::OnceCallback<void(bool)> callback) { + base::FilePath dir = + file_manager::util::GetMyFilesFolderForProfile(profile).Append( + kPluginVmName); + base::PostTaskWithTraits( + FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce(&EnsureDirExistsOnIOThread, dir, std::move(callback))); +} + +} // namespace plugin_vm
diff --git a/chrome/browser/chromeos/plugin_vm/plugin_vm_files.h b/chrome/browser/chromeos/plugin_vm/plugin_vm_files.h new file mode 100644 index 0000000..bc796c6 --- /dev/null +++ b/chrome/browser/chromeos/plugin_vm/plugin_vm_files.h
@@ -0,0 +1,21 @@ +// 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 CHROME_BROWSER_CHROMEOS_PLUGIN_VM_PLUGIN_VM_FILES_H_ +#define CHROME_BROWSER_CHROMEOS_PLUGIN_VM_PLUGIN_VM_FILES_H_ + +#include "base/callback.h" + +class Profile; + +namespace plugin_vm { + +// Ensure default shared dir <cryptohome>/MyFiles/PluginVm exists. Invokes +// |callback| with true if dir is successfully created or already exists. +void EnsureDefaultSharedDirExists(Profile* profile, + base::OnceCallback<void(bool)> callback); + +} // namespace plugin_vm + +#endif // CHROME_BROWSER_CHROMEOS_PLUGIN_VM_PLUGIN_VM_FILES_H_
diff --git a/chrome/browser/chromeos/plugin_vm/plugin_vm_files_unittest.cc b/chrome/browser/chromeos/plugin_vm/plugin_vm_files_unittest.cc new file mode 100644 index 0000000..0ab2160 --- /dev/null +++ b/chrome/browser/chromeos/plugin_vm/plugin_vm_files_unittest.cc
@@ -0,0 +1,72 @@ +// 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 "chrome/browser/chromeos/plugin_vm/plugin_vm_files.h" + +#include <memory> + +#include "base/bind.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/system/sys_info.h" +#include "base/time/time.h" +#include "chrome/browser/chromeos/file_manager/path_util.h" +#include "chrome/test/base/testing_profile.h" +#include "content/public/test/test_browser_thread_bundle.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace plugin_vm { + +const char kLsbRelease[] = + "CHROMEOS_RELEASE_NAME=Chrome OS\n" + "CHROMEOS_RELEASE_VERSION=1.2.3.4\n"; + +class PluginVmFilesTest : public testing::Test { + public: + void Callback(bool expected, bool result) { EXPECT_EQ(result, expected); } + + void SetUp() override { + profile_ = std::make_unique<TestingProfile>(); + base::SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease, base::Time()); + } + + void TearDown() override { profile_.reset(); } + + protected: + content::TestBrowserThreadBundle thread_bundle_; + std::unique_ptr<TestingProfile> profile_; +}; + +TEST_F(PluginVmFilesTest, DirNotExists) { + base::FilePath my_files = + file_manager::util::GetMyFilesFolderForProfile(profile_.get()); + EnsureDefaultSharedDirExists(profile_.get(), + base::BindOnce(&PluginVmFilesTest::Callback, + base::Unretained(this), true)); + thread_bundle_.RunUntilIdle(); +} + +TEST_F(PluginVmFilesTest, DirAlreadyExists) { + base::FilePath my_files = + file_manager::util::GetMyFilesFolderForProfile(profile_.get()); + base::CreateDirectory(my_files.Append("PluginVm")); + EnsureDefaultSharedDirExists(profile_.get(), + base::BindOnce(&PluginVmFilesTest::Callback, + base::Unretained(this), true)); + thread_bundle_.RunUntilIdle(); +} + +TEST_F(PluginVmFilesTest, FileAlreadyExists) { + base::FilePath my_files = + file_manager::util::GetMyFilesFolderForProfile(profile_.get()); + base::FilePath path = my_files.Append("PluginVm"); + EXPECT_TRUE(base::CreateDirectory(my_files)); + EXPECT_EQ(base::WriteFile(path, "", 0), 0); + EnsureDefaultSharedDirExists(profile_.get(), + base::BindOnce(&PluginVmFilesTest::Callback, + base::Unretained(this), false)); + thread_bundle_.RunUntilIdle(); +} + +} // namespace plugin_vm
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc index 6d8ac09..e2add3f 100644 --- a/chrome/browser/extensions/extension_service.cc +++ b/chrome/browser/extensions/extension_service.cc
@@ -64,7 +64,7 @@ #include "chrome/browser/ui/webui/favicon_source.h" #include "chrome/browser/ui/webui/theme_source.h" #include "chrome/browser/upgrade_detector/upgrade_detector.h" -#include "chrome/browser/web_applications/extensions/web_app_extension_ids_map.h" +#include "chrome/browser/web_applications/components/externally_installed_web_app_prefs.h" #include "chrome/common/buildflags.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/crash_keys.h" @@ -162,7 +162,8 @@ // // Long term, PWAs will be completely separate from extensions, and we can // remove this cross-link. - if (web_app::ExtensionIdsMap::HasExtensionId(profile_->GetPrefs(), id)) { + if (web_app::ExternallyInstalledWebAppPrefs::HasAppId(profile_->GetPrefs(), + id)) { return; }
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 222428c..0dedd8e7 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -1085,7 +1085,7 @@ { "name": "enable-filesystem-in-incognito", "owners": [ "rhalavati" ], - "expiry_milestone": 76 + "expiry_milestone": 78 }, { "name": "enable-fs-nosymfollow", @@ -1997,6 +1997,11 @@ "expiry_milestone": 76 }, { + "name": "file-handling-api", + "owners": ["harrisjay@chromium.org", "raymes@chromium.org"], + "expiry_milestone": 79 + }, + { "name": "file-manager-feedback-panel", "owners": [ "adanilo" ], "expiry_milestone": 77
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 43b4c9f..c80708f 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -991,6 +991,11 @@ const char kEffectiveConnectionType3GDescription[] = "3G"; const char kEffectiveConnectionType4GDescription[] = "4G"; +const char kFileHandlingAPIName[] = "File Handling API"; +const char kFileHandlingAPIDescription[] = + "Enables the file handling API, allowing websites to register as file " + "handlers. This depends on native-file-system"; + const char kFillOnAccountSelectName[] = "Fill passwords on account selection"; const char kFillOnAccountSelectDescription[] = "Filling of passwords when an account is explicitly selected by the user "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index f644266..6fdcabc 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -600,6 +600,9 @@ extern const char kEffectiveConnectionType3GDescription[]; extern const char kEffectiveConnectionType4GDescription[]; +extern const char kFileHandlingAPIName[]; +extern const char kFileHandlingAPIDescription[]; + extern const char kFillOnAccountSelectName[]; extern const char kFillOnAccountSelectDescription[];
diff --git a/chrome/browser/profiles/profile_key.cc b/chrome/browser/profiles/profile_key.cc index b225f2b7..946403e 100644 --- a/chrome/browser/profiles/profile_key.cc +++ b/chrome/browser/profiles/profile_key.cc
@@ -5,9 +5,12 @@ #include "chrome/browser/profiles/profile_key.h" #include "base/logging.h" +#include "components/keyed_service/core/simple_dependency_manager.h" ProfileKey::ProfileKey(const base::FilePath& path, ProfileKey* original_key) - : SimpleFactoryKey(path), prefs_(nullptr), original_key_(original_key) {} + : SimpleFactoryKey(path), prefs_(nullptr), original_key_(original_key) { + SimpleDependencyManager::GetInstance()->MarkContextLive(this); +} ProfileKey::~ProfileKey() = default;
diff --git a/chrome/browser/resources/app_management/reducers.js b/chrome/browser/resources/app_management/reducers.js index 1a10663..6b8a4e92 100644 --- a/chrome/browser/resources/app_management/reducers.js +++ b/chrome/browser/resources/app_management/reducers.js
@@ -44,7 +44,9 @@ * @return {AppMap} */ AppState.removeApp = function(apps, action) { - assert(apps[action.id]); + if (!apps.hasOwnProperty(action.id)) { + return apps; + } delete apps[action.id]; return Object.assign({}, apps);
diff --git a/chrome/browser/resources/settings/internet_page/internet_detail_page.html b/chrome/browser/resources/settings/internet_page/internet_detail_page.html index e178d57a..8b6ea2163 100644 --- a/chrome/browser/resources/settings/internet_page/internet_detail_page.html +++ b/chrome/browser/resources/settings/internet_page/internet_detail_page.html
@@ -31,7 +31,7 @@ <dom-module id="settings-internet-detail-page"> <template> - <style include="internet-shared iron-flex"> + <style include="internet-shared settings-shared iron-flex"> :host { padding-bottom: 40px; } @@ -65,6 +65,10 @@ paper-spinner-lite { @apply --cr-icon-height-width; } + .warning { + color: var(--cr-secondary-text-color); + margin-inline-start: var(--settings-controlled-by-spacing); + } </style> <!-- Title section: Icon + name + connection state. --> <div id="titleDiv" class="settings-box first"> @@ -182,6 +186,15 @@ pref="{{autoConnect_}}" label="[[getAutoConnectToggleLabel_(networkProperties_)]]"> </settings-toggle-button> + <!-- Hidden Network Warning --> + <template is="dom-if" + if="[[showHiddenNetworkWarning_(autoConnect_, networkProperties_)]]" + restamp> + <div class="warning"> + <iron-icon icon="cr:warning"></iron-icon> + [[i18n('hiddenNetworkWarning')]] + </div> + </template> </template> <!-- Always-on VPN. --> <template is="dom-if"
diff --git a/chrome/browser/resources/settings/internet_page/internet_detail_page.js b/chrome/browser/resources/settings/internet_page/internet_detail_page.js index 44b742d5..f607fd2 100644 --- a/chrome/browser/resources/settings/internet_page/internet_detail_page.js +++ b/chrome/browser/resources/settings/internet_page/internet_detail_page.js
@@ -88,7 +88,7 @@ globalPolicy: { type: Object, value: null, - observer: 'updateAutoConnectPref_' + observer: 'updateAutoConnectPref_', }, /** @@ -932,6 +932,16 @@ }, /** + * @return {boolean} + * @private + */ + showHiddenNetworkWarning_: function() { + return !!this.autoConnect_ && !!this.autoConnect_.value && + !!this.networkProperties_ && !!this.networkProperties_.WiFi && + !!CrOnc.getActiveValue(this.networkProperties_.WiFi.HiddenSSID); + }, + + /** * Event triggered for elements associated with network properties. * @param {!CustomEvent<!{ * field: string,
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service.cc b/chrome/browser/safe_browsing/chrome_password_protection_service.cc index 8b61aed..10c33b6 100644 --- a/chrome/browser/safe_browsing/chrome_password_protection_service.cc +++ b/chrome/browser/safe_browsing/chrome_password_protection_service.cc
@@ -52,7 +52,7 @@ #include "components/strings/grit/components_strings.h" #include "components/sync/driver/sync_service.h" #include "components/sync/protocol/user_event_specifics.pb.h" -#include "components/sync/user_events/user_event_service.h" +#include "components/sync_user_events/user_event_service.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/navigation_entry.h" #include "content/public/browser/navigation_handle.h"
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc b/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc index 4bb6b66..2e88050 100644 --- a/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc +++ b/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
@@ -31,8 +31,8 @@ #include "components/safe_browsing/password_protection/password_protection_request.h" #include "components/signin/core/browser/account_info.h" #include "components/strings/grit/components_strings.h" -#include "components/sync/user_events/fake_user_event_service.h" #include "components/sync_preferences/testing_pref_service_syncable.h" +#include "components/sync_user_events/fake_user_event_service.h" #include "components/variations/variations_params_manager.h" #include "content/public/browser/navigation_handle.h" #include "content/public/browser/web_contents.h"
diff --git a/chrome/browser/signin/dice_browsertest.cc b/chrome/browser/signin/dice_browsertest.cc index b9a1a0c..2e1327c 100644 --- a/chrome/browser/signin/dice_browsertest.cc +++ b/chrome/browser/signin/dice_browsertest.cc
@@ -55,7 +55,7 @@ #include "components/signin/core/browser/signin_metrics.h" #include "components/signin/core/browser/signin_pref_names.h" #include "components/sync/base/sync_prefs.h" -#include "components/sync/user_events/user_event_service.h" +#include "components/sync_user_events/user_event_service.h" #include "components/variations/variations_switches.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/sync/chrome_sync_client.cc b/chrome/browser/sync/chrome_sync_client.cc index 84dd4ff4..1dbcea5 100644 --- a/chrome/browser/sync/chrome_sync_client.cc +++ b/chrome/browser/sync/chrome_sync_client.cc
@@ -78,11 +78,11 @@ #include "components/sync/engine/ui_model_worker.h" #include "components/sync/model/model_type_store_service.h" #include "components/sync/model_impl/forwarding_model_type_controller_delegate.h" -#include "components/sync/user_events/user_event_service.h" #include "components/sync_bookmarks/bookmark_sync_service.h" #include "components/sync_preferences/pref_service_syncable.h" #include "components/sync_sessions/favicon_cache.h" #include "components/sync_sessions/session_sync_service.h" +#include "components/sync_user_events/user_event_service.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "extensions/browser/api/storage/backend_task_runner.h"
diff --git a/chrome/browser/sync/test/integration/single_client_user_events_sync_test.cc b/chrome/browser/sync/test/integration/single_client_user_events_sync_test.cc index 17d47bf2..9164fff 100644 --- a/chrome/browser/sync/test/integration/single_client_user_events_sync_test.cc +++ b/chrome/browser/sync/test/integration/single_client_user_events_sync_test.cc
@@ -20,7 +20,7 @@ #include "components/sync/driver/sync_driver_switches.h" #include "components/sync/model/model_type_sync_bridge.h" #include "components/sync/protocol/user_event_specifics.pb.h" -#include "components/sync/user_events/user_event_service.h" +#include "components/sync_user_events/user_event_service.h" #include "components/variations/variations_associated_data.h" using fake_server::FakeServer;
diff --git a/chrome/browser/sync/test/integration/two_client_user_events_sync_test.cc b/chrome/browser/sync/test/integration/two_client_user_events_sync_test.cc index a780fda..12140ee 100644 --- a/chrome/browser/sync/test/integration/two_client_user_events_sync_test.cc +++ b/chrome/browser/sync/test/integration/two_client_user_events_sync_test.cc
@@ -12,7 +12,7 @@ #include "chrome/browser/sync/test/integration/user_events_helper.h" #include "chrome/browser/sync/user_event_service_factory.h" #include "components/sync/protocol/user_event_specifics.pb.h" -#include "components/sync/user_events/user_event_service.h" +#include "components/sync_user_events/user_event_service.h" #include "testing/gtest/include/gtest/gtest.h" namespace {
diff --git a/chrome/browser/sync/user_event_service_factory.cc b/chrome/browser/sync/user_event_service_factory.cc index 88a5430..d56f5370 100644 --- a/chrome/browser/sync/user_event_service_factory.cc +++ b/chrome/browser/sync/user_event_service_factory.cc
@@ -19,10 +19,10 @@ #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" -#include "components/sync/user_events/user_event_service_impl.h" -#include "components/sync/user_events/user_event_sync_bridge.h" #include "components/sync_sessions/session_sync_service.h" +#include "components/sync_user_events/no_op_user_event_service.h" +#include "components/sync_user_events/user_event_service_impl.h" +#include "components/sync_user_events/user_event_sync_bridge.h" namespace browser_sync {
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 595716f9..f6b50847 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -361,7 +361,7 @@ public_deps = [ "//components/dom_distiller/core", "//components/sync", - "//components/sync/user_events", + "//components/sync_user_events", "//components/translate/content/browser", "//content/public/browser", ] @@ -3281,6 +3281,8 @@ "app_list/search/search_resource_manager.h", "app_list/search/search_result_ranker/app_launch_predictor.cc", "app_list/search/search_result_ranker/app_launch_predictor.h", + "app_list/search/search_result_ranker/app_list_launch_recorder.cc", + "app_list/search/search_result_ranker/app_list_launch_recorder.h", "app_list/search/search_result_ranker/app_search_result_ranker.cc", "app_list/search/search_result_ranker/app_search_result_ranker.h", "app_list/search/search_result_ranker/frecency_store.cc", @@ -3291,6 +3293,8 @@ "app_list/search/search_result_ranker/recurrence_predictor.h", "app_list/search/search_result_ranker/recurrence_ranker.cc", "app_list/search/search_result_ranker/recurrence_ranker.h", + "app_list/search/search_result_ranker/search_result_ranker.cc", + "app_list/search/search_result_ranker/search_result_ranker.h", "app_list/search/settings_shortcut/settings_shortcut_metadata.cc", "app_list/search/settings_shortcut/settings_shortcut_metadata.h", "app_list/search/settings_shortcut/settings_shortcut_provider.cc",
diff --git a/chrome/browser/ui/app_list/search/mixer.cc b/chrome/browser/ui/app_list/search/mixer.cc index 28f50ac2..a5e1eef 100644 --- a/chrome/browser/ui/app_list/search/mixer.cc +++ b/chrome/browser/ui/app_list/search/mixer.cc
@@ -18,7 +18,7 @@ #include "chrome/browser/ui/app_list/search/chrome_search_result.h" #include "chrome/browser/ui/app_list/search/search_provider.h" #include "chrome/browser/ui/app_list/search/search_result_ranker/ranking_item_util.h" -#include "chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker.h" +#include "chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.h" namespace app_list { @@ -43,7 +43,7 @@ providers_.emplace_back(provider); } - void FetchResults() { + void FetchResults(SearchResultRanker* ranker) { results_.clear(); for (const SearchProvider* provider : providers_) { @@ -59,6 +59,8 @@ } } + if (ranker) + ranker->Rank(results_); std::sort(results_.begin(), results_.end()); } @@ -79,11 +81,7 @@ }; Mixer::Mixer(AppListModelUpdater* model_updater) - : model_updater_(model_updater), - boost_coefficient_(base::GetFieldTrialParamByFeatureAsDouble( - app_list_features::kEnableAdaptiveResultRanker, - "boost_coefficient", - 0.1)) {} + : model_updater_(model_updater) {} Mixer::~Mixer() = default; size_t Mixer::AddGroup(size_t max_results, double multiplier, double boost) { @@ -114,25 +112,6 @@ // number* will be kept (e.g., an app result takes priority over a web store // result with the same ID). RemoveDuplicates(&results); - - // Tweak the rankings using the ranker if it exists. - if (app_list_features::IsAdaptiveResultRankerEnabled() && ranker_) { - base::flat_map<std::string, float> ranks = ranker_->Rank(); - - for (auto& result : results) { - RankingItemType type = RankingItemTypeFromSearchResult(*result.result); - const auto& rank_it = ranks.find(std::to_string(static_cast<int>(type))); - // The ranker only contains entries trained with types relating to files - // or the omnibox. This means scores for apps, app shortcuts, and answer - // cards will be unchanged. - if (rank_it != ranks.end()) - // Ranker scores are guaranteed to be in [0,1]. But, enforce that the - // result of tweaking does not put the score above 3.0, as that may - // interfere with apps or answer cards. - result.score += std::min(rank_it->second * boost_coefficient_, 3.0f); - } - } - std::sort(results.begin(), results.end()); const size_t original_size = results.size(); @@ -177,26 +156,19 @@ } void Mixer::FetchResults() { + if (ranker_) + ranker_->FetchRankings(); for (const auto& group : groups_) - group->FetchResults(); + group->FetchResults(ranker_.get()); } -void Mixer::SetRecurrenceRanker(std::unique_ptr<RecurrenceRanker> ranker) { +void Mixer::SetSearchResultRanker(std::unique_ptr<SearchResultRanker> ranker) { ranker_ = std::move(ranker); } void Mixer::Train(const std::string& id, RankingItemType type) { - if (!ranker_) - return; - - if (type == RankingItemType::kFile || - type == RankingItemType::kOmniboxGeneric || - type == RankingItemType::kOmniboxBookmark || - type == RankingItemType::kOmniboxDocument || - type == RankingItemType::kOmniboxHistory || - type == RankingItemType::kOmniboxSearch) { - ranker_->Record(std::to_string(static_cast<int>(type))); - } + if (ranker_) + ranker_->Train(id, type); } } // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/mixer.h b/chrome/browser/ui/app_list/search/mixer.h index c1bc958..53ccc611 100644 --- a/chrome/browser/ui/app_list/search/mixer.h +++ b/chrome/browser/ui/app_list/search/mixer.h
@@ -22,8 +22,8 @@ FORWARD_DECLARE_TEST(MixerTest, Publish); } -class RecurrenceRanker; class SearchProvider; +class SearchResultRanker; enum class RankingItemType; // Mixer collects results from providers, sorts them and publishes them to the @@ -49,15 +49,13 @@ // Collects the results, sorts and publishes them. void MixAndPublish(size_t num_max_results); - // Add a |RecurrenceRanker| to tweak mixing results. - void SetRecurrenceRanker(std::unique_ptr<RecurrenceRanker> ranker); + // Sets a SearchResultRanker to re-rank search results before they are + // published. + void SetSearchResultRanker(std::unique_ptr<SearchResultRanker> ranker); // Handle a training signal. void Train(const std::string& id, RankingItemType type); - private: - FRIEND_TEST_ALL_PREFIXES(test::MixerTest, Publish); - // Used for sorting and mixing results. struct SortData { SortData(); @@ -70,6 +68,9 @@ }; typedef std::vector<Mixer::SortData> SortedResults; + private: + FRIEND_TEST_ALL_PREFIXES(test::MixerTest, Publish); + class Group; typedef std::vector<std::unique_ptr<Group>> Groups; @@ -85,12 +86,8 @@ Groups groups_; - // Adaptive category ranking model, which tweaks the score of search results. - std::unique_ptr<RecurrenceRanker> ranker_; - - // How much the scores produced by |ranker_| affect the final scores. - // Controlled by Finch. - float boost_coefficient_; + // Adaptive models used for re-ranking search results. + std::unique_ptr<SearchResultRanker> ranker_; DISALLOW_COPY_AND_ASSIGN(Mixer); };
diff --git a/chrome/browser/ui/app_list/search/search_controller.cc b/chrome/browser/ui/app_list/search/search_controller.cc index 4460635..dec8a0f 100644 --- a/chrome/browser/ui/app_list/search/search_controller.cc +++ b/chrome/browser/ui/app_list/search/search_controller.cc
@@ -10,6 +10,7 @@ #include <vector> #include "ash/public/cpp/app_list/app_list_config.h" +#include "ash/public/cpp/app_list/app_list_features.h" #include "base/bind.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" @@ -19,12 +20,33 @@ #include "chrome/browser/ui/app_list/app_list_model_updater.h" #include "chrome/browser/ui/app_list/search/chrome_search_result.h" #include "chrome/browser/ui/app_list/search/search_provider.h" +#include "chrome/browser/ui/app_list/search/search_result_ranker/app_list_launch_recorder.h" #include "chrome/browser/ui/app_list/search/search_result_ranker/app_search_result_ranker.h" +#include "chrome/browser/ui/app_list/search/search_result_ranker/ranking_item_util.h" #include "chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker.h" +#include "chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.h" #include "chrome/browser/ui/ash/tablet_mode_client.h" namespace app_list { +namespace { + +// Normalizes training targets by removing any scheme prefix and trailing slash: +// "arc://[id]/" to "[id]". This is necessary because apps launched from +// different parts of the launcher have differently formatted IDs. +std::string NormalizeId(const std::string& id) { + std::string result(id); + // No existing scheme names include the delimiter string "://". + std::size_t delimiter_index = result.find("://"); + if (delimiter_index != std::string::npos) + result.erase(0, delimiter_index + 3); + if (!result.empty() && result.back() == '/') + result.pop_back(); + return result; +} + +} // namespace + SearchController::SearchController(AppListModelUpdater* model_updater, AppListControllerDelegate* list_controller, Profile* profile) @@ -42,6 +64,7 @@ provider->Start(query); dispatching_query_ = false; + last_query_ = query; query_for_recommendation_ = query.empty(); OnResultsChanged(); @@ -127,12 +150,27 @@ return nullptr; } -void SearchController::SetRecurrenceRanker( - std::unique_ptr<RecurrenceRanker> ranker) { - mixer_->SetRecurrenceRanker(std::move(ranker)); +void SearchController::SetSearchResultRanker( + std::unique_ptr<SearchResultRanker> ranker) { + mixer_->SetSearchResultRanker(std::move(ranker)); } void SearchController::Train(const std::string& id, RankingItemType type) { + if (app_list_features::IsAppListLaunchRecordingEnabled()) { + AppListLaunchRecorder::LaunchType launch_type; + if (type == RankingItemType::kApp || + type == RankingItemType::kArcAppShortcut) { + launch_type = AppListLaunchRecorder::APP_TILES; + } else { + launch_type = AppListLaunchRecorder::RESULTS_LIST; + } + + // TODO(951287): Record the last-used domain and app. + AppListLaunchRecorder::GetInstance()->Record( + {launch_type, NormalizeId(id), base::UTF16ToUTF8(last_query_), + std::string(), std::string()}); + } + for (const auto& provider : providers_) provider->Train(id, type); mixer_->Train(id, type);
diff --git a/chrome/browser/ui/app_list/search/search_controller.h b/chrome/browser/ui/app_list/search/search_controller.h index b9a6ce1..79e3ca9 100644 --- a/chrome/browser/ui/app_list/search/search_controller.h +++ b/chrome/browser/ui/app_list/search/search_controller.h
@@ -23,7 +23,7 @@ namespace app_list { class AppSearchResultRanker; -class RecurrenceRanker; +class SearchResultRanker; class SearchProvider; enum class RankingItemType; @@ -54,8 +54,10 @@ ChromeSearchResult* FindSearchResult(const std::string& result_id); ChromeSearchResult* GetResultByTitleForTest(const std::string& title); - // Set a |RecurrenceRanker| to tweak search results. - void SetRecurrenceRanker(std::unique_ptr<RecurrenceRanker> ranker); + // Sets a SearchResultRanker to re-rank search results before they are + // published. The Mixer owned by the SearchController will take ownership of + // |ranker|. + void SetSearchResultRanker(std::unique_ptr<SearchResultRanker> ranker); // Sends training signal to each |providers_| void Train(const std::string& id, RankingItemType type); @@ -72,6 +74,9 @@ // If true, the search results are shown on the launcher start page. bool query_for_recommendation_ = false; + // The query associated with the most recent search. + base::string16 last_query_; + using Providers = std::vector<std::unique_ptr<SearchProvider>>; Providers providers_; std::unique_ptr<Mixer> mixer_;
diff --git a/chrome/browser/ui/app_list/search/search_controller_factory.cc b/chrome/browser/ui/app_list/search/search_controller_factory.cc index e2c8120..a816f91 100644 --- a/chrome/browser/ui/app_list/search/search_controller_factory.cc +++ b/chrome/browser/ui/app_list/search/search_controller_factory.cc
@@ -26,7 +26,7 @@ #include "chrome/browser/ui/app_list/search/mixer.h" #include "chrome/browser/ui/app_list/search/omnibox_provider.h" #include "chrome/browser/ui/app_list/search/search_controller.h" -#include "chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker.h" +#include "chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.h" #include "chrome/browser/ui/app_list/search/settings_shortcut/settings_shortcut_provider.h" #include "chrome/common/chrome_features.h" #include "chrome/common/chrome_switches.h" @@ -168,28 +168,8 @@ std::make_unique<CrostiniRepositorySearchProvider>(profile)); } - if (app_list_features::IsAdaptiveResultRankerEnabled()) { - RecurrenceRankerConfigProto group_ranker_config; - group_ranker_config.set_min_seconds_between_saves(240u); - auto* predictor = - group_ranker_config.mutable_zero_state_frecency_predictor(); - predictor->set_target_limit(base::GetFieldTrialParamByFeatureAsInt( - app_list_features::kEnableAdaptiveResultRanker, "target_limit", 200)); - predictor->set_decay_coeff(base::GetFieldTrialParamByFeatureAsDouble( - app_list_features::kEnableAdaptiveResultRanker, "decay_coeff", 0.8f)); - auto* fallback = group_ranker_config.mutable_fallback_predictor(); - fallback->set_target_limit(base::GetFieldTrialParamByFeatureAsInt( - app_list_features::kEnableAdaptiveResultRanker, "fallback_target_limit", - 200)); - fallback->set_decay_coeff(base::GetFieldTrialParamByFeatureAsDouble( - app_list_features::kEnableAdaptiveResultRanker, "fallback_decay_coeff", - 0.8f)); - - controller->SetRecurrenceRanker(std::make_unique<RecurrenceRanker>( - profile->GetPath().AppendASCII("adaptive_result_ranker.proto"), - group_ranker_config, - chromeos::ProfileHelper::IsEphemeralUserProfile(profile))); - } + controller->SetSearchResultRanker( + std::make_unique<SearchResultRanker>(profile)); return controller; }
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/app_list_launch_recorder.cc b/chrome/browser/ui/app_list/search/search_result_ranker/app_list_launch_recorder.cc new file mode 100644 index 0000000..2508a50 --- /dev/null +++ b/chrome/browser/ui/app_list/search/search_result_ranker/app_list_launch_recorder.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 "chrome/browser/ui/app_list/search/search_result_ranker/app_list_launch_recorder.h" + +#include "base/task/post_task.h" + +namespace app_list { + +using LaunchInfo = AppListLaunchRecorder::LaunchInfo; + +AppListLaunchRecorder::LaunchInfo::LaunchInfo( + AppListLaunchRecorder::LaunchType launch_type, + const std::string& target, + const std::string& query, + const std::string& domain, + const std::string& app) + : launch_type(launch_type), + target(target), + query(query), + domain(domain), + app(app) {} + +AppListLaunchRecorder::LaunchInfo::LaunchInfo(const LaunchInfo& other) = + default; + +AppListLaunchRecorder::LaunchInfo::~LaunchInfo() = default; + +AppListLaunchRecorder* AppListLaunchRecorder::GetInstance() { + static base::NoDestructor<AppListLaunchRecorder> recorder; + return recorder.get(); +} + +AppListLaunchRecorder::AppListLaunchRecorder() = default; +AppListLaunchRecorder::~AppListLaunchRecorder() = default; + +std::unique_ptr<AppListLaunchRecorder::LaunchEventSubscription> +AppListLaunchRecorder::RegisterCallback(const LaunchEventCallback& callback) { + // TODO(951287): implement a metrics provider that is notified of these + // events. + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return callback_list_.Add(callback); +} + +// Notifies all observers of the given |launch_info|. If the +// AppListMetricsProvider has been constructed, this will queue an +// AppListLaunchEvent to be provided to the metrics service. +void AppListLaunchRecorder::Record(const LaunchInfo& launch_info) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + callback_list_.Notify(launch_info); +} + +} // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/app_list_launch_recorder.h b/chrome/browser/ui/app_list/search/search_result_ranker/app_list_launch_recorder.h new file mode 100644 index 0000000..1d65fe5 --- /dev/null +++ b/chrome/browser/ui/app_list/search/search_result_ranker/app_list_launch_recorder.h
@@ -0,0 +1,90 @@ +// 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 CHROME_BROWSER_UI_APP_LIST_SEARCH_SEARCH_RESULT_RANKER_APP_LIST_LAUNCH_RECORDER_H_ +#define CHROME_BROWSER_UI_APP_LIST_SEARCH_SEARCH_RESULT_RANKER_APP_LIST_LAUNCH_RECORDER_H_ + +#include <memory> + +#include "base/callback_list.h" +#include "base/macros.h" +#include "base/no_destructor.h" +#include "base/observer_list.h" +#include "base/sequence_checker.h" + +namespace app_list { + +class SearchController; + +// AppListLaunchRecorder is a singleton that can be called to send hashed +// logging events to UMA. Typical usage is: +// +// AppListLaunchRecorder::GetInstance()->Record(my_data); +// +// This should only be called from the browser UI thread. +class AppListLaunchRecorder { + public: + // TODO(951287): Replace this with the relevant enum from the proto to be + // added to ChromeUserMetricsExtension. + enum LaunchType { APP_TILES, RESULTS_LIST }; + + // Stores information about a single launch event to be logged by a call to + // Record. + struct LaunchInfo { + LaunchInfo(LaunchType launch_type, + const std::string& target, + const std::string& query, + const std::string& domain, + const std::string& app); + LaunchInfo(const LaunchInfo& other); + ~LaunchInfo(); + + LaunchType launch_type; + // A string identifier of the item being launched, eg. an app ID or + // filepath. + std::string target; + // The search query at the time of launch. If this is a zero-state launch + // (eg. from the suggested chips), this should be the empty string. + std::string query; + // The last-visited domain at the time of launch. + std::string domain; + // The app ID of the last-opened app at the time of launch. + std::string app; + }; + + using LaunchEventCallback = + base::RepeatingCallback<void(const AppListLaunchRecorder::LaunchInfo&)>; + using LaunchEventSubscription = base::CallbackList<void( + const AppListLaunchRecorder::LaunchInfo&)>::Subscription; + + // Returns the instance of AppListLaunchRecorder. + static AppListLaunchRecorder* GetInstance(); + + // Registers a callback to be invoked on a call to Record(). + std::unique_ptr<LaunchEventSubscription> RegisterCallback( + const LaunchEventCallback& callback); + + private: + friend class base::NoDestructor<AppListLaunchRecorder>; + + // These are the clients of hashed logging: + friend class app_list::SearchController; + + // Adds |launch_info| to the cache of launches to be hashed and provided to + // the metrics service on a call to ProvideCurrentSessionData. + void Record(const LaunchInfo& launch_info); + + AppListLaunchRecorder(); + ~AppListLaunchRecorder(); + + base::CallbackList<void(const LaunchInfo&)> callback_list_; + + SEQUENCE_CHECKER(sequence_checker_); + + DISALLOW_COPY_AND_ASSIGN(AppListLaunchRecorder); +}; + +} // namespace app_list + +#endif // CHROME_BROWSER_UI_APP_LIST_SEARCH_SEARCH_RESULT_RANKER_APP_LIST_LAUNCH_RECORDER_H_
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.cc b/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.cc new file mode 100644 index 0000000..4ec3843 --- /dev/null +++ b/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.cc
@@ -0,0 +1,128 @@ +// 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 "chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.h" + +#include <algorithm> + +#include "ash/public/cpp/app_list/app_list_features.h" +#include "ash/public/cpp/app_list/app_list_types.h" +#include "base/macros.h" +#include "base/metrics/field_trial_params.h" +#include "base/strings/string_number_conversions.h" +#include "chrome/browser/chromeos/profiles/profile_helper.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/app_list/search/chrome_search_result.h" +#include "chrome/browser/ui/app_list/search/search_result_ranker/ranking_item_util.h" +#include "chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker.h" + +namespace app_list { +namespace { + +using base::Time; +using base::TimeDelta; + +// Limits how frequently models are queried for ranking results. +constexpr TimeDelta kMinSecondsBetweenFetches = TimeDelta::FromSeconds(1); + +// Represents each model used within the SearchResultRanker. +enum class Model { NONE, RESULTS_LIST_GROUP_RANKER }; + +// Returns the model relevant for predicting launches for results with the given +// |type|. +Model ModelForType(RankingItemType type) { + switch (type) { + case RankingItemType::kFile: + case RankingItemType::kOmniboxGeneric: + case RankingItemType::kOmniboxBookmark: + case RankingItemType::kOmniboxDocument: + case RankingItemType::kOmniboxHistory: + case RankingItemType::kOmniboxSearch: + return Model::RESULTS_LIST_GROUP_RANKER; + default: + return Model::NONE; + } +} + +} // namespace + +SearchResultRanker::SearchResultRanker(Profile* profile) { + if (app_list_features::IsAdaptiveResultRankerEnabled()) { + RecurrenceRankerConfigProto config; + config.set_min_seconds_between_saves(240u); + auto* predictor = config.mutable_zero_state_frecency_predictor(); + predictor->set_target_limit(base::GetFieldTrialParamByFeatureAsInt( + app_list_features::kEnableAdaptiveResultRanker, "target_limit", 200)); + predictor->set_decay_coeff(base::GetFieldTrialParamByFeatureAsDouble( + app_list_features::kEnableAdaptiveResultRanker, "decay_coeff", 0.8f)); + auto* fallback = config.mutable_fallback_predictor(); + fallback->set_target_limit(base::GetFieldTrialParamByFeatureAsInt( + app_list_features::kEnableAdaptiveResultRanker, "fallback_target_limit", + 200)); + fallback->set_decay_coeff(base::GetFieldTrialParamByFeatureAsDouble( + app_list_features::kEnableAdaptiveResultRanker, "fallback_decay_coeff", + 0.8f)); + + results_list_group_ranker_ = std::make_unique<RecurrenceRanker>( + profile->GetPath().AppendASCII("adaptive_result_ranker.proto"), config, + chromeos::ProfileHelper::IsEphemeralUserProfile(profile)); + + results_list_boost_coefficient_ = base::GetFieldTrialParamByFeatureAsDouble( + app_list_features::kEnableAdaptiveResultRanker, "boost_coefficient", + 0.1); + } +} + +SearchResultRanker::~SearchResultRanker() = default; + +void SearchResultRanker::FetchRankings() { + // The search controller potentially calls SearchController::FetchResults + // several times for each user's search, so we cache the results of querying + // the models for a short time, to prevent uneccessary queries. + const auto& now = Time::Now(); + if (now - time_of_last_fetch_ < kMinSecondsBetweenFetches) + return; + time_of_last_fetch_ = now; + + if (results_list_group_ranker_) { + group_ranks_.clear(); + group_ranks_ = results_list_group_ranker_->Rank(); + } +} + +void SearchResultRanker::Rank(Mixer::SortedResults& results) { + for (auto& result : results) { + const RankingItemType& type = + RankingItemTypeFromSearchResult(*result.result); + const Model& model = ModelForType(type); + + if (model == Model::RESULTS_LIST_GROUP_RANKER && + results_list_group_ranker_) { + const auto& rank_it = + group_ranks_.find(base::NumberToString(static_cast<int>(type))); + // The ranker only contains entries trained with types relating to files + // or the omnibox. This means scores for apps, app shortcuts, and answer + // cards will be unchanged. + if (rank_it != group_ranks_.end()) { + // Ranker scores are guaranteed to be in [0,1]. But, enforce that the + // result of tweaking does not put the score above 3.0, as that may + // interfere with apps or answer cards. + result.score = std::min( + result.score + rank_it->second * results_list_boost_coefficient_, + 3.0); + } + } + } +} + +void SearchResultRanker::Train(const std::string& id, RankingItemType type) { + const Model& model = ModelForType(type); + + if (model == Model::RESULTS_LIST_GROUP_RANKER && results_list_group_ranker_) { + results_list_group_ranker_->Record( + base::NumberToString(static_cast<int>(type))); + } +} + +} // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.h b/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.h new file mode 100644 index 0000000..3b825c0 --- /dev/null +++ b/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.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 CHROME_BROWSER_UI_APP_LIST_SEARCH_SEARCH_RESULT_RANKER_SEARCH_RESULT_RANKER_H_ +#define CHROME_BROWSER_UI_APP_LIST_SEARCH_SEARCH_RESULT_RANKER_SEARCH_RESULT_RANKER_H_ + +#include "base/containers/flat_map.h" +#include "base/time/time.h" +#include "chrome/browser/ui/app_list/search/mixer.h" + +class Profile; + +namespace app_list { + +class RecurrenceRanker; +enum class RankingItemType; + +// SearchResultRanker re-ranks launcher search and zero-state results using a +// collection of on-device models. It can be provided training signals via the +// Train method, which are then forwarded to the appropriate model. +// FetchRankings queries each model for ranking results. Rank modifies the +// scores of provided search results, which are intended to be the output of a +// search provider. +class SearchResultRanker { + public: + explicit SearchResultRanker(Profile* profile); + ~SearchResultRanker(); + + // Queries each model contained with the SearchResultRanker for its results, + // and saves them for use on subsequent calls to Rank(). + void FetchRankings(); + + // Modifies the scores of |results| using the saved rankings. This should be + // called after rankings have been queried with a call to FetchRankings(). + // Only the scores of elements in |results| are modified, not the + // ChromeSearchResults themselves. + void Rank(Mixer::SortedResults& results); + + // Forwards the given training signal to the relevant models contained within + // the SearchResultRanker. |id| is the string ID of an item that is launched + // from the launcher, eg. an app ID or a filepath, and is derived from the + // relevant ChromeSearchResult's ID. + void Train(const std::string& id, RankingItemType type); + + private: + // Records the time of the last call to FetchRankings() and is used to + // limit the number of queries to the models within a short timespan. + base::Time time_of_last_fetch_; + + // How much the scores produced by |results_list_group_ranker_| affect the + // final scores. Controlled by Finch. + float results_list_boost_coefficient_ = 0.0f; + + // Stores the scores produced by |results_list_group_ranker_|. + base::flat_map<std::string, float> group_ranks_; + + // A model that ranks groups (eg. 'file' and 'omnibox'), which is used to + // tweak the results shown in the search results list only. This does not + // affect apps. + std::unique_ptr<RecurrenceRanker> results_list_group_ranker_; + + // TODO(931149): Move the AppSearchResultRanker instance and associated logic + // to here. +}; + +} // namespace app_list + +#endif // CHROME_BROWSER_UI_APP_LIST_SEARCH_SEARCH_RESULT_RANKER_SEARCH_RESULT_RANKER_H_
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker_unittest.cc b/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker_unittest.cc new file mode 100644 index 0000000..e21c3fa --- /dev/null +++ b/chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker_unittest.cc
@@ -0,0 +1,168 @@ +// 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 "chrome/browser/ui/app_list/search/search_result_ranker/search_result_ranker.h" + +#include <stddef.h> + +#include <memory> +#include <string> +#include <vector> + +#include "ash/public/cpp/app_list/app_list_features.h" +#include "ash/public/cpp/app_list/app_list_types.h" +#include "base/files/scoped_temp_dir.h" +#include "base/stl_util.h" +#include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_feature_list.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/app_list/search/chrome_search_result.h" +#include "chrome/browser/ui/app_list/search/mixer.h" +#include "chrome/browser/ui/app_list/search/search_result_ranker/ranking_item_util.h" +#include "chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker.h" +#include "chrome/test/base/testing_profile.h" +#include "content/public/test/test_browser_thread_bundle.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace app_list { +namespace test { +namespace { + +using ResultType = ash::SearchResultType; + +using base::ScopedTempDir; +using base::test::ScopedFeatureList; +using testing::ElementsAre; +using testing::WhenSorted; + +class TestSearchResult : public ChromeSearchResult { + public: + TestSearchResult(const std::string& id, ResultType type) + : instance_id_(instantiation_count++) { + set_id(id); + SetTitle(base::UTF8ToUTF16(id)); + SetResultType(type); + } + ~TestSearchResult() override {} + + // ChromeSearchResult overrides: + void Open(int event_flags) override {} + void InvokeAction(int action_index, int event_flags) override {} + SearchResultType GetSearchResultType() const override { + return app_list::SEARCH_RESULT_TYPE_BOUNDARY; + } + + private: + static int instantiation_count; + + int instance_id_; + + DISALLOW_COPY_AND_ASSIGN(TestSearchResult); +}; +int TestSearchResult::instantiation_count = 0; + +MATCHER_P(HasId, id, "") { + return base::UTF16ToUTF8(arg.result->title()) == id; +} + +} // namespace + +class SearchResultRankerTest : public testing::Test { + public: + SearchResultRankerTest() + : thread_bundle_( + base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME) {} + ~SearchResultRankerTest() override {} + + // testing::Test overrides: + void SetUp() override { + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + TestingProfile::Builder profile_builder; + profile_builder.SetProfileName("testuser@gmail.com"); + profile_builder.SetPath(temp_dir_.GetPath().AppendASCII("TestProfile")); + profile_ = profile_builder.Build(); + } + + std::unique_ptr<SearchResultRanker> MakeRanker( + bool use_group_ranker, + const std::map<std::string, std::string>& params = {}) { + if (use_group_ranker) { + scoped_feature_list_.InitAndEnableFeatureWithParameters( + app_list_features::kEnableAdaptiveResultRanker, params); + } else { + scoped_feature_list_.InitWithFeatures( + {}, {app_list_features::kEnableAdaptiveResultRanker}); + } + + auto ranker = std::make_unique<SearchResultRanker>(profile_.get()); + Wait(); + return ranker; + } + + Mixer::SortedResults MakeSearchResults(const std::vector<std::string>& ids, + const std::vector<ResultType>& types, + const std::vector<double> scores) { + Mixer::SortedResults results; + for (int i = 0; i < static_cast<int>(ids.size()); ++i) { + test_search_results_.emplace_back(ids[i], types[i]); + results.emplace_back(&test_search_results_.back(), scores[i]); + } + return results; + } + + void Wait() { thread_bundle_.RunUntilIdle(); } + + private: + // This is used only to make the ownership clear for the TestSearchResult + // objects that the return value of MakeSearchResults() contains raw pointers + // to. + std::list<TestSearchResult> test_search_results_; + + content::TestBrowserThreadBundle thread_bundle_; + ScopedFeatureList scoped_feature_list_; + ScopedTempDir temp_dir_; + + std::unique_ptr<Profile> profile_; + + DISALLOW_COPY_AND_ASSIGN(SearchResultRankerTest); +}; + +TEST_F(SearchResultRankerTest, GroupRankerIsDisabledWithFlag) { + auto ranker = MakeRanker(false); + for (int i = 0; i < 20; ++i) + ranker->Train("unused", RankingItemType::kFile); + ranker->FetchRankings(); + + auto results = + MakeSearchResults({"A", "B", "C", "D"}, + {ResultType::kOmnibox, ResultType::kOmnibox, + ResultType::kLauncher, ResultType::kLauncher}, + {0.6f, 0.5f, 0.4f, 0.3f}); + + // Despite training, we expect the scores not to have changed. + ranker->Rank(results); + EXPECT_THAT(results, WhenSorted(ElementsAre(HasId("A"), HasId("B"), + HasId("C"), HasId("D")))); +} + +TEST_F(SearchResultRankerTest, GroupRankerImprovesScores) { + auto ranker = MakeRanker(true, {{"boost_coefficient", "1.0"}}); + for (int i = 0; i < 20; ++i) + ranker->Train("unused", RankingItemType::kFile); + ranker->FetchRankings(); + + auto results = + MakeSearchResults({"A", "B", "C", "D"}, + {ResultType::kOmnibox, ResultType::kOmnibox, + ResultType::kLauncher, ResultType::kLauncher}, + {0.5f, 0.6f, 0.45f, 0.46f}); + + ranker->Rank(results); + EXPECT_THAT(results, WhenSorted(ElementsAre(HasId("D"), HasId("C"), + HasId("B"), HasId("A")))); +} + +} // namespace test +} // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/tests/mixer_unittest.cc b/chrome/browser/ui/app_list/search/tests/mixer_unittest.cc index 0774b89..5066962 100644 --- a/chrome/browser/ui/app_list/search/tests/mixer_unittest.cc +++ b/chrome/browser/ui/app_list/search/tests/mixer_unittest.cc
@@ -11,7 +11,6 @@ #include <vector> #include "ash/public/cpp/app_list/app_list_config.h" -#include "ash/public/cpp/app_list/app_list_features.h" #include "ash/public/cpp/app_list/app_list_metrics.h" #include "ash/public/cpp/app_list/app_list_types.h" #include "base/files/scoped_temp_dir.h" @@ -23,8 +22,6 @@ #include "base/test/scoped_task_environment.h" #include "chrome/browser/ui/app_list/search/chrome_search_result.h" #include "chrome/browser/ui/app_list/search/search_provider.h" -#include "chrome/browser/ui/app_list/search/search_result_ranker/ranking_item_util.h" -#include "chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker.h" #include "chrome/browser/ui/app_list/test/fake_app_list_model_updater.h" #include "testing/gtest/include/gtest/gtest.h" @@ -40,8 +37,6 @@ const size_t kMaxOmniboxResults = 4; const size_t kMaxWebstoreResults = 2; -const bool kEphemeralUser = false; - class TestSearchResult : public ChromeSearchResult { public: TestSearchResult(const std::string& id, double relevance) @@ -144,38 +139,9 @@ "webstore", ResultType::kWebStoreApp)); } - void CreateMixer(bool use_adaptive_ranker, - const std::map<std::string, std::string>& params = {}) { - if (use_adaptive_ranker) { - scoped_feature_list_.InitAndEnableFeatureWithParameters( - app_list_features::kEnableAdaptiveResultRanker, params); - } else { - scoped_feature_list_.InitWithFeatures( - {}, {app_list_features::kEnableAdaptiveResultRanker}); - } - + void CreateMixer() { mixer_ = std::make_unique<Mixer>(model_updater_.get()); - if (use_adaptive_ranker) { - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - - RecurrenceRankerConfigProto ranker_config; - ranker_config.set_min_seconds_between_saves(240u); - auto* predictor = ranker_config.mutable_zero_state_frecency_predictor(); - predictor->set_target_limit(200u); - predictor->set_decay_coeff(0.8f); - auto* fallback = ranker_config.mutable_fallback_predictor(); - fallback->set_target_limit(200u); - fallback->set_decay_coeff(0.8f); - - std::unique_ptr<RecurrenceRanker> ranker = - std::make_unique<RecurrenceRanker>( - temp_dir_.GetPath().AppendASCII("ranker_model.proto"), - ranker_config, kEphemeralUser); - Wait(); - mixer_->SetRecurrenceRanker(std::move(ranker)); - } - // TODO(warx): when fullscreen app list is default enabled, modify this test // to test answer card/apps group having relevance boost. size_t apps_group_id = mixer_->AddGroup(kMaxAppsGroupResults, 1.0, 0.0); @@ -209,10 +175,6 @@ return result; } - void Train(const std::string& id, const RankingItemType& type) { - mixer_->Train(id, type); - } - void Wait() { scoped_task_environment_.RunUntilIdle(); } Mixer* mixer() { return mixer_.get(); } @@ -234,8 +196,7 @@ }; TEST_F(MixerTest, Basic) { - // Create mixer without adaptive ranker. - CreateMixer(false); + CreateMixer(); // Note: Some cases in |expected| have vastly more results than others, due to // the "at least 6" mechanism. If it gets at least 6 results from all @@ -288,8 +249,7 @@ } TEST_F(MixerTest, RemoveDuplicates) { - // Create mixer without adaptive ranker. - CreateMixer(false); + CreateMixer(); const std::string dup = "dup"; @@ -311,40 +271,5 @@ EXPECT_EQ("dup0,dup1,dup2", GetResults()); } -TEST_F(MixerTest, RankerIsDisabledWithFlag) { - CreateMixer(false); - - for (int i = 0; i < 20; ++i) - Train("omnibox2", RankingItemType::kOmniboxGeneric); - - app_provider()->set_count(4); - app_provider()->set_small_relevance_range(); - omnibox_provider()->set_count(4); - omnibox_provider()->set_small_relevance_range(); - RunQuery(); - - // Expect training calls to have not affected rankings. - EXPECT_EQ(GetResults(), - "app0,omnibox0,app1,omnibox1,app2,omnibox2,app3,omnibox3"); -} - -TEST_F(MixerTest, RankerImprovesScores) { - CreateMixer(true, {{"boost_coefficient", "10.0"}}); - - for (int i = 0; i < 20; ++i) - Train("omnibox2", RankingItemType::kOmniboxGeneric); - - app_provider()->set_count(4); - app_provider()->set_small_relevance_range(); - omnibox_provider()->set_count(4); - omnibox_provider()->set_small_relevance_range(); - RunQuery(); - - // Omnibox results exist in the ranker and should be up-weighted to the top of - // the list. - EXPECT_EQ(GetResults(), - "omnibox0,omnibox1,omnibox2,omnibox3,app0,app1,app2,app3"); -} - } // namespace test } // namespace app_list
diff --git a/chrome/browser/ui/ash/DEPS b/chrome/browser/ui/ash/DEPS index 416ca5c..469b29fc 100644 --- a/chrome/browser/ui/ash/DEPS +++ b/chrome/browser/ui/ash/DEPS
@@ -10,6 +10,7 @@ "!ash", "+ash/components/shortcut_viewer", "+ash/public", + "+ash/shelf/shelf_constants.h", ], # AshShellInit supports classic (non-mash) mode so allow ash/ includes. "ash_shell_init\.cc": [
diff --git a/chrome/browser/ui/ash/launcher_drag_interactive_uitest.cc b/chrome/browser/ui/ash/launcher_drag_interactive_uitest.cc index d669b3c4..bd0b91d 100644 --- a/chrome/browser/ui/ash/launcher_drag_interactive_uitest.cc +++ b/chrome/browser/ui/ash/launcher_drag_interactive_uitest.cc
@@ -4,6 +4,7 @@ #include "ash/public/cpp/app_list/app_list_config.h" #include "ash/public/interfaces/app_list_view.mojom.h" +#include "ash/shelf/shelf_constants.h" #include "base/macros.h" #include "base/run_loop.h" #include "base/strings/stringprintf.h" @@ -64,9 +65,9 @@ ash::mojom::AppListViewState::kFullscreenAllApps, waiter.QuitClosure()); gfx::Rect display_bounds = GetDisplayBounds(browser_window); - // TODO(oshima): Use shelf constants. gfx::Point start_point = - gfx::Point(display_bounds.width() / 4, display_bounds.bottom() - 28); + gfx::Point(display_bounds.width() / 4, + display_bounds.bottom() - ash::kShelfSize / 2); gfx::Point end_point(start_point); end_point.set_y(10); ui_test_utils::DragEventGenerator generator( @@ -102,8 +103,7 @@ gfx::Rect display_bounds = GetDisplayBounds(browser_window); gfx::Point start_point = gfx::Point(display_bounds.width() / 4, 10); gfx::Point end_point(start_point); - // TODO(oshima): Use shelf_constants. - end_point.set_y(display_bounds.bottom() - 56); + end_point.set_y(display_bounds.bottom() - ash::kShelfSize / 2); ui_test_utils::DragEventGenerator generator( std::make_unique<ui_test_utils::InterporateProducer>( start_point, end_point, base::TimeDelta::FromMilliseconds(1000)),
diff --git a/chrome/browser/ui/views/payments/payment_handler_change_payment_method_browsertest.cc b/chrome/browser/ui/views/payments/payment_handler_change_payment_method_browsertest.cc new file mode 100644 index 0000000..88dc32f4 --- /dev/null +++ b/chrome/browser/ui/views/payments/payment_handler_change_payment_method_browsertest.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 <string> +#include <utility> + +#include "base/strings/utf_string_conversions.h" +#include "chrome/browser/ui/views/payments/payment_request_browsertest_base.h" +#include "content/public/test/browser_test_utils.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/re2/src/re2/re2.h" +#include "url/gurl.h" + +namespace payments { +namespace { + +// Looks for the "supportedMethods" URL and removes its port number. +std::string ClearPortNumber(const std::string& may_contain_method_url) { + std::string before; + std::string method; + std::string after; + GURL::Replacements port; + port.ClearPort(); + return re2::RE2::FullMatch( + may_contain_method_url, + "(.*\"supportedMethods\":\")(https://.*)(\",\"total\".*)", &before, + &method, &after) + ? before + GURL(method).ReplaceComponents(port).spec() + after + : may_contain_method_url; +} + +class PaymentHandlerChangePaymentMethodTest + : public PaymentRequestBrowserTestBase, + public testing::WithParamInterface<std::pair<std::string, std::string>> { + protected: + PaymentHandlerChangePaymentMethodTest() {} + ~PaymentHandlerChangePaymentMethodTest() override {} + + private: + DISALLOW_COPY_AND_ASSIGN(PaymentHandlerChangePaymentMethodTest); +}; + +IN_PROC_BROWSER_TEST_P(PaymentHandlerChangePaymentMethodTest, Test) { + NavigateTo("/change_payment_method.html"); + std::string actual_output; + ASSERT_TRUE(content::ExecuteScriptAndExtractString( + GetActiveWebContents(), "install();", &actual_output)); + ASSERT_EQ(actual_output, "instruments.set(): Payment handler installed."); + + ASSERT_TRUE(content::ExecuteScriptAndExtractString( + GetActiveWebContents(), GetParam().first, &actual_output)); + + // The test expectations are hard-coded, but the embedded test server changes + // its port number in every test, e.g., https://a.com:34548. + ASSERT_EQ(ClearPortNumber(actual_output), GetParam().second) + << "When executing " << GetParam().first; +} + +INSTANTIATE_TEST_SUITE_P( + Tests, + PaymentHandlerChangePaymentMethodTest, + testing::Values( + std::make_pair( + "testNoHandler();", + "PaymentRequest.show(): changePaymentMethod() returned: null"), + std::make_pair("testReject()", + "PaymentRequest.show() rejected with: Error for test"), + std::make_pair( + "testThrow()", + "PaymentRequest.show() rejected with: Error: Error for test"), + std::make_pair( + "testDetails()", + "PaymentRequest.show(): changePaymentMethod() returned: " + "{\"error\":\"Error for test\"," + "\"modifiers\":[{\"data\":{\"soup\":\"potato\"}," + "\"supportedMethods\":\"https://a.com/\"," + "\"total\":{\"amount\":{\"currency\":\"EUR\",\"value\":\"0.03\"}," + "\"label\":\"\",\"pending\":false}}]," + "\"paymentMethodErrors\":{\"country\":\"Unsupported country\"}," + "\"total\":{\"currency\":\"GBP\",\"value\":\"0.02\"}}"))); + +} // namespace +} // namespace payments
diff --git a/chrome/browser/ui/webui/app_management/app_management_page_handler.cc b/chrome/browser/ui/webui/app_management/app_management_page_handler.cc index e5f72e98..c400e23 100644 --- a/chrome/browser/ui/webui/app_management/app_management_page_handler.cc +++ b/chrome/browser/ui/webui/app_management/app_management_page_handler.cc
@@ -201,16 +201,18 @@ } void AppManagementPageHandler::OnAppUpdate(const apps::AppUpdate& update) { + if (update.ReadinessChanged() && + update.Readiness() == apps::mojom::Readiness::kUninstalledByUser) { + page_->OnAppRemoved(update.AppId()); + return; + } + if (update.ShowInManagement() != apps::mojom::OptionalBool::kTrue) { return; } if (update.ReadinessChanged() && - update.Readiness() == apps::mojom::Readiness::kUninstalledByUser) { - page_->OnAppRemoved(update.AppId()); - - } else if (update.ReadinessChanged() && - update.Readiness() == apps::mojom::Readiness::kReady) { + update.Readiness() == apps::mojom::Readiness::kReady) { page_->OnAppAdded(CreateUIAppPtr(update)); } else { page_->OnAppChanged(CreateUIAppPtr(update));
diff --git a/chrome/browser/ui/webui/chromeos/network_element_localized_strings_provider.cc b/chrome/browser/ui/webui/chromeos/network_element_localized_strings_provider.cc index 6013fe4..e006b48 100644 --- a/chrome/browser/ui/webui/chromeos/network_element_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/chromeos/network_element_localized_strings_provider.cc
@@ -15,6 +15,7 @@ #include "components/login/localized_values_builder.h" #include "content/public/browser/web_ui_data_source.h" #include "third_party/cros_system_api/dbus/service_constants.h" +#include "ui/base/l10n/l10n_util.h" namespace chromeos { namespace network_element { @@ -263,6 +264,8 @@ {"networkConfigSaveCredentials", IDS_SETTINGS_INTERNET_CONFIG_SAVE_CREDENTIALS}, {"networkConfigShare", IDS_SETTINGS_INTERNET_CONFIG_SHARE}, + {"networkAutoConnect", IDS_SETTINGS_INTERNET_NETWORK_AUTO_CONNECT}, + {"hiddenNetworkWarning", IDS_SETTINGS_HIDDEN_NETWORK_WARNING}, {"hidePassword", IDS_SETTINGS_PASSWORD_HIDE}, {"showPassword", IDS_SETTINGS_PASSWORD_SHOW}, };
diff --git a/chrome/browser/ui/webui/sync_internals_message_handler.cc b/chrome/browser/ui/webui/sync_internals_message_handler.cc index dbcae7e4..4b2ed4b 100644 --- a/chrome/browser/ui/webui/sync_internals_message_handler.cc +++ b/chrome/browser/ui/webui/sync_internals_message_handler.cc
@@ -26,7 +26,7 @@ #include "components/sync/engine/events/protocol_event.h" #include "components/sync/js/js_event_details.h" #include "components/sync/protocol/sync.pb.h" -#include "components/sync/user_events/user_event_service.h" +#include "components/sync_user_events/user_event_service.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/web_ui.h"
diff --git a/chrome/browser/ui/webui/sync_internals_message_handler_unittest.cc b/chrome/browser/ui/webui/sync_internals_message_handler_unittest.cc index 86df2a38..0e69a9c 100644 --- a/chrome/browser/ui/webui/sync_internals_message_handler_unittest.cc +++ b/chrome/browser/ui/webui/sync_internals_message_handler_unittest.cc
@@ -17,7 +17,7 @@ #include "components/sync/driver/fake_sync_service.h" #include "components/sync/driver/sync_service.h" #include "components/sync/js/js_test_util.h" -#include "components/sync/user_events/fake_user_event_service.h" +#include "components/sync_user_events/fake_user_event_service.h" #include "content/public/browser/site_instance.h" #include "content/public/browser/web_contents.h" #include "content/public/test/test_web_ui.h"
diff --git a/chrome/browser/web_applications/bookmark_apps/policy/web_app_policy_manager_unittest.cc b/chrome/browser/web_applications/bookmark_apps/policy/web_app_policy_manager_unittest.cc index f848710..e76b6979 100644 --- a/chrome/browser/web_applications/bookmark_apps/policy/web_app_policy_manager_unittest.cc +++ b/chrome/browser/web_applications/bookmark_apps/policy/web_app_policy_manager_unittest.cc
@@ -12,12 +12,12 @@ #include "base/values.h" #include "chrome/browser/prefs/browser_prefs.h" #include "chrome/browser/web_applications/bookmark_apps/test_web_app_provider.h" +#include "chrome/browser/web_applications/components/externally_installed_web_app_prefs.h" #include "chrome/browser/web_applications/components/install_options.h" #include "chrome/browser/web_applications/components/pending_app_manager.h" #include "chrome/browser/web_applications/components/policy/web_app_policy_constants.h" #include "chrome/browser/web_applications/components/test_pending_app_manager.h" #include "chrome/browser/web_applications/components/web_app_constants.h" -#include "chrome/browser/web_applications/extensions/web_app_extension_ids_map.h" #include "chrome/browser/web_applications/web_app_provider.h" #include "chrome/common/pref_names.h" #include "chrome/test/base/chrome_render_view_host_test_harness.h" @@ -191,8 +191,9 @@ extensions::ExtensionRegistry::Get(profile())->AddEnabled( extensions::ExtensionBuilder("Dummy Name").SetID(id).Build()); - ExtensionIdsMap extension_ids_map(profile()->GetPrefs()); - extension_ids_map.Insert(url, id, install_source); + ExternallyInstalledWebAppPrefs externally_installed_app_prefs( + profile()->GetPrefs()); + externally_installed_app_prefs.Insert(url, id, install_source); pending_app_manager()->SimulatePreviouslyInstalledApp(url, install_source); }
diff --git a/chrome/browser/web_applications/bookmark_apps/system_web_app_manager_unittest.cc b/chrome/browser/web_applications/bookmark_apps/system_web_app_manager_unittest.cc index 69e6055..a42dcca 100644 --- a/chrome/browser/web_applications/bookmark_apps/system_web_app_manager_unittest.cc +++ b/chrome/browser/web_applications/bookmark_apps/system_web_app_manager_unittest.cc
@@ -13,10 +13,10 @@ #include "base/values.h" #include "chrome/browser/prefs/browser_prefs.h" #include "chrome/browser/web_applications/bookmark_apps/test_web_app_provider.h" +#include "chrome/browser/web_applications/components/externally_installed_web_app_prefs.h" #include "chrome/browser/web_applications/components/pending_app_manager.h" #include "chrome/browser/web_applications/components/test_pending_app_manager.h" #include "chrome/browser/web_applications/components/web_app_constants.h" -#include "chrome/browser/web_applications/extensions/web_app_extension_ids_map.h" #include "chrome/browser/web_applications/test/test_system_web_app_manager.h" #include "chrome/browser/web_applications/web_app_provider.h" #include "chrome/common/chrome_features.h" @@ -85,8 +85,8 @@ extensions::ExtensionRegistry::Get(profile())->AddEnabled( extensions::ExtensionBuilder("Dummy Name").SetID(id).Build()); - ExtensionIdsMap extension_ids_map(profile()->GetPrefs()); - extension_ids_map.Insert(url, id, install_source); + ExternallyInstalledWebAppPrefs(profile()->GetPrefs()) + .Insert(url, id, install_source); pending_app_manager()->SimulatePreviouslyInstalledApp(url, install_source); }
diff --git a/chrome/browser/web_applications/components/BUILD.gn b/chrome/browser/web_applications/components/BUILD.gn index 38d573d..0c61a80 100644 --- a/chrome/browser/web_applications/components/BUILD.gn +++ b/chrome/browser/web_applications/components/BUILD.gn
@@ -7,6 +7,8 @@ "app_registrar.cc", "app_registrar.h", "app_registrar_observer.h", + "externally_installed_web_app_prefs.cc", + "externally_installed_web_app_prefs.h", "install_finalizer.h", "install_manager.cc", "install_manager.h",
diff --git a/chrome/browser/web_applications/extensions/web_app_extension_ids_map.cc b/chrome/browser/web_applications/components/externally_installed_web_app_prefs.cc similarity index 75% rename from chrome/browser/web_applications/extensions/web_app_extension_ids_map.cc rename to chrome/browser/web_applications/components/externally_installed_web_app_prefs.cc index 10d5f96..a84b99d 100644 --- a/chrome/browser/web_applications/extensions/web_app_extension_ids_map.cc +++ b/chrome/browser/web_applications/components/externally_installed_web_app_prefs.cc
@@ -1,8 +1,8 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. +// 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 "chrome/browser/web_applications/extensions/web_app_extension_ids_map.h" +#include "chrome/browser/web_applications/components/externally_installed_web_app_prefs.h" #include <string> #include <utility> @@ -45,21 +45,24 @@ // Two levels in is a dictionary (key/value pairs) whose keys are URLs and // values are leaf dictionaries. Those leaf dictionaries have keys such as // kExtensionId and kInstallSource. +// The name "extension_id" comes from when PWAs were only backed by the +// Extension system rather than their own. It cannot be changed now that it +// lives persistently in users' profiles. constexpr char kExtensionId[] = "extension_id"; constexpr char kInstallSource[] = "install_source"; constexpr char kIsPlaceholder[] = "is_placeholder"; // Returns the base::Value in |pref_service| corresponding to our stored dict -// for |extension_id|, or nullptr if it doesn't exist. +// for |app_id|, or nullptr if it doesn't exist. const base::Value* GetPreferenceValue(const PrefService* pref_service, - const std::string& extension_id) { + const AppId& app_id) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); const base::DictionaryValue* urls_to_dicts = pref_service->GetDictionary(prefs::kWebAppsExtensionIDs); if (!urls_to_dicts) { return nullptr; } - // Do a simple O(N) scan for extension_id being a value in each dictionary's + // Do a simple O(N) scan for app_id being a value in each dictionary's // key/value pairs. We expect both N and the number of times // GetPreferenceValue is called to be relatively small in practice. If they // turn out to be large, we can write a more sophisticated implementation. @@ -68,7 +71,7 @@ const base::Value* v = root; if (v->is_dict()) { v = v->FindKey(kExtensionId); - if (v && v->is_string() && (v->GetString() == extension_id)) { + if (v && v->is_string() && (v->GetString() == app_id)) { return root; } } @@ -79,24 +82,24 @@ } // namespace // static -void ExtensionIdsMap::RegisterProfilePrefs( +void ExternallyInstalledWebAppPrefs::RegisterProfilePrefs( user_prefs::PrefRegistrySyncable* registry) { registry->RegisterDictionaryPref(prefs::kWebAppsExtensionIDs); } // static -bool ExtensionIdsMap::HasExtensionId(const PrefService* pref_service, - const std::string& extension_id) { - return GetPreferenceValue(pref_service, extension_id) != nullptr; +bool ExternallyInstalledWebAppPrefs::HasAppId(const PrefService* pref_service, + const AppId& app_id) { + return GetPreferenceValue(pref_service, app_id) != nullptr; } // static -bool ExtensionIdsMap::HasExtensionIdWithInstallSource( +bool ExternallyInstalledWebAppPrefs::HasAppIdWithInstallSource( const PrefService* pref_service, - const std::string& extension_id, + const AppId& app_id, InstallSource install_source) { - const base::Value* v = GetPreferenceValue(pref_service, extension_id); + const base::Value* v = GetPreferenceValue(pref_service, app_id); if (v == nullptr || !v->is_dict()) return false; @@ -105,7 +108,7 @@ } // static -std::vector<GURL> ExtensionIdsMap::GetInstalledAppUrls( +std::vector<GURL> ExternallyInstalledWebAppPrefs::GetInstalledAppUrls( Profile* profile, InstallSource install_source) { const base::DictionaryValue* urls_to_dicts = @@ -147,23 +150,24 @@ return installed_app_urls; } -ExtensionIdsMap::ExtensionIdsMap(PrefService* pref_service) +ExternallyInstalledWebAppPrefs::ExternallyInstalledWebAppPrefs( + PrefService* pref_service) : pref_service_(pref_service) {} -void ExtensionIdsMap::Insert(const GURL& url, - const std::string& extension_id, - InstallSource install_source) { +void ExternallyInstalledWebAppPrefs::Insert(const GURL& url, + const AppId& app_id, + InstallSource install_source) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); base::Value dict(base::Value::Type::DICTIONARY); - dict.SetKey(kExtensionId, base::Value(extension_id)); + dict.SetKey(kExtensionId, base::Value(app_id)); dict.SetKey(kInstallSource, base::Value(static_cast<int>(install_source))); DictionaryPrefUpdate update(pref_service_, prefs::kWebAppsExtensionIDs); update->SetKey(url.spec(), std::move(dict)); } -base::Optional<std::string> ExtensionIdsMap::LookupExtensionId( +base::Optional<AppId> ExternallyInstalledWebAppPrefs::LookupAppId( const GURL& url) const { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); @@ -179,7 +183,7 @@ return base::nullopt; } -base::Optional<std::string> ExtensionIdsMap::LookupPlaceholderAppId( +base::Optional<AppId> ExternallyInstalledWebAppPrefs::LookupPlaceholderAppId( const GURL& url) const { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); @@ -196,7 +200,8 @@ return *entry->FindStringKey(kExtensionId); } -void ExtensionIdsMap::SetIsPlaceholder(const GURL& url, bool is_placeholder) { +void ExternallyInstalledWebAppPrefs::SetIsPlaceholder(const GURL& url, + bool is_placeholder) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK(pref_service_->GetDictionary(prefs::kWebAppsExtensionIDs)
diff --git a/chrome/browser/web_applications/components/externally_installed_web_app_prefs.h b/chrome/browser/web_applications/components/externally_installed_web_app_prefs.h new file mode 100644 index 0000000..8462b6b --- /dev/null +++ b/chrome/browser/web_applications/components/externally_installed_web_app_prefs.h
@@ -0,0 +1,67 @@ +// 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 CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_EXTERNALLY_INSTALLED_WEB_APP_PREFS_H_ +#define CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_EXTERNALLY_INSTALLED_WEB_APP_PREFS_H_ + +#include <string> +#include <vector> + +#include "base/macros.h" +#include "base/optional.h" +#include "chrome/browser/web_applications/components/pending_app_manager.h" + +class GURL; +class PrefService; +class Profile; + +namespace user_prefs { +class PrefRegistrySyncable; +} + +namespace web_app { + +// A Prefs-backed map from web app URLs to app IDs and their InstallSources. +// +// This lets us determine, given a web app's URL, whether that web app was +// already installed by a non-user external source e.g. policy or Chrome default +// and system apps. +class ExternallyInstalledWebAppPrefs { + public: + static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); + + static bool HasAppId(const PrefService* pref_service, const AppId& app_id); + + // Returns true if |app_id| was added with |install_source| to + // |pref_service|. + static bool HasAppIdWithInstallSource(const PrefService* pref_service, + const AppId& app_id, + InstallSource install_source); + + // Returns the URLs of the apps that were installed from |install_source|. + static std::vector<GURL> GetInstalledAppUrls(Profile* profile, + InstallSource install_source); + + explicit ExternallyInstalledWebAppPrefs(PrefService* pref_service); + + void Insert(const GURL& url, + const AppId& app_id, + InstallSource install_source); + base::Optional<AppId> LookupAppId(const GURL& url) const; + + // Returns an id if there is a placeholder app for |url|. Note that nullopt + // does not mean that there is no app for |url| just that there is no + // *placeholder app*. + base::Optional<AppId> LookupPlaceholderAppId(const GURL& url) const; + void SetIsPlaceholder(const GURL& url, bool is_placeholder); + + private: + PrefService* pref_service_; + + DISALLOW_COPY_AND_ASSIGN(ExternallyInstalledWebAppPrefs); +}; + +} // namespace web_app + +#endif // CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_EXTERNALLY_INSTALLED_WEB_APP_PREFS_H_
diff --git a/chrome/browser/web_applications/extensions/BUILD.gn b/chrome/browser/web_applications/extensions/BUILD.gn index b523871..d457655 100644 --- a/chrome/browser/web_applications/extensions/BUILD.gn +++ b/chrome/browser/web_applications/extensions/BUILD.gn
@@ -22,8 +22,6 @@ "bookmark_app_util.h", "pending_bookmark_app_manager.cc", "pending_bookmark_app_manager.h", - "web_app_extension_ids_map.cc", - "web_app_extension_ids_map.h", "web_app_extension_shortcut.cc", "web_app_extension_shortcut.h", "web_app_extension_shortcut_mac.h", @@ -50,9 +48,9 @@ "bookmark_app_installation_task_unittest.cc", "bookmark_app_uninstaller_unittest.cc", "bookmark_app_util_unittest.cc", + "externally_installed_web_app_prefs_unittest.cc", "install_manager_bookmark_app_unittest.cc", "pending_bookmark_app_manager_unittest.cc", - "web_app_extension_ids_map_unittest.cc", ] deps = [
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_installation_task.cc b/chrome/browser/web_applications/extensions/bookmark_app_installation_task.cc index 310f726..6cd9a4d 100644 --- a/chrome/browser/web_applications/extensions/bookmark_app_installation_task.cc +++ b/chrome/browser/web_applications/extensions/bookmark_app_installation_task.cc
@@ -48,7 +48,7 @@ web_app::InstallOptions install_options) : profile_(profile), install_finalizer_(install_finalizer), - extension_ids_map_(profile_->GetPrefs()), + externally_installed_app_prefs_(profile_->GetPrefs()), install_options_(std::move(install_options)) {} BookmarkAppInstallationTask::~BookmarkAppInstallationTask() = default; @@ -106,9 +106,10 @@ return; } - extension_ids_map_.Insert(install_options_.url, app_id, - install_options_.install_source); - extension_ids_map_.SetIsPlaceholder(install_options_.url, is_placeholder); + externally_installed_app_prefs_.Insert(install_options_.url, app_id, + install_options_.install_source); + externally_installed_app_prefs_.SetIsPlaceholder(install_options_.url, + is_placeholder); auto success_closure = base::BindOnce(std::move(result_callback),
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_installation_task.h b/chrome/browser/web_applications/extensions/bookmark_app_installation_task.h index b67fa476..0dd8c2e 100644 --- a/chrome/browser/web_applications/extensions/bookmark_app_installation_task.h +++ b/chrome/browser/web_applications/extensions/bookmark_app_installation_task.h
@@ -11,9 +11,9 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/optional.h" +#include "chrome/browser/web_applications/components/externally_installed_web_app_prefs.h" #include "chrome/browser/web_applications/components/install_options.h" #include "chrome/browser/web_applications/components/web_app_helpers.h" -#include "chrome/browser/web_applications/extensions/web_app_extension_ids_map.h" class Profile; @@ -78,7 +78,7 @@ Profile* profile_; web_app::InstallFinalizer* install_finalizer_; - web_app::ExtensionIdsMap extension_ids_map_; + web_app::ExternallyInstalledWebAppPrefs externally_installed_app_prefs_; const web_app::InstallOptions install_options_;
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_installation_task_unittest.cc b/chrome/browser/web_applications/extensions/bookmark_app_installation_task_unittest.cc index 755fd14..e0213b7 100644 --- a/chrome/browser/web_applications/extensions/bookmark_app_installation_task_unittest.cc +++ b/chrome/browser/web_applications/extensions/bookmark_app_installation_task_unittest.cc
@@ -24,10 +24,10 @@ #include "chrome/browser/extensions/test_extension_system.h" #include "chrome/browser/installable/installable_data.h" #include "chrome/browser/web_applications/bookmark_apps/bookmark_app_install_manager.h" +#include "chrome/browser/web_applications/components/externally_installed_web_app_prefs.h" #include "chrome/browser/web_applications/components/web_app_constants.h" #include "chrome/browser/web_applications/components/web_app_data_retriever.h" #include "chrome/browser/web_applications/components/web_app_provider_base.h" -#include "chrome/browser/web_applications/extensions/web_app_extension_ids_map.h" #include "chrome/browser/web_applications/test/test_data_retriever.h" #include "chrome/browser/web_applications/test/test_install_finalizer.h" #include "chrome/common/pref_names.h" @@ -52,8 +52,8 @@ const char kWebAppTitle[] = "Foo Title"; const GURL kWebAppUrl("https://foo.example"); -// TODO(ortuno): Move this to ExtensionIdsMap or replace with a method -// in ExtensionIdsMap once there is one. +// TODO(ortuno): Move this to ExternallyInstalledWebAppPrefs or replace with a +// method in ExternallyInstalledWebAppPrefs once there is one. bool IsPlaceholderApp(Profile* profile, const GURL& url) { const base::Value* map = profile->GetPrefs()->GetDictionary(prefs::kWebAppsExtensionIDs); @@ -192,9 +192,9 @@ web_contents(), base::BindLambdaForTesting( [&](BookmarkAppInstallationTask::Result result) { - base::Optional<std::string> id = - web_app::ExtensionIdsMap(profile()->GetPrefs()) - .LookupExtensionId(kWebAppUrl); + base::Optional<web_app::AppId> id = + web_app::ExternallyInstalledWebAppPrefs(profile()->GetPrefs()) + .LookupAppId(kWebAppUrl); EXPECT_EQ(web_app::InstallResultCode::kSuccess, result.code); EXPECT_TRUE(result.app_id.has_value()); @@ -231,20 +231,20 @@ web_app::InstallSource::kInternal)); bool callback_called = false; - task->Install(web_contents(), - base::BindLambdaForTesting( - [&](BookmarkAppInstallationTask::Result result) { - base::Optional<std::string> id = - web_app::ExtensionIdsMap(profile()->GetPrefs()) - .LookupExtensionId(kWebAppUrl); + task->Install( + web_contents(), + base::BindLambdaForTesting( + [&](BookmarkAppInstallationTask::Result result) { + base::Optional<web_app::AppId> id = + web_app::ExternallyInstalledWebAppPrefs(profile()->GetPrefs()) + .LookupAppId(kWebAppUrl); - EXPECT_NE(web_app::InstallResultCode::kSuccess, - result.code); - EXPECT_FALSE(result.app_id.has_value()); + EXPECT_NE(web_app::InstallResultCode::kSuccess, result.code); + EXPECT_FALSE(result.app_id.has_value()); - EXPECT_FALSE(id.has_value()); - callback_called = true; - })); + EXPECT_FALSE(id.has_value()); + callback_called = true; + })); content::RunAllTasksUntilIdle();
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_uninstaller.cc b/chrome/browser/web_applications/extensions/bookmark_app_uninstaller.cc index af20ea4..48809d6 100644 --- a/chrome/browser/web_applications/extensions/bookmark_app_uninstaller.cc +++ b/chrome/browser/web_applications/extensions/bookmark_app_uninstaller.cc
@@ -17,20 +17,20 @@ web_app::AppRegistrar* registrar) : profile_(profile), registrar_(registrar), - extension_ids_map_(profile->GetPrefs()) {} + externally_installed_app_prefs_(profile->GetPrefs()) {} BookmarkAppUninstaller::~BookmarkAppUninstaller() = default; bool BookmarkAppUninstaller::UninstallApp(const GURL& app_url) { - base::Optional<std::string> extension_id = - extension_ids_map_.LookupExtensionId(app_url); - if (!extension_id.has_value()) { + base::Optional<web_app::AppId> app_id = + externally_installed_app_prefs_.LookupAppId(app_url); + if (!app_id.has_value()) { LOG(WARNING) << "Couldn't uninstall app with url " << app_url << "; No corresponding extension for url."; return false; } - if (!registrar_->IsInstalled(extension_id.value())) { + if (!registrar_->IsInstalled(app_id.value())) { LOG(WARNING) << "Couldn't uninstall app with url " << app_url << "; Extension not installed."; return false; @@ -39,8 +39,7 @@ base::string16 error; bool uninstalled = ExtensionSystem::Get(profile_)->extension_service()->UninstallExtension( - extension_id.value(), UNINSTALL_REASON_ORPHANED_EXTERNAL_EXTENSION, - &error); + app_id.value(), UNINSTALL_REASON_ORPHANED_EXTERNAL_EXTENSION, &error); if (!uninstalled) { LOG(WARNING) << "Couldn't uninstall app with url " << app_url << ". "
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_uninstaller.h b/chrome/browser/web_applications/extensions/bookmark_app_uninstaller.h index be69df76..a114cb11 100644 --- a/chrome/browser/web_applications/extensions/bookmark_app_uninstaller.h +++ b/chrome/browser/web_applications/extensions/bookmark_app_uninstaller.h
@@ -5,7 +5,7 @@ #ifndef CHROME_BROWSER_WEB_APPLICATIONS_EXTENSIONS_BOOKMARK_APP_UNINSTALLER_H_ #define CHROME_BROWSER_WEB_APPLICATIONS_EXTENSIONS_BOOKMARK_APP_UNINSTALLER_H_ -#include "chrome/browser/web_applications/extensions/web_app_extension_ids_map.h" +#include "chrome/browser/web_applications/components/externally_installed_web_app_prefs.h" class Profile; class GURL; @@ -29,7 +29,7 @@ private: Profile* profile_; web_app::AppRegistrar* registrar_; - web_app::ExtensionIdsMap extension_ids_map_; + web_app::ExternallyInstalledWebAppPrefs externally_installed_app_prefs_; }; } // namespace extensions
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_uninstaller_unittest.cc b/chrome/browser/web_applications/extensions/bookmark_app_uninstaller_unittest.cc index 21e2861..dfa52b5 100644 --- a/chrome/browser/web_applications/extensions/bookmark_app_uninstaller_unittest.cc +++ b/chrome/browser/web_applications/extensions/bookmark_app_uninstaller_unittest.cc
@@ -83,8 +83,6 @@ std::make_unique<TestExtensionRegistryObserver>( ExtensionRegistry::Get(profile())); - extension_ids_map_ = - std::make_unique<web_app::ExtensionIdsMap>(profile()->GetPrefs()); registrar_ = std::make_unique<BookmarkAppRegistrar>(profile()); uninstaller_ = @@ -105,8 +103,8 @@ .SetID(app_id) .Build(); ExtensionRegistry::Get(profile())->AddEnabled(extension); - extension_ids_map_->Insert(app_url, app_id, - web_app::InstallSource::kExternalPolicy); + web_app::ExternallyInstalledWebAppPrefs(profile()->GetPrefs()) + .Insert(app_url, app_id, web_app::InstallSource::kExternalPolicy); return app_id; } @@ -133,7 +131,6 @@ std::unique_ptr<TestExtensionRegistryObserver> test_extension_registry_observer_; - std::unique_ptr<web_app::ExtensionIdsMap> extension_ids_map_; std::unique_ptr<BookmarkAppRegistrar> registrar_; std::unique_ptr<BookmarkAppUninstaller> uninstaller_;
diff --git a/chrome/browser/web_applications/extensions/externally_installed_web_app_prefs_unittest.cc b/chrome/browser/web_applications/extensions/externally_installed_web_app_prefs_unittest.cc new file mode 100644 index 0000000..5b92a83 --- /dev/null +++ b/chrome/browser/web_applications/extensions/externally_installed_web_app_prefs_unittest.cc
@@ -0,0 +1,171 @@ +// 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 "chrome/browser/web_applications/components/externally_installed_web_app_prefs.h" + +#include <algorithm> + +#include "chrome/browser/extensions/test_extension_system.h" +#include "chrome/browser/web_applications/components/web_app_constants.h" +#include "chrome/common/pref_names.h" +#include "chrome/test/base/chrome_render_view_host_test_harness.h" +#include "chrome/test/base/testing_profile.h" +#include "components/crx_file/id_util.h" +#include "components/prefs/scoped_user_pref_update.h" +#include "extensions/browser/extension_registry.h" +#include "extensions/common/extension_builder.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace web_app { + +using InstallSource = InstallSource; + +class ExternallyInstalledWebAppPrefsTest + : public ChromeRenderViewHostTestHarness { + public: + ExternallyInstalledWebAppPrefsTest() = default; + ~ExternallyInstalledWebAppPrefsTest() override = default; + + void SetUp() override { + ChromeRenderViewHostTestHarness::SetUp(); + // TODO(https://crbug.com/891172): Use an extension agnostic test registry. + extensions::TestExtensionSystem* test_system = + static_cast<extensions::TestExtensionSystem*>( + extensions::ExtensionSystem::Get(profile())); + test_system->CreateExtensionService(base::CommandLine::ForCurrentProcess(), + profile()->GetPath(), + false); // autoupdate_enabled + } + + std::string GenerateFakeExtensionId(GURL url) { + return crx_file::id_util::GenerateId("fake_app_id_for:" + url.spec()); + } + + void SimulatePreviouslyInstalledApp(GURL url, InstallSource install_source) { + std::string id = GenerateFakeExtensionId(url); + extensions::ExtensionRegistry::Get(profile())->AddEnabled( + extensions::ExtensionBuilder("Dummy Name").SetID(id).Build()); + + ExternallyInstalledWebAppPrefs(profile()->GetPrefs()) + .Insert(url, id, install_source); + } + + void SimulateUninstallApp(GURL url) { + std::string id = GenerateFakeExtensionId(url); + extensions::ExtensionRegistry::Get(profile())->RemoveEnabled(id); + } + + std::vector<GURL> GetInstalledAppUrls(InstallSource install_source) { + std::vector<GURL> vec = ExternallyInstalledWebAppPrefs::GetInstalledAppUrls( + profile(), install_source); + std::sort(vec.begin(), vec.end()); + return vec; + } + + private: + DISALLOW_COPY_AND_ASSIGN(ExternallyInstalledWebAppPrefsTest); +}; + +TEST_F(ExternallyInstalledWebAppPrefsTest, BasicOps) { + GURL url_a("https://a.example.com/"); + GURL url_b("https://b.example.com/"); + GURL url_c("https://c.example.com/"); + GURL url_d("https://d.example.com/"); + + std::string id_a = GenerateFakeExtensionId(url_a); + std::string id_b = GenerateFakeExtensionId(url_b); + std::string id_c = GenerateFakeExtensionId(url_c); + std::string id_d = GenerateFakeExtensionId(url_d); + + auto* prefs = profile()->GetPrefs(); + ExternallyInstalledWebAppPrefs map(prefs); + + // Start with an empty map. + + EXPECT_EQ("missing", map.LookupAppId(url_a).value_or("missing")); + EXPECT_EQ("missing", map.LookupAppId(url_b).value_or("missing")); + EXPECT_EQ("missing", map.LookupAppId(url_c).value_or("missing")); + EXPECT_EQ("missing", map.LookupAppId(url_d).value_or("missing")); + + EXPECT_FALSE(ExternallyInstalledWebAppPrefs::HasAppId(prefs, id_a)); + EXPECT_FALSE(ExternallyInstalledWebAppPrefs::HasAppId(prefs, id_b)); + EXPECT_FALSE(ExternallyInstalledWebAppPrefs::HasAppId(prefs, id_c)); + EXPECT_FALSE(ExternallyInstalledWebAppPrefs::HasAppId(prefs, id_d)); + + EXPECT_EQ(std::vector<GURL>({}), + GetInstalledAppUrls(InstallSource::kInternal)); + EXPECT_EQ(std::vector<GURL>({}), + GetInstalledAppUrls(InstallSource::kExternalDefault)); + EXPECT_EQ(std::vector<GURL>({}), + GetInstalledAppUrls(InstallSource::kExternalPolicy)); + + // Add some entries. + + SimulatePreviouslyInstalledApp(url_a, InstallSource::kExternalDefault); + SimulatePreviouslyInstalledApp(url_b, InstallSource::kInternal); + SimulatePreviouslyInstalledApp(url_c, InstallSource::kExternalDefault); + + EXPECT_EQ(id_a, map.LookupAppId(url_a).value_or("missing")); + EXPECT_EQ(id_b, map.LookupAppId(url_b).value_or("missing")); + EXPECT_EQ(id_c, map.LookupAppId(url_c).value_or("missing")); + EXPECT_EQ("missing", map.LookupAppId(url_d).value_or("missing")); + + EXPECT_TRUE(ExternallyInstalledWebAppPrefs::HasAppId(prefs, id_a)); + EXPECT_TRUE(ExternallyInstalledWebAppPrefs::HasAppId(prefs, id_b)); + EXPECT_TRUE(ExternallyInstalledWebAppPrefs::HasAppId(prefs, id_c)); + EXPECT_FALSE(ExternallyInstalledWebAppPrefs::HasAppId(prefs, id_d)); + + EXPECT_EQ(std::vector<GURL>({url_b}), + GetInstalledAppUrls(InstallSource::kInternal)); + EXPECT_EQ(std::vector<GURL>({url_a, url_c}), + GetInstalledAppUrls(InstallSource::kExternalDefault)); + EXPECT_EQ(std::vector<GURL>({}), + GetInstalledAppUrls(InstallSource::kExternalPolicy)); + + // Overwrite an entry. + + SimulatePreviouslyInstalledApp(url_c, InstallSource::kInternal); + + EXPECT_EQ(id_a, map.LookupAppId(url_a).value_or("missing")); + EXPECT_EQ(id_b, map.LookupAppId(url_b).value_or("missing")); + EXPECT_EQ(id_c, map.LookupAppId(url_c).value_or("missing")); + EXPECT_EQ("missing", map.LookupAppId(url_d).value_or("missing")); + + EXPECT_TRUE(ExternallyInstalledWebAppPrefs::HasAppId(prefs, id_a)); + EXPECT_TRUE(ExternallyInstalledWebAppPrefs::HasAppId(prefs, id_b)); + EXPECT_TRUE(ExternallyInstalledWebAppPrefs::HasAppId(prefs, id_c)); + EXPECT_FALSE(ExternallyInstalledWebAppPrefs::HasAppId(prefs, id_d)); + + EXPECT_EQ(std::vector<GURL>({url_b, url_c}), + GetInstalledAppUrls(InstallSource::kInternal)); + EXPECT_EQ(std::vector<GURL>({url_a}), + GetInstalledAppUrls(InstallSource::kExternalDefault)); + EXPECT_EQ(std::vector<GURL>({}), + GetInstalledAppUrls(InstallSource::kExternalPolicy)); + + // Uninstall an underlying extension. The ExternallyInstalledWebAppPrefs will + // still return positive for LookupAppId and HasAppId (as they ignore + // installed-ness), but GetInstalledAppUrls will skip over it. + + SimulateUninstallApp(url_b); + + EXPECT_EQ(id_a, map.LookupAppId(url_a).value_or("missing")); + EXPECT_EQ(id_b, map.LookupAppId(url_b).value_or("missing")); + EXPECT_EQ(id_c, map.LookupAppId(url_c).value_or("missing")); + EXPECT_EQ("missing", map.LookupAppId(url_d).value_or("missing")); + + EXPECT_TRUE(ExternallyInstalledWebAppPrefs::HasAppId(prefs, id_a)); + EXPECT_TRUE(ExternallyInstalledWebAppPrefs::HasAppId(prefs, id_b)); + EXPECT_TRUE(ExternallyInstalledWebAppPrefs::HasAppId(prefs, id_c)); + EXPECT_FALSE(ExternallyInstalledWebAppPrefs::HasAppId(prefs, id_d)); + + EXPECT_EQ(std::vector<GURL>({url_c}), + GetInstalledAppUrls(InstallSource::kInternal)); + EXPECT_EQ(std::vector<GURL>({url_a}), + GetInstalledAppUrls(InstallSource::kExternalDefault)); + EXPECT_EQ(std::vector<GURL>({}), + GetInstalledAppUrls(InstallSource::kExternalPolicy)); +} + +} // namespace web_app
diff --git a/chrome/browser/web_applications/extensions/pending_bookmark_app_manager.cc b/chrome/browser/web_applications/extensions/pending_bookmark_app_manager.cc index 03de80d..8ddbaf3 100644 --- a/chrome/browser/web_applications/extensions/pending_bookmark_app_manager.cc +++ b/chrome/browser/web_applications/extensions/pending_bookmark_app_manager.cc
@@ -53,7 +53,7 @@ install_finalizer_(install_finalizer), uninstaller_( std::make_unique<BookmarkAppUninstaller>(profile_, registrar_)), - extension_ids_map_(profile->GetPrefs()), + externally_installed_app_prefs_(profile->GetPrefs()), url_loader_(std::make_unique<web_app::WebAppUrlLoader>()), task_factory_(base::BindRepeating(&InstallationTaskCreateWrapper)) {} @@ -98,19 +98,19 @@ std::vector<GURL> PendingBookmarkAppManager::GetInstalledAppUrls( web_app::InstallSource install_source) const { - return web_app::ExtensionIdsMap::GetInstalledAppUrls(profile_, - install_source); + return web_app::ExternallyInstalledWebAppPrefs::GetInstalledAppUrls( + profile_, install_source); } base::Optional<web_app::AppId> PendingBookmarkAppManager::LookupAppId( const GURL& url) const { - return extension_ids_map_.LookupExtensionId(url); + return externally_installed_app_prefs_.LookupAppId(url); } bool PendingBookmarkAppManager::HasAppIdWithInstallSource( const web_app::AppId& app_id, web_app::InstallSource install_source) const { - return web_app::ExtensionIdsMap::HasExtensionIdWithInstallSource( + return web_app::ExternallyInstalledWebAppPrefs::HasAppIdWithInstallSource( profile_->GetPrefs(), app_id, install_source); } @@ -150,20 +150,21 @@ return; } - base::Optional<std::string> extension_id = - extension_ids_map_.LookupExtensionId(install_options.url); + base::Optional<web_app::AppId> app_id = + externally_installed_app_prefs_.LookupAppId(install_options.url); - // If the URL is not in ExtensionIdsMap, we haven't installed it. - if (!extension_id.has_value()) { + // If the URL is not in ExternallyInstalledWebAppPrefs, then no external + // source has installed it. + if (!app_id.has_value()) { StartInstallationTask(std::move(front)); return; } - if (registrar_->IsInstalled(extension_id.value())) { + if (registrar_->IsInstalled(app_id.value())) { if (install_options.wait_for_windows_closed && - GetUiDelegate().GetNumWindowsForApp(extension_id.value()) != 0) { + GetUiDelegate().GetNumWindowsForApp(app_id.value()) != 0) { GetUiDelegate().NotifyOnAllAppWindowsClosed( - extension_id.value(), + app_id.value(), base::BindOnce(&PendingBookmarkAppManager::Install, weak_ptr_factory_.GetWeakPtr(), install_options, std::move(front->callback))); @@ -173,7 +174,8 @@ // If the app is already installed, only reinstall it if the app is a // placeholder app and the client asked for it to be reinstalled. if (install_options.reinstall_placeholder && - extension_ids_map_.LookupPlaceholderAppId(install_options.url) + externally_installed_app_prefs_ + .LookupPlaceholderAppId(install_options.url) .has_value()) { StartInstallationTask(std::move(front)); return; @@ -189,7 +191,7 @@ // The app is not installed, but it might have been previously uninstalled // by the user. If that's the case, don't install it again unless // |override_previous_user_uninstall| is true. - if (registrar_->WasExternalAppUninstalledByUser(extension_id.value()) && + if (registrar_->WasExternalAppUninstalledByUser(app_id.value()) && !install_options.override_previous_user_uninstall) { std::move(front->callback) .Run(install_options.url, @@ -212,11 +214,11 @@ if (!install_options.reinstall_placeholder) return true; - base::Optional<std::string> extension_id = - extension_ids_map_.LookupPlaceholderAppId(install_options.url); + base::Optional<web_app::AppId> app_id = + externally_installed_app_prefs_.LookupPlaceholderAppId( + install_options.url); - if (extension_id.has_value() && - registrar_->IsInstalled(extension_id.value())) { + if (app_id.has_value() && registrar_->IsInstalled(app_id.value())) { return uninstaller_->UninstallApp(install_options.url); } @@ -266,12 +268,12 @@ return; } - base::Optional<std::string> extension_id = - extension_ids_map_.LookupPlaceholderAppId(install_options.url); - if (extension_id.has_value() && - registrar_->IsInstalled(extension_id.value())) { + base::Optional<web_app::AppId> app_id = + externally_installed_app_prefs_.LookupPlaceholderAppId( + install_options.url); + if (app_id.has_value() && registrar_->IsInstalled(app_id.value())) { // No need to install a placeholder app again. - CurrentInstallationFinished(extension_id.value()); + CurrentInstallationFinished(app_id.value()); return; } @@ -293,7 +295,7 @@ } void PendingBookmarkAppManager::CurrentInstallationFinished( - const base::Optional<std::string>& app_id) { + const base::Optional<web_app::AppId>& app_id) { // Post a task to avoid InstallableManager crashing and do so before // running the callback in case the callback tries to install another // app.
diff --git a/chrome/browser/web_applications/extensions/pending_bookmark_app_manager.h b/chrome/browser/web_applications/extensions/pending_bookmark_app_manager.h index 005b60d..0a45204 100644 --- a/chrome/browser/web_applications/extensions/pending_bookmark_app_manager.h +++ b/chrome/browser/web_applications/extensions/pending_bookmark_app_manager.h
@@ -14,12 +14,12 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/optional.h" +#include "chrome/browser/web_applications/components/externally_installed_web_app_prefs.h" #include "chrome/browser/web_applications/components/install_options.h" #include "chrome/browser/web_applications/components/pending_app_manager.h" #include "chrome/browser/web_applications/components/web_app_url_loader.h" #include "chrome/browser/web_applications/extensions/bookmark_app_installation_task.h" #include "chrome/browser/web_applications/extensions/bookmark_app_uninstaller.h" -#include "chrome/browser/web_applications/extensions/web_app_extension_ids_map.h" class GURL; class Profile; @@ -101,7 +101,7 @@ web_app::AppRegistrar* registrar_; web_app::InstallFinalizer* install_finalizer_; std::unique_ptr<BookmarkAppUninstaller> uninstaller_; - web_app::ExtensionIdsMap extension_ids_map_; + web_app::ExternallyInstalledWebAppPrefs externally_installed_app_prefs_; // unique_ptr so that it can be replaced in tests. std::unique_ptr<web_app::WebAppUrlLoader> url_loader_;
diff --git a/chrome/browser/web_applications/extensions/pending_bookmark_app_manager_browsertest.cc b/chrome/browser/web_applications/extensions/pending_bookmark_app_manager_browsertest.cc index 16cfb86..25e8347 100644 --- a/chrome/browser/web_applications/extensions/pending_bookmark_app_manager_browsertest.cc +++ b/chrome/browser/web_applications/extensions/pending_bookmark_app_manager_browsertest.cc
@@ -13,8 +13,8 @@ #include "chrome/browser/extensions/extension_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" +#include "chrome/browser/web_applications/components/externally_installed_web_app_prefs.h" #include "chrome/browser/web_applications/components/web_app_constants.h" -#include "chrome/browser/web_applications/extensions/web_app_extension_ids_map.h" #include "chrome/browser/web_applications/web_app_provider.h" #include "chrome/common/chrome_features.h" #include "chrome/common/extensions/api/url_handlers/url_handlers_parser.h" @@ -67,9 +67,9 @@ GURL url(embedded_test_server()->GetURL("/banners/manifest_test_page.html")); InstallApp(CreateInstallOptions(url)); EXPECT_EQ(web_app::InstallResultCode::kSuccess, result_code_.value()); - base::Optional<std::string> id = - web_app::ExtensionIdsMap(browser()->profile()->GetPrefs()) - .LookupExtensionId(url); + base::Optional<web_app::AppId> id = + web_app::ExternallyInstalledWebAppPrefs(browser()->profile()->GetPrefs()) + .LookupAppId(url); ASSERT_TRUE(id.has_value()); const Extension* app = ExtensionRegistry::Get(browser()->profile()) ->enabled_extensions() @@ -167,9 +167,9 @@ "/banners/manifest_test_page.html?manifest=manifest_chrome_url.json")); InstallApp(CreateInstallOptions(url)); EXPECT_EQ(web_app::InstallResultCode::kSuccess, result_code_.value()); - base::Optional<std::string> id = - web_app::ExtensionIdsMap(browser()->profile()->GetPrefs()) - .LookupExtensionId(url); + base::Optional<web_app::AppId> id = + web_app::ExternallyInstalledWebAppPrefs(browser()->profile()->GetPrefs()) + .LookupAppId(url); ASSERT_TRUE(id.has_value()); const Extension* app = ExtensionRegistry::Get(browser()->profile()) ->enabled_extensions() @@ -195,9 +195,9 @@ EXPECT_EQ(web_app::InstallResultCode::kFailedUnknownReason, result_code_.value()); - base::Optional<std::string> id = - web_app::ExtensionIdsMap(browser()->profile()->GetPrefs()) - .LookupExtensionId(url); + base::Optional<web_app::AppId> id = + web_app::ExternallyInstalledWebAppPrefs(browser()->profile()->GetPrefs()) + .LookupAppId(url); ASSERT_FALSE(id.has_value()); }
diff --git a/chrome/browser/web_applications/extensions/pending_bookmark_app_manager_unittest.cc b/chrome/browser/web_applications/extensions/pending_bookmark_app_manager_unittest.cc index 6acad24..7431a70 100644 --- a/chrome/browser/web_applications/extensions/pending_bookmark_app_manager_unittest.cc +++ b/chrome/browser/web_applications/extensions/pending_bookmark_app_manager_unittest.cc
@@ -88,7 +88,7 @@ profile_(profile), registrar_(registrar), succeeds_(succeeds), - extension_ids_map_(profile_->GetPrefs()) {} + externally_installed_app_prefs_(profile_->GetPrefs()) {} ~TestBookmarkAppInstallationTask() override = default; void Install(content::WebContents* web_contents, @@ -126,9 +126,10 @@ BookmarkAppInstallationTask::Result SimulateInstallingApp( bool is_placeholder = false) { std::string app_id = GenerateFakeAppId(install_options().url); - extension_ids_map_.Insert(install_options().url, app_id, - install_options().install_source); - extension_ids_map_.SetIsPlaceholder(install_options().url, is_placeholder); + externally_installed_app_prefs_.Insert(install_options().url, app_id, + install_options().install_source); + externally_installed_app_prefs_.SetIsPlaceholder(install_options().url, + is_placeholder); registrar_->AddAsInstalled(app_id); return {web_app::InstallResultCode::kSuccess, app_id}; } @@ -136,7 +137,7 @@ Profile* profile_; web_app::TestAppRegistrar* registrar_; bool succeeds_; - web_app::ExtensionIdsMap extension_ids_map_; + web_app::ExternallyInstalledWebAppPrefs externally_installed_app_prefs_; base::OnceClosure on_install_called_; base::OnceClosure on_install_placeholder_called_;
diff --git a/chrome/browser/web_applications/extensions/web_app_extension_ids_map.h b/chrome/browser/web_applications/extensions/web_app_extension_ids_map.h deleted file mode 100644 index 3f1f7632..0000000 --- a/chrome/browser/web_applications/extensions/web_app_extension_ids_map.h +++ /dev/null
@@ -1,68 +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 CHROME_BROWSER_WEB_APPLICATIONS_EXTENSIONS_WEB_APP_EXTENSION_IDS_MAP_H_ -#define CHROME_BROWSER_WEB_APPLICATIONS_EXTENSIONS_WEB_APP_EXTENSION_IDS_MAP_H_ - -#include <string> -#include <vector> - -#include "base/macros.h" -#include "base/optional.h" -#include "chrome/browser/web_applications/components/pending_app_manager.h" - -class GURL; -class PrefService; -class Profile; - -namespace user_prefs { -class PrefRegistrySyncable; -} - -namespace web_app { - -// A Prefs-backed map from web app URLs to Chrome extension IDs and their -// InstallSources. -// -// This lets us determine, given a web app's URL, whether that web app is -// already installed. -class ExtensionIdsMap { - public: - static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); - - static bool HasExtensionId(const PrefService* pref_service, - const std::string& extension_id); - - // Returns true if |extension_id| was added with |install_source| to - // |pref_service|. - static bool HasExtensionIdWithInstallSource(const PrefService* pref_service, - const std::string& extension_id, - InstallSource install_source); - - // Returns the URLs of the apps that were installed from |install_source|. - static std::vector<GURL> GetInstalledAppUrls(Profile* profile, - InstallSource install_source); - - explicit ExtensionIdsMap(PrefService* pref_service); - - void Insert(const GURL& url, - const std::string& extension_id, - InstallSource install_source); - base::Optional<std::string> LookupExtensionId(const GURL& url) const; - - // Returns an id if there is a placeholder app for |url|. Note that nullopt - // does not mean that there is no app for |url| just that there is no - // *placeholder app*. - base::Optional<std::string> LookupPlaceholderAppId(const GURL& url) const; - void SetIsPlaceholder(const GURL& url, bool is_placeholder); - - private: - PrefService* pref_service_; - - DISALLOW_COPY_AND_ASSIGN(ExtensionIdsMap); -}; - -} // namespace web_app - -#endif // CHROME_BROWSER_WEB_APPLICATIONS_EXTENSIONS_WEB_APP_EXTENSION_IDS_MAP_H_
diff --git a/chrome/browser/web_applications/extensions/web_app_extension_ids_map_unittest.cc b/chrome/browser/web_applications/extensions/web_app_extension_ids_map_unittest.cc deleted file mode 100644 index 434ad37c..0000000 --- a/chrome/browser/web_applications/extensions/web_app_extension_ids_map_unittest.cc +++ /dev/null
@@ -1,169 +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 "chrome/browser/web_applications/extensions/web_app_extension_ids_map.h" - -#include <algorithm> - -#include "chrome/browser/extensions/test_extension_system.h" -#include "chrome/browser/web_applications/components/web_app_constants.h" -#include "chrome/common/pref_names.h" -#include "chrome/test/base/chrome_render_view_host_test_harness.h" -#include "chrome/test/base/testing_profile.h" -#include "components/crx_file/id_util.h" -#include "components/prefs/scoped_user_pref_update.h" -#include "extensions/browser/extension_registry.h" -#include "extensions/common/extension_builder.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace web_app { - -using InstallSource = InstallSource; - -class WebAppExtensionIdsMapTest : public ChromeRenderViewHostTestHarness { - public: - WebAppExtensionIdsMapTest() = default; - ~WebAppExtensionIdsMapTest() override = default; - - void SetUp() override { - ChromeRenderViewHostTestHarness::SetUp(); - extensions::TestExtensionSystem* test_system = - static_cast<extensions::TestExtensionSystem*>( - extensions::ExtensionSystem::Get(profile())); - test_system->CreateExtensionService(base::CommandLine::ForCurrentProcess(), - profile()->GetPath(), - false); // autoupdate_enabled - } - - std::string GenerateFakeExtensionId(GURL url) { - return crx_file::id_util::GenerateId("fake_app_id_for:" + url.spec()); - } - - void SimulatePreviouslyInstalledApp(GURL url, InstallSource install_source) { - std::string id = GenerateFakeExtensionId(url); - extensions::ExtensionRegistry::Get(profile())->AddEnabled( - extensions::ExtensionBuilder("Dummy Name").SetID(id).Build()); - - ExtensionIdsMap extension_ids_map(profile()->GetPrefs()); - extension_ids_map.Insert(url, id, install_source); - } - - void SimulateUninstallApp(GURL url) { - std::string id = GenerateFakeExtensionId(url); - extensions::ExtensionRegistry::Get(profile())->RemoveEnabled(id); - } - - std::vector<GURL> GetInstalledAppUrls(InstallSource install_source) { - std::vector<GURL> vec = - ExtensionIdsMap::GetInstalledAppUrls(profile(), install_source); - std::sort(vec.begin(), vec.end()); - return vec; - } - - private: - DISALLOW_COPY_AND_ASSIGN(WebAppExtensionIdsMapTest); -}; - -TEST_F(WebAppExtensionIdsMapTest, BasicOps) { - GURL url_a("https://a.example.com/"); - GURL url_b("https://b.example.com/"); - GURL url_c("https://c.example.com/"); - GURL url_d("https://d.example.com/"); - - std::string id_a = GenerateFakeExtensionId(url_a); - std::string id_b = GenerateFakeExtensionId(url_b); - std::string id_c = GenerateFakeExtensionId(url_c); - std::string id_d = GenerateFakeExtensionId(url_d); - - auto* prefs = profile()->GetPrefs(); - ExtensionIdsMap map(prefs); - - // Start with an empty map. - - EXPECT_EQ("missing", map.LookupExtensionId(url_a).value_or("missing")); - EXPECT_EQ("missing", map.LookupExtensionId(url_b).value_or("missing")); - EXPECT_EQ("missing", map.LookupExtensionId(url_c).value_or("missing")); - EXPECT_EQ("missing", map.LookupExtensionId(url_d).value_or("missing")); - - EXPECT_FALSE(ExtensionIdsMap::HasExtensionId(prefs, id_a)); - EXPECT_FALSE(ExtensionIdsMap::HasExtensionId(prefs, id_b)); - EXPECT_FALSE(ExtensionIdsMap::HasExtensionId(prefs, id_c)); - EXPECT_FALSE(ExtensionIdsMap::HasExtensionId(prefs, id_d)); - - EXPECT_EQ(std::vector<GURL>({}), - GetInstalledAppUrls(InstallSource::kInternal)); - EXPECT_EQ(std::vector<GURL>({}), - GetInstalledAppUrls(InstallSource::kExternalDefault)); - EXPECT_EQ(std::vector<GURL>({}), - GetInstalledAppUrls(InstallSource::kExternalPolicy)); - - // Add some entries. - - SimulatePreviouslyInstalledApp(url_a, InstallSource::kExternalDefault); - SimulatePreviouslyInstalledApp(url_b, InstallSource::kInternal); - SimulatePreviouslyInstalledApp(url_c, InstallSource::kExternalDefault); - - EXPECT_EQ(id_a, map.LookupExtensionId(url_a).value_or("missing")); - EXPECT_EQ(id_b, map.LookupExtensionId(url_b).value_or("missing")); - EXPECT_EQ(id_c, map.LookupExtensionId(url_c).value_or("missing")); - EXPECT_EQ("missing", map.LookupExtensionId(url_d).value_or("missing")); - - EXPECT_TRUE(ExtensionIdsMap::HasExtensionId(prefs, id_a)); - EXPECT_TRUE(ExtensionIdsMap::HasExtensionId(prefs, id_b)); - EXPECT_TRUE(ExtensionIdsMap::HasExtensionId(prefs, id_c)); - EXPECT_FALSE(ExtensionIdsMap::HasExtensionId(prefs, id_d)); - - EXPECT_EQ(std::vector<GURL>({url_b}), - GetInstalledAppUrls(InstallSource::kInternal)); - EXPECT_EQ(std::vector<GURL>({url_a, url_c}), - GetInstalledAppUrls(InstallSource::kExternalDefault)); - EXPECT_EQ(std::vector<GURL>({}), - GetInstalledAppUrls(InstallSource::kExternalPolicy)); - - // Overwrite an entry. - - SimulatePreviouslyInstalledApp(url_c, InstallSource::kInternal); - - EXPECT_EQ(id_a, map.LookupExtensionId(url_a).value_or("missing")); - EXPECT_EQ(id_b, map.LookupExtensionId(url_b).value_or("missing")); - EXPECT_EQ(id_c, map.LookupExtensionId(url_c).value_or("missing")); - EXPECT_EQ("missing", map.LookupExtensionId(url_d).value_or("missing")); - - EXPECT_TRUE(ExtensionIdsMap::HasExtensionId(prefs, id_a)); - EXPECT_TRUE(ExtensionIdsMap::HasExtensionId(prefs, id_b)); - EXPECT_TRUE(ExtensionIdsMap::HasExtensionId(prefs, id_c)); - EXPECT_FALSE(ExtensionIdsMap::HasExtensionId(prefs, id_d)); - - EXPECT_EQ(std::vector<GURL>({url_b, url_c}), - GetInstalledAppUrls(InstallSource::kInternal)); - EXPECT_EQ(std::vector<GURL>({url_a}), - GetInstalledAppUrls(InstallSource::kExternalDefault)); - EXPECT_EQ(std::vector<GURL>({}), - GetInstalledAppUrls(InstallSource::kExternalPolicy)); - - // Uninstall an underlying extension. The ExtensionIdsMap will still return - // positive for LookupExtensionId and HasExtensionId (as they ignore - // installed-ness), but GetInstalledAppUrls will skip over it. - - SimulateUninstallApp(url_b); - - EXPECT_EQ(id_a, map.LookupExtensionId(url_a).value_or("missing")); - EXPECT_EQ(id_b, map.LookupExtensionId(url_b).value_or("missing")); - EXPECT_EQ(id_c, map.LookupExtensionId(url_c).value_or("missing")); - EXPECT_EQ("missing", map.LookupExtensionId(url_d).value_or("missing")); - - EXPECT_TRUE(ExtensionIdsMap::HasExtensionId(prefs, id_a)); - EXPECT_TRUE(ExtensionIdsMap::HasExtensionId(prefs, id_b)); - EXPECT_TRUE(ExtensionIdsMap::HasExtensionId(prefs, id_c)); - EXPECT_FALSE(ExtensionIdsMap::HasExtensionId(prefs, id_d)); - - EXPECT_EQ(std::vector<GURL>({url_c}), - GetInstalledAppUrls(InstallSource::kInternal)); - EXPECT_EQ(std::vector<GURL>({url_a}), - GetInstalledAppUrls(InstallSource::kExternalDefault)); - EXPECT_EQ(std::vector<GURL>({}), - GetInstalledAppUrls(InstallSource::kExternalPolicy)); -} - -} // namespace web_app
diff --git a/chrome/browser/web_applications/web_app_provider.cc b/chrome/browser/web_applications/web_app_provider.cc index edec6f4..09b3931 100644 --- a/chrome/browser/web_applications/web_app_provider.cc +++ b/chrome/browser/web_applications/web_app_provider.cc
@@ -14,6 +14,7 @@ #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/web_applications/bookmark_apps/bookmark_app_install_manager.h" +#include "chrome/browser/web_applications/components/externally_installed_web_app_prefs.h" #include "chrome/browser/web_applications/components/policy/web_app_policy_manager.h" #include "chrome/browser/web_applications/components/web_app_audio_focus_id_map.h" #include "chrome/browser/web_applications/components/web_app_constants.h" @@ -24,7 +25,6 @@ #include "chrome/browser/web_applications/extensions/bookmark_app_tab_helper.h" #include "chrome/browser/web_applications/extensions/bookmark_app_util.h" #include "chrome/browser/web_applications/extensions/pending_bookmark_app_manager.h" -#include "chrome/browser/web_applications/extensions/web_app_extension_ids_map.h" #include "chrome/browser/web_applications/external_web_apps.h" #include "chrome/browser/web_applications/file_utils_wrapper.h" #include "chrome/browser/web_applications/system_web_app_manager.h" @@ -168,7 +168,7 @@ // static void WebAppProvider::RegisterProfilePrefs( user_prefs::PrefRegistrySyncable* registry) { - ExtensionIdsMap::RegisterProfilePrefs(registry); + ExternallyInstalledWebAppPrefs::RegisterProfilePrefs(registry); WebAppPolicyManager::RegisterProfilePrefs(registry); SystemWebAppManager::RegisterProfilePrefs(registry); }
diff --git a/chrome/credential_provider/test/BUILD.gn b/chrome/credential_provider/test/BUILD.gn index 6e8ca24..45b2cc9 100644 --- a/chrome/credential_provider/test/BUILD.gn +++ b/chrome/credential_provider/test/BUILD.gn
@@ -52,9 +52,9 @@ "//third_party/tlslite/", ] - if (is_win && llvm_force_head_revision) { + if (is_win) { # TODO(https://crbug.com/958955): Fix dupes and remove this flag. - ldflags = [ "/FORCE:MultipleRes" ] configs -= [ "//build/config/compiler:fatal_linker_warnings_win" ] + ldflags = [ "/FORCE:MultipleRes" ] } }
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index c7c936be..6c9ac8fa 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -1670,6 +1670,7 @@ "../browser/ui/views/payments/error_message_view_controller_browsertest.cc", "../browser/ui/views/payments/modifiers_browsertest.cc", "../browser/ui/views/payments/order_summary_view_controller_browsertest.cc", + "../browser/ui/views/payments/payment_handler_change_payment_method_browsertest.cc", "../browser/ui/views/payments/payment_method_view_controller_browsertest.cc", "../browser/ui/views/payments/payment_request_blob_url_browsertest.cc", "../browser/ui/views/payments/payment_request_browsertest.cc", @@ -3159,8 +3160,8 @@ "//components/strings", "//components/subresource_filter/core/browser:test_support", "//components/sync:test_support", - "//components/sync:test_support_user_events", "//components/sync_sessions:test_support", + "//components/sync_user_events:test_support", "//components/ukm/content", "//components/version_info:generate_version_info", "//components/webdata_services:test_support", @@ -3728,6 +3729,7 @@ "../browser/chromeos/crostini/crostini_mime_types_service_unittest.cc", "../browser/chromeos/crostini/crostini_registry_service_unittest.cc", "../browser/chromeos/crostini/crostini_reporting_util_unittest.cc", + "../browser/chromeos/plugin_vm/plugin_vm_files_unittest.cc", "../browser/chromeos/plugin_vm/plugin_vm_util_unittest.cc", "../browser/chromeos/usb/cros_usb_detector_unittest.cc", "../browser/component_updater/cros_component_installer_chromeos_unittest.cc", @@ -4551,11 +4553,10 @@ "/DELAYLOAD:api-ms-win-core-winrt-l1-1-0.dll", "/DELAYLOAD:api-ms-win-core-winrt-string-l1-1-0.dll", ] - if (llvm_force_head_revision) { - # TODO(https://crbug.com/958955): Fix dupes and remove this flag. - ldflags += [ "/FORCE:MultipleRes" ] - configs -= [ "//build/config/compiler:fatal_linker_warnings_win" ] - } + + # TODO(https://crbug.com/958955): Fix dupes and remove this flag. + configs -= [ "//build/config/compiler:fatal_linker_warnings_win" ] + ldflags += [ "/FORCE:MultipleRes" ] if (is_chrome_branded) { sources += [ @@ -4757,6 +4758,7 @@ "../browser/ui/app_list/search/search_result_ranker/ranking_item_util_unittest.cc", "../browser/ui/app_list/search/search_result_ranker/recurrence_predictor_unittest.cc", "../browser/ui/app_list/search/search_result_ranker/recurrence_ranker_unittest.cc", + "../browser/ui/app_list/search/search_result_ranker/search_result_ranker_unittest.cc", "../browser/ui/app_list/search/settings_shortcut/settings_shortcut_provider_unittest.cc", "../browser/ui/app_list/search/settings_shortcut/settings_shortcut_result_unittest.cc", "../browser/ui/app_list/search/tests/app_search_provider_unittest.cc", @@ -5779,11 +5781,10 @@ configs -= [ "//build/config/win:default_incremental_linking" ] configs += [ "//build/config/win:default_large_module_incremental_linking" ] - if (llvm_force_head_revision) { - # TODO(https://crbug.com/958955): Fix dupes and remove this flag. - ldflags = [ "/FORCE:MultipleRes" ] - configs -= [ "//build/config/compiler:fatal_linker_warnings_win" ] - } + + # TODO(https://crbug.com/958955): Fix dupes and remove this flag. + configs -= [ "//build/config/compiler:fatal_linker_warnings_win" ] + ldflags = [ "/FORCE:MultipleRes" ] } else { sources -= [ "../app/chrome_version.rc.version" ] }
diff --git a/chromeos/components/account_manager/account_manager.cc b/chromeos/components/account_manager/account_manager.cc index 5c741ffa..737ee575 100644 --- a/chromeos/components/account_manager/account_manager.cc +++ b/chromeos/components/account_manager/account_manager.cc
@@ -22,6 +22,7 @@ #include "components/prefs/pref_service.h" #include "google_apis/gaia/gaia_auth_consumer.h" #include "google_apis/gaia/gaia_auth_fetcher.h" +#include "google_apis/gaia/gaia_auth_util.h" #include "google_apis/gaia/oauth2_access_token_fetcher_impl.h" #include "google_apis/gaia/oauth2_token_service_delegate.h" #include "services/network/public/cpp/shared_url_loader_factory.h" @@ -323,6 +324,27 @@ NotifyAccountRemovalObservers(Account{account_key, raw_email}); } +void AccountManager::RemoveAccount(const std::string& email) { + DCHECK_NE(init_state_, InitializationState::kNotStarted); + + base::OnceClosure closure = + base::BindOnce(&AccountManager::RemoveAccountByEmailInternal, + weak_factory_.GetWeakPtr(), email); + RunOnInitialization(std::move(closure)); +} + +void AccountManager::RemoveAccountByEmailInternal(const std::string& email) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK_EQ(init_state_, InitializationState::kInitialized); + + for (const std::pair<AccountKey, AccountInfo> account : accounts_) { + if (gaia::AreEmailsSame(account.second.raw_email, email)) { + RemoveAccountInternal(account.first /* account_key */); + return; + } + } +} + void AccountManager::UpsertAccount(const AccountKey& account_key, const std::string& raw_email, const std::string& token) {
diff --git a/chromeos/components/account_manager/account_manager.h b/chromeos/components/account_manager/account_manager.h index 2eacbb1..0a89dc4 100644 --- a/chromeos/components/account_manager/account_manager.h +++ b/chromeos/components/account_manager/account_manager.h
@@ -157,6 +157,11 @@ // with GAIA fails, AccountManager will forget the account. void RemoveAccount(const AccountKey& account_key); + // Similar to |RemoveAccount(AccountKey)| except that it accepts |email| as + // the account identifier instead of |account_key|. |email| can be the raw + // email or the canonical email. + void RemoveAccount(const std::string& email); + // Updates or inserts an account. |raw_email| is the raw, un-canonicalized // email id for |account_key|. |raw_email| must not be empty. Use // |AccountManager::kActiveDirectoryDummyToken| as the |token| for Active @@ -275,6 +280,11 @@ // |AccountManager| initialization (|init_state_|) is complete. void RemoveAccountInternal(const AccountKey& account_key); + // Does the actual work of removing an account. Assumes that |AccountManager| + // initialization (|init_state_|) is complete. |email| can be the raw email or + // the canonical email. + void RemoveAccountByEmailInternal(const std::string& email); + // Assumes that |AccountManager| initialization (|init_state_|) is complete. void UpdateTokenInternal(const AccountKey& account_key, const std::string& token);
diff --git a/chromeos/components/account_manager/account_manager_unittest.cc b/chromeos/components/account_manager/account_manager_unittest.cc index 797ab39b..eba789c 100644 --- a/chromeos/components/account_manager/account_manager_unittest.cc +++ b/chromeos/components/account_manager/account_manager_unittest.cc
@@ -319,9 +319,24 @@ account_manager_->UpsertAccount(kGaiaAccountKey_, kRawUserEmail, kGaiaToken); account_manager_->RemoveAccount(kGaiaAccountKey_); - std::vector<AccountManager::Account> accounts = GetAccountsBlocking(); + EXPECT_TRUE(GetAccountsBlocking().empty()); +} - EXPECT_TRUE(accounts.empty()); +TEST_F(AccountManagerTest, AccountsCanBeRemovedByRawEmail) { + account_manager_->UpsertAccount(kGaiaAccountKey_, kRawUserEmail, kGaiaToken); + + account_manager_->RemoveAccount(kRawUserEmail); + EXPECT_TRUE(GetAccountsBlocking().empty()); +} + +TEST_F(AccountManagerTest, AccountsCanBeRemovedByCanonicalEmail) { + const std::string raw_email = "abc.123.456@gmail.com"; + const std::string canonical_email = "abc123456@gmail.com"; + + account_manager_->UpsertAccount(kGaiaAccountKey_, raw_email, kGaiaToken); + + account_manager_->RemoveAccount(canonical_email); + EXPECT_TRUE(GetAccountsBlocking().empty()); } TEST_F(AccountManagerTest, AccountRemovalIsPersistedToDisk) { @@ -330,10 +345,7 @@ scoped_task_environment_.RunUntilIdle(); ResetAndInitializeAccountManager(); - - std::vector<AccountManager::Account> accounts = GetAccountsBlocking(); - - EXPECT_TRUE(accounts.empty()); + EXPECT_TRUE(GetAccountsBlocking().empty()); } TEST_F(AccountManagerTest, ObserversAreNotifiedOnAccountRemoval) { @@ -412,8 +424,8 @@ AccountManager::kActiveDirectoryDummyToken); scoped_task_environment_.RunUntilIdle(); EXPECT_FALSE(account_manager_->IsTokenAvailable(kActiveDirectoryAccountKey_)); - std::vector<AccountManager::Account> accounts = GetAccountsBlocking(); - EXPECT_TRUE(IsAccountKeyPresent(accounts, kActiveDirectoryAccountKey_)); + EXPECT_TRUE( + IsAccountKeyPresent(GetAccountsBlocking(), kActiveDirectoryAccountKey_)); } TEST_F(AccountManagerTest, IsTokenAvailableReturnsTrueForInvalidTokens) { @@ -422,8 +434,7 @@ AccountManager::kInvalidToken); scoped_task_environment_.RunUntilIdle(); EXPECT_TRUE(account_manager_->IsTokenAvailable(kGaiaAccountKey_)); - std::vector<AccountManager::Account> accounts = GetAccountsBlocking(); - EXPECT_TRUE(IsAccountKeyPresent(accounts, kGaiaAccountKey_)); + EXPECT_TRUE(IsAccountKeyPresent(GetAccountsBlocking(), kGaiaAccountKey_)); } } // namespace chromeos
diff --git a/chromeos/dbus/cros_disks_client.cc b/chromeos/dbus/cros_disks_client.cc index 0bf45c8..3994610 100644 --- a/chromeos/dbus/cros_disks_client.cc +++ b/chromeos/dbus/cros_disks_client.cc
@@ -639,6 +639,10 @@ // variant string "/sys/devices/pci0000:00/0000:00:1d.7/usb1/1-4/... // } // dict entry { +// string "StorageDevicePath" +// variant string "/sys/devices/pci0000:00/0000:00:1d.7/usb1/1-4/... +// } +// dict entry { // string "FileSystemType" // variant string "vfat" // } @@ -668,6 +672,8 @@ &is_auto_mountable_); properties->GetStringWithoutPathExpansion( cros_disks::kNativePath, &system_path_); + properties->GetStringWithoutPathExpansion(cros_disks::kStorageDevicePath, + &storage_device_path_); properties->GetStringWithoutPathExpansion( cros_disks::kDeviceFile, &file_path_); properties->GetStringWithoutPathExpansion(cros_disks::kVendorId, &vendor_id_);
diff --git a/chromeos/dbus/cros_disks_client.h b/chromeos/dbus/cros_disks_client.h index 56913513..297e544eb 100644 --- a/chromeos/dbus/cros_disks_client.h +++ b/chromeos/dbus/cros_disks_client.h
@@ -152,6 +152,12 @@ // (e.g. /sys/devices/pci0000:00/.../8:0:0:0/block/sdb/sdb1) const std::string& system_path() const { return system_path_; } + // Path of the scsi/mmc/nvme storage device that this disk is a part of. + // (e.g. /sys/devices/pci0000:00/.../mmc_host/mmc0/mmc0:0002) + const std::string& storage_device_path() const { + return storage_device_path_; + } + // Is a drive or not. (i.e. true with /dev/sdb, false with /dev/sdb1) bool is_drive() const { return is_drive_; } @@ -215,6 +221,7 @@ std::string device_path_; std::string mount_path_; std::string system_path_; + std::string storage_device_path_; bool is_drive_; bool has_media_; bool on_boot_device_;
diff --git a/chromeos/disks/disk.cc b/chromeos/disks/disk.cc index 4144289f..20f55f7 100644 --- a/chromeos/disks/disk.cc +++ b/chromeos/disks/disk.cc
@@ -17,7 +17,6 @@ Disk::Disk(const DiskInfo& disk_info, bool write_disabled_by_policy, - const std::string& system_path_prefix, const std::string& base_mount_path) : device_path_(disk_info.device_path()), mount_path_(disk_info.mount_path()), @@ -31,7 +30,7 @@ product_id_(disk_info.product_id()), product_name_(disk_info.product_name()), fs_uuid_(disk_info.uuid()), - system_path_prefix_(system_path_prefix), + system_path_prefix_(disk_info.storage_device_path()), device_type_(disk_info.device_type()), total_size_in_bytes_(disk_info.total_size_in_bytes()), is_parent_(disk_info.is_drive()),
diff --git a/chromeos/disks/disk.h b/chromeos/disks/disk.h index a9f9d30..c72585b 100644 --- a/chromeos/disks/disk.h +++ b/chromeos/disks/disk.h
@@ -23,7 +23,6 @@ // Whether the device is mounted in read-only mode by the policy. // Valid only when the device mounted and mount_path_ is non-empty. bool write_disabled_by_policy, - const std::string& system_path_prefix, const std::string& base_mount_path); // For tests.
diff --git a/chromeos/disks/disk_mount_manager.cc b/chromeos/disks/disk_mount_manager.cc index 9ad68758..3879313 100644 --- a/chromeos/disks/disk_mount_manager.cc +++ b/chromeos/disks/disk_mount_manager.cc
@@ -634,7 +634,6 @@ bool write_disabled_by_policy = access_mode != access_modes_.end() && access_mode->second == chromeos::MOUNT_ACCESS_MODE_READ_ONLY; Disk* disk = new Disk(disk_info, write_disabled_by_policy, - FindSystemPathPrefix(disk_info.system_path()), base_mount_path); disks_.insert( std::make_pair(disk_info.device_path(), base::WrapUnique(disk))); @@ -726,12 +725,10 @@ break; } case CROS_DISKS_DEVICE_ADDED: { - system_path_prefixes_.insert(device_path); NotifyDeviceStatusUpdate(DEVICE_ADDED, device_path); break; } case CROS_DISKS_DEVICE_REMOVED: { - system_path_prefixes_.erase(device_path); NotifyDeviceStatusUpdate(DEVICE_REMOVED, device_path); break; } @@ -782,20 +779,6 @@ observer.OnRenameEvent(event, error_code, device_path); } - // Finds system path prefix from |system_path|. - const std::string& FindSystemPathPrefix(const std::string& system_path) { - if (system_path.empty()) - return base::EmptyString(); - for (SystemPathPrefixSet::const_iterator it = system_path_prefixes_.begin(); - it != system_path_prefixes_.end(); - ++it) { - const std::string& prefix = *it; - if (base::StartsWith(system_path, prefix, base::CompareCase::SENSITIVE)) - return prefix; - } - return base::EmptyString(); - } - // Mount event change observers. base::ObserverList<DiskMountManager::Observer>::Unchecked observers_; @@ -806,9 +789,6 @@ DiskMountManager::MountPointMap mount_points_; - typedef std::set<std::string> SystemPathPrefixSet; - SystemPathPrefixSet system_path_prefixes_; - bool already_refreshed_; std::vector<EnsureMountInfoRefreshedCallback> refresh_callbacks_;
diff --git a/chromeos/disks/disk_unittest.cc b/chromeos/disks/disk_unittest.cc index 948e6b0..833d125 100644 --- a/chromeos/disks/disk_unittest.cc +++ b/chromeos/disks/disk_unittest.cc
@@ -27,6 +27,9 @@ const char kIdLabel[] = "UNTITLED"; const char kIdUuid[] = "XXXX-YYYY"; const char kNativePath[] = "/sys/devices/.../sdb/sdb1"; +const char kStorageDevicePath[] = + "/sys/devices/pci0000:00/0000:00:14.0/usb2/2-8/2-8:1.0/host14/target14:0:0/" + "14:0:0:0"; const char kProductId[] = "1234"; const char kProductName[] = "Product Name"; const char kVendorId[] = "0000"; @@ -85,6 +88,8 @@ AppendStringDictEntry(array_writer, cros_disks::kIdLabel, kIdLabel); AppendStringDictEntry(array_writer, cros_disks::kIdUuid, kIdUuid); AppendStringDictEntry(array_writer, cros_disks::kNativePath, kNativePath); + AppendStringDictEntry(array_writer, cros_disks::kStorageDevicePath, + kStorageDevicePath); AppendStringDictEntry(array_writer, cros_disks::kProductId, kProductId); AppendStringDictEntry(array_writer, cros_disks::kProductName, kProductName); AppendStringDictEntry(array_writer, cros_disks::kVendorId, kVendorId); @@ -110,13 +115,11 @@ } TEST(DiskTest, ConstructFromDiskInfo) { - const char kSystemPathPrefix[] = "/system/path/prefix"; const char kBaseMountpath[] = "/base/mount/path"; std::unique_ptr<dbus::Response> response = BuildBasicDbusResponse(); DiskInfo disk_info(kDevicePath, response.get()); - Disk disk(disk_info, false /* write_disabled_by_policy */, kSystemPathPrefix, - kBaseMountpath); + Disk disk(disk_info, false /* write_disabled_by_policy */, kBaseMountpath); EXPECT_EQ(kDevicePath, disk.device_path()); EXPECT_EQ(kNativePath, disk.system_path()); @@ -130,7 +133,7 @@ EXPECT_EQ(kIdUuid, disk.fs_uuid()); EXPECT_EQ(kDeviceSize, disk.total_size_in_bytes()); EXPECT_EQ(DEVICE_TYPE_SD, disk.device_type()); - EXPECT_EQ(kSystemPathPrefix, disk.system_path_prefix()); + EXPECT_EQ(kStorageDevicePath, disk.system_path_prefix()); EXPECT_EQ(kBaseMountpath, disk.base_mount_path()); EXPECT_FALSE(disk.is_parent()); EXPECT_FALSE(disk.is_read_only()); @@ -159,7 +162,7 @@ writer.CloseContainer(&array_writer); } DiskInfo disk_info(kDevicePath, response.get()); - return std::make_unique<Disk>(disk_info, false, "", ""); + return std::make_unique<Disk>(disk_info, false, ""); } TEST(DiskTest, ConstructFromDiskInfo_BoolProperties) { @@ -195,7 +198,7 @@ TEST(DiskTest, ConstructFromDiskInfo_WriteDisabledByPolicy) { std::unique_ptr<dbus::Response> response = BuildBasicDbusResponse(); DiskInfo disk_info(kDevicePath, response.get()); - Disk disk(disk_info, true /* write_disabled_by_policy */, "", ""); + Disk disk(disk_info, true /* write_disabled_by_policy */, ""); EXPECT_TRUE(disk.is_read_only()); EXPECT_FALSE(disk.is_read_only_hardware()); @@ -225,7 +228,7 @@ } DiskInfo disk_info(kDevicePath, response.get()); - Disk disk(disk_info, false, "", ""); + Disk disk(disk_info, false, ""); EXPECT_TRUE(disk.is_mounted()); EXPECT_EQ(kMountPath1, disk.mount_path()); @@ -234,7 +237,7 @@ TEST(DiskTest, SetMountPath) { std::unique_ptr<dbus::Response> response = BuildBasicDbusResponse(); DiskInfo disk_info(kDevicePath, response.get()); - Disk disk(disk_info, false /* write_disabled_by_policy */, "", ""); + Disk disk(disk_info, false /* write_disabled_by_policy */, ""); EXPECT_EQ("", disk.mount_path()); EXPECT_EQ("", disk.base_mount_path());
diff --git a/components/BUILD.gn b/components/BUILD.gn index 6f9928c..2472eeb 100644 --- a/components/BUILD.gn +++ b/components/BUILD.gn
@@ -157,6 +157,7 @@ "//components/sync_bookmarks:unit_tests", "//components/sync_preferences:unit_tests", "//components/sync_sessions:unit_tests", + "//components/sync_user_events:unit_tests", "//components/test:run_all_unittests", "//components/thread_pool_util:unit_tests", "//components/translate/core/browser:unit_tests",
diff --git a/components/browser_sync/BUILD.gn b/components/browser_sync/BUILD.gn index 09b81e0..d083bc4 100644 --- a/components/browser_sync/BUILD.gn +++ b/components/browser_sync/BUILD.gn
@@ -29,9 +29,9 @@ "//components/prefs", "//components/reading_list/features:flags", "//components/send_tab_to_self", - "//components/sync/user_events", "//components/sync_bookmarks", "//components/sync_sessions", + "//components/sync_user_events", "//components/version_info", "//components/version_info:generate_version_info", ]
diff --git a/components/browser_sync/DEPS b/components/browser_sync/DEPS index 179495cf..22ec7ac 100644 --- a/components/browser_sync/DEPS +++ b/components/browser_sync/DEPS
@@ -13,6 +13,7 @@ "+components/sync_bookmarks", "+components/sync_preferences", "+components/sync_sessions", + "+components/sync_user_events", "+components/version_info", "+components/webdata/common", "+components/webdata_services",
diff --git a/components/browser_sync/profile_sync_components_factory_impl.cc b/components/browser_sync/profile_sync_components_factory_impl.cc index 51fa026..1296548 100644 --- a/components/browser_sync/profile_sync_components_factory_impl.cc +++ b/components/browser_sync/profile_sync_components_factory_impl.cc
@@ -40,7 +40,6 @@ #include "components/sync/model/model_type_store_service.h" #include "components/sync/model_impl/forwarding_model_type_controller_delegate.h" #include "components/sync/model_impl/proxy_model_type_controller_delegate.h" -#include "components/sync/user_events/user_event_model_type_controller.h" #include "components/sync_bookmarks/bookmark_change_processor.h" #include "components/sync_bookmarks/bookmark_data_type_controller.h" #include "components/sync_bookmarks/bookmark_model_associator.h" @@ -48,6 +47,7 @@ #include "components/sync_sessions/proxy_tabs_data_type_controller.h" #include "components/sync_sessions/session_model_type_controller.h" #include "components/sync_sessions/session_sync_service.h" +#include "components/sync_user_events/user_event_model_type_controller.h" using base::FeatureList; using bookmarks::BookmarkModel;
diff --git a/components/keyed_service/core/simple_dependency_manager.cc b/components/keyed_service/core/simple_dependency_manager.cc index 254c6ef..57d20b9 100644 --- a/components/keyed_service/core/simple_dependency_manager.cc +++ b/components/keyed_service/core/simple_dependency_manager.cc
@@ -43,6 +43,10 @@ DependencyManager::CreateContextServices(key, true); } +void SimpleDependencyManager::MarkContextLive(SimpleFactoryKey* key) { + DependencyManager::MarkContextLive(key); +} + SimpleDependencyManager::SimpleDependencyManager() = default; SimpleDependencyManager::~SimpleDependencyManager() = default;
diff --git a/components/keyed_service/core/simple_dependency_manager.h b/components/keyed_service/core/simple_dependency_manager.h index 72fa74c9..480f971 100644 --- a/components/keyed_service/core/simple_dependency_manager.h +++ b/components/keyed_service/core/simple_dependency_manager.h
@@ -35,6 +35,11 @@ // ServiceIsNULLWhileTesting(). void CreateServicesForTest(SimpleFactoryKey* key); + // Marks |context| as live (i.e., not stale). This method can be called as a + // safeguard against |AssertContextWasntDestroyed()| checks going off due to + // |context| aliasing an instance from a prior construction. + void MarkContextLive(SimpleFactoryKey* key); + private: ~SimpleDependencyManager() override;
diff --git a/components/omnibox/browser/omnibox_metrics_provider.cc b/components/omnibox/browser/omnibox_metrics_provider.cc index 279e4d4..8109dc8 100644 --- a/components/omnibox/browser/omnibox_metrics_provider.cc +++ b/components/omnibox/browser/omnibox_metrics_provider.cc
@@ -177,12 +177,6 @@ provider_info->CopyFrom(*i); } omnibox_event->set_in_keyword_mode(log.in_keyword_mode); - if (log.in_keyword_mode) { - if (metrics::OmniboxEventProto_KeywordModeEntryMethod_IsValid( - log.keyword_mode_entry_method)) - omnibox_event->set_keyword_mode_entry_method( - log.keyword_mode_entry_method); - else - omnibox_event->set_keyword_mode_entry_method(OmniboxEventProto::INVALID); - } + if (log.in_keyword_mode) + omnibox_event->set_keyword_mode_entry_method(log.keyword_mode_entry_method); }
diff --git a/components/payments/content/BUILD.gn b/components/payments/content/BUILD.gn index 67fc6a0e..51555e0 100644 --- a/components/payments/content/BUILD.gn +++ b/components/payments/content/BUILD.gn
@@ -37,6 +37,7 @@ "//components/keyed_service/content", "//components/payments/content/utility", "//components/payments/core", + "//components/payments/core:error_strings", "//components/payments/mojom", "//components/prefs", "//components/strings:components_strings_grit",
diff --git a/components/payments/content/payment_request.cc b/components/payments/content/payment_request.cc index 0a190ab..3c21dc8e 100644 --- a/components/payments/content/payment_request.cc +++ b/components/payments/content/payment_request.cc
@@ -15,7 +15,9 @@ #include "components/payments/content/origin_security_checker.h" #include "components/payments/content/payment_request_converter.h" #include "components/payments/content/payment_request_web_contents_manager.h" +#include "components/payments/content/service_worker_payment_instrument.h" #include "components/payments/core/can_make_payment_query.h" +#include "components/payments/core/error_strings.h" #include "components/payments/core/features.h" #include "components/payments/core/payment_details.h" #include "components/payments/core/payment_details_validation.h" @@ -30,14 +32,51 @@ #include "content/public/browser/web_contents.h" #include "content/public/common/content_features.h" +namespace payments { namespace { using ::payments::mojom::CanMakePaymentQueryResult; using ::payments::mojom::HasEnrolledInstrumentQueryResult; -} // namespace +mojom::PaymentMethodChangeResponsePtr ConvertToPaymentMethodChangeResponse( + const mojom::PaymentDetailsPtr& details, + const PaymentInstrument& invoked_app) { + mojom::PaymentMethodChangeResponsePtr response = + mojom::PaymentMethodChangeResponse::New(); + response->error = details->error; + response->stringified_payment_method_errors = + details->stringified_payment_method_errors; -namespace payments { + if (details->total) + response->total = details->total->amount.Clone(); + + if (!details->modifiers) + return response; + + response->modifiers = std::vector<mojom::PaymentHandlerModifierPtr>(); + + for (const auto& merchant : *details->modifiers) { + if (!invoked_app.IsValidForPaymentMethodIdentifier( + merchant->method_data->supported_method)) { + continue; + } + + mojom::PaymentHandlerModifierPtr mod = mojom::PaymentHandlerModifier::New(); + mod->method_data = mojom::PaymentHandlerMethodData::New(); + mod->method_data->method_name = merchant->method_data->supported_method; + mod->method_data->stringified_data = + merchant->method_data->stringified_data; + + if (merchant->total) + mod->total = merchant->total->amount.Clone(); + + response->modifiers->emplace_back(std::move(mod)); + } + + return response; +} + +} // namespace PaymentRequest::PaymentRequest( content::RenderFrameHost* render_frame_host, @@ -54,6 +93,7 @@ display_manager_(display_manager), display_handle_(nullptr), binding_(this, std::move(request)), + payment_handler_host_binding_(this), top_level_origin_(url_formatter::FormatUrlForSecurityDisplay( web_contents_->GetLastCommittedURL())), frame_origin_(url_formatter::FormatUrlForSecurityDisplay( @@ -80,7 +120,7 @@ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); if (is_initialized_) { - log_.Error("Attempted initialization twice"); + log_.Error(errors::kAttemptedInitializationTwice); OnConnectionTerminated(); return; } @@ -90,7 +130,7 @@ const GURL last_committed_url = delegate_->GetLastCommittedURL(); if (!OriginSecurityChecker::IsOriginSecure(last_committed_url)) { - log_.Error("Not in a secure origin"); + log_.Error(errors::kNotInASecureOrigin); OnConnectionTerminated(); return; } @@ -99,22 +139,19 @@ OriginSecurityChecker::IsSchemeCryptographic(last_committed_url) || OriginSecurityChecker::IsOriginLocalhostOrFile(last_committed_url); if (!allowed_origin) { - log_.Error( - "Only localhost, file://, and cryptographic scheme origins allowed"); + log_.Error(errors::kProhibitedOrigin); } bool invalid_ssl = OriginSecurityChecker::IsSchemeCryptographic(last_committed_url) && !delegate_->IsSslCertificateValid(); if (invalid_ssl) { - log_.Error("SSL certificate is not valid."); + log_.Error(errors::kInvalidSslCertificate); } if (!allowed_origin || invalid_ssl) { // Intentionally don't set |spec_| and |state_|, so the UI is never shown. - log_.Error( - "No UI will be shown. CanMakePayment will always return false. " - "Show will be rejected with NotSupportedError."); + log_.Error(errors::kProhibitedOriginOrInvalidSslExplanation); return; } @@ -126,7 +163,7 @@ } if (!details->total) { - log_.Error("Missing total"); + log_.Error(errors::kTotalRequired); OnConnectionTerminated(); return; } @@ -166,13 +203,13 @@ void PaymentRequest::Show(bool is_user_gesture, bool wait_for_updated_details) { if (!IsInitialized()) { - log_.Error("Attempted show without initialization"); + log_.Error(errors::kCannotShowWithoutInit); OnConnectionTerminated(); return; } if (is_show_called_) { - log_.Error("Attempted show twice"); + log_.Error(errors::kCannotShowTwice); OnConnectionTerminated(); return; } @@ -182,7 +219,7 @@ // A tab can display only one PaymentRequest UI at a time. display_handle_ = display_manager_->TryShow(delegate_.get()); if (!display_handle_) { - log_.Error("A PaymentRequest UI is already showing"); + log_.Error(errors::kAnotherUiShowing); journey_logger_.SetNotShown( JourneyLogger::NOT_SHOWN_REASON_CONCURRENT_REQUESTS); client_->OnError(mojom::PaymentErrorReason::ALREADY_SHOWING); @@ -191,7 +228,7 @@ } if (!delegate_->IsBrowserWindowActive()) { - log_.Error("Cannot show PaymentRequest UI in a background tab"); + log_.Error(errors::kCannotShowInBackgroundTab); journey_logger_.SetNotShown(JourneyLogger::NOT_SHOWN_REASON_OTHER); client_->OnError(mojom::PaymentErrorReason::USER_CANCEL); OnConnectionTerminated(); @@ -222,13 +259,13 @@ void PaymentRequest::Retry(mojom::PaymentValidationErrorsPtr errors) { if (!IsInitialized()) { - log_.Error("Attempted retry without initialization"); + log_.Error(errors::kCannotRetryWithoutInit); OnConnectionTerminated(); return; } if (!IsThisPaymentRequestShowing()) { - log_.Error("Attempted retry without show"); + log_.Error(errors::kCannotRetryWithoutShow); OnConnectionTerminated(); return; } @@ -248,13 +285,13 @@ void PaymentRequest::UpdateWith(mojom::PaymentDetailsPtr details) { if (!IsInitialized()) { - log_.Error("Attempted updateWith without initialization"); + log_.Error(errors::kCannotUpdateWithoutInit); OnConnectionTerminated(); return; } if (!IsThisPaymentRequestShowing()) { - log_.Error("Attempted updateWith without show"); + log_.Error(errors::kCannotUpdateWithoutShow); OnConnectionTerminated(); return; } @@ -274,6 +311,13 @@ return; } + if (change_payment_method_callback_) { + DCHECK(state()->selected_instrument()); + std::move(change_payment_method_callback_) + .Run(ConvertToPaymentMethodChangeResponse( + details, *state()->selected_instrument())); + } + bool is_resolving_promise_passed_into_show_method = !spec_->IsInitialized(); spec_->UpdateWith(std::move(details)); @@ -293,29 +337,34 @@ // response to a shipping address update event, so the error messages cannot // be more verbose. if (!IsInitialized()) { - log_.Error("Not initialized"); + log_.Error(errors::kNotInitialized); OnConnectionTerminated(); return; } if (!IsThisPaymentRequestShowing()) { - log_.Error("Not shown"); + log_.Error(errors::kNotShown); OnConnectionTerminated(); return; } spec_->RecomputeSpecForDetails(); + + if (change_payment_method_callback_) { + std::move(change_payment_method_callback_) + .Run(mojom::PaymentMethodChangeResponse::New()); + } } void PaymentRequest::Abort() { if (!IsInitialized()) { - log_.Error("Attempted abort without initialization"); + log_.Error(errors::kCannotAbortWithoutInit); OnConnectionTerminated(); return; } if (!IsThisPaymentRequestShowing()) { - log_.Error("Attempted abort without show"); + log_.Error(errors::kCannotAbortWithoutShow); OnConnectionTerminated(); return; } @@ -340,13 +389,13 @@ void PaymentRequest::Complete(mojom::PaymentComplete result) { if (!IsInitialized()) { - log_.Error("Attempted complete without initialization"); + log_.Error(errors::kCannotCompleteWithoutInit); OnConnectionTerminated(); return; } if (!IsThisPaymentRequestShowing()) { - log_.Error("Attempted complete without show"); + log_.Error(errors::kCannotAbortWithoutShow); OnConnectionTerminated(); return; } @@ -371,7 +420,7 @@ void PaymentRequest::CanMakePayment(bool legacy_mode) { if (!IsInitialized()) { - log_.Error("Attempted canMakePayment without initialization"); + log_.Error(errors::kCannotCallCanMakePaymentWithoutInit); OnConnectionTerminated(); return; } @@ -394,7 +443,7 @@ void PaymentRequest::HasEnrolledInstrument(bool per_method_quota) { if (!IsInitialized()) { - log_.Error("Attempted hasEnrolledInstrument without initialization"); + log_.Error(errors::kCannotCallHasEnrolledInstrumentWithoutInit); OnConnectionTerminated(); return; } @@ -415,6 +464,39 @@ } } +void PaymentRequest::ChangePaymentMethod( + mojom::PaymentHandlerMethodDataPtr method_data, + mojom::PaymentHandlerHost::ChangePaymentMethodCallback callback) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + if (!state_ || !state_->IsPaymentAppInvoked() || !client_) { + mojom::PaymentMethodChangeResponsePtr response = + mojom::PaymentMethodChangeResponse::New(); + response->error = errors::kInvalidState; + std::move(callback).Run(std::move(response)); + return; + } + + if (!method_data) { + mojom::PaymentMethodChangeResponsePtr response = + mojom::PaymentMethodChangeResponse::New(); + response->error = errors::kMethodDataRequired; + std::move(callback).Run(std::move(response)); + return; + } + + if (method_data->method_name.empty()) { + mojom::PaymentMethodChangeResponsePtr response = + mojom::PaymentMethodChangeResponse::New(); + response->error = errors::kMethodNameRequired; + std::move(callback).Run(std::move(response)); + return; + } + + change_payment_method_callback_ = std::move(callback); + client_->OnPaymentMethodChange(method_data->method_name, + method_data->stringified_data); +} + void PaymentRequest::AreRequestedMethodsSupportedCallback( bool methods_supported) { if (methods_supported) { @@ -507,6 +589,7 @@ // We close all bindings and ask to be destroyed. client_.reset(); binding_.Close(); + payment_handler_host_binding_.Close(); if (observer_for_testing_) observer_for_testing_->OnConnectionTerminated(); manager_->DestroyRequest(this); @@ -527,6 +610,7 @@ // the binding and the dialog, and ask to be deleted. client_.reset(); binding_.Close(); + payment_handler_host_binding_.Close(); delegate_->CloseDialog(); if (observer_for_testing_) observer_for_testing_->OnConnectionTerminated(); @@ -548,6 +632,7 @@ break; case PaymentInstrument::Type::SERVICE_WORKER_APP: selected_event = JourneyLogger::Event::EVENT_SELECTED_OTHER; + BindPaymentHandlerHost(); break; case PaymentInstrument::Type::NATIVE_MOBILE_APP: NOTREACHED(); @@ -570,6 +655,24 @@ return delegate_->IsIncognito(); } +void PaymentRequest::BindPaymentHandlerHost() { + mojom::PaymentHandlerHostPtrInfo payment_handler_host; + payment_handler_host_binding_.Close(); + payment_handler_host_binding_.Bind(mojo::MakeRequest(&payment_handler_host)); + + // Connection error handler can be set only after the Bind() call. + payment_handler_host_binding_.set_connection_error_handler( + base::BindOnce(&PaymentRequest::OnPaymentHandlerConnectionTerminated, + weak_ptr_factory_.GetWeakPtr())); + + static_cast<ServiceWorkerPaymentInstrument*>(state()->selected_instrument()) + ->set_payment_handler_host(std::move(payment_handler_host)); +} + +void PaymentRequest::OnPaymentHandlerConnectionTerminated() { + payment_handler_host_binding_.Close(); +} + void PaymentRequest::RecordFirstAbortReason( JourneyLogger::AbortReason abort_reason) { if (!has_recorded_completion_) {
diff --git a/components/payments/content/payment_request.h b/components/payments/content/payment_request.h index 4394b82..381b8b22 100644 --- a/components/payments/content/payment_request.h +++ b/components/payments/content/payment_request.h
@@ -17,6 +17,7 @@ #include "components/payments/core/journey_logger.h" #include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/bindings/interface_request.h" +#include "third_party/blink/public/mojom/payments/payment_handler_host.mojom.h" #include "third_party/blink/public/mojom/payments/payment_request.mojom.h" #include "url/gurl.h" @@ -37,6 +38,7 @@ // PaymentRequestSpec, and the current user selection state (and related data) // is stored in PaymentRequestSpec. class PaymentRequest : public mojom::PaymentRequest, + public mojom::PaymentHandlerHost, public PaymentRequestSpec::Observer, public PaymentRequestState::Delegate { public: @@ -77,6 +79,11 @@ void CanMakePayment(bool legacy_mode) override; void HasEnrolledInstrument(bool per_method_quota) override; + // mojom::PaymentHandlerHost + void ChangePaymentMethod( + mojom::PaymentHandlerMethodDataPtr method_data, + mojom::PaymentHandlerHost::ChangePaymentMethodCallback callback) override; + // PaymentRequestSpec::Observer: void OnSpecUpdated() override {} @@ -129,6 +136,13 @@ } private: + // Binds itself as the payment handler host for the selected service worker + // payment instrument. + void BindPaymentHandlerHost(); + + // Called when the mojo pipe to the payment handler closed. + void OnPaymentHandlerConnectionTerminated(); + // Returns true after init() has been called and the mojo connection has been // established. If the mojo connection gets later disconnected, this will // returns false. @@ -182,6 +196,15 @@ std::unique_ptr<PaymentRequestSpec> spec_; std::unique_ptr<PaymentRequestState> state_; + // The end-point for the payment handler renderer process to call into the + // browser process. + mojo::Binding<mojom::PaymentHandlerHost> payment_handler_host_binding_; + + // Payment handler's callback to invoke after merchant responds to the + // "payment method change" event. + mojom::PaymentHandlerHost::ChangePaymentMethodCallback + change_payment_method_callback_; + // The RFC 6454 origin of the top level frame that has invoked PaymentRequest // API. This is what the user sees in the address bar. const GURL top_level_origin_;
diff --git a/components/payments/content/service_worker_payment_instrument.cc b/components/payments/content/service_worker_payment_instrument.cc index 786dfb82..dafe8e9 100644 --- a/components/payments/content/service_worker_payment_instrument.cc +++ b/components/payments/content/service_worker_payment_instrument.cc
@@ -284,6 +284,8 @@ } } + event_data->payment_handler_host = std::move(payment_handler_host_); + return event_data; } @@ -351,7 +353,7 @@ if (needs_installation_) return installable_enabled_method_ == method; - if (!base::ContainsValue(stored_payment_app_info_->enabled_methods, method)) + if (!IsValidForPaymentMethodIdentifier(method)) return false; // Return true if 'basic-card' is not the only matched payment method. This @@ -409,6 +411,13 @@ return i < stored_payment_app_info_->capabilities.size(); } +bool ServiceWorkerPaymentInstrument::IsValidForPaymentMethodIdentifier( + const std::string& payment_method_identifier) const { + DCHECK(!needs_installation_); + return base::ContainsValue(stored_payment_app_info_->enabled_methods, + payment_method_identifier); +} + gfx::ImageSkia ServiceWorkerPaymentInstrument::icon_image_skia() const { return icon_image_; }
diff --git a/components/payments/content/service_worker_payment_instrument.h b/components/payments/content/service_worker_payment_instrument.h index 7dbb9e47..dcb4da8b 100644 --- a/components/payments/content/service_worker_payment_instrument.h +++ b/components/payments/content/service_worker_payment_instrument.h
@@ -10,6 +10,7 @@ #include "components/payments/core/payment_instrument.h" #include "content/public/browser/stored_payment_app.h" #include "third_party/blink/public/mojom/payments/payment_app.mojom.h" +#include "third_party/blink/public/mojom/payments/payment_handler_host.mojom.h" #include "third_party/blink/public/mojom/payments/payment_request.mojom.h" namespace content { @@ -76,8 +77,15 @@ bool supported_types_specified, const std::set<autofill::CreditCard::CardType>& supported_types) const override; + bool IsValidForPaymentMethodIdentifier( + const std::string& payment_method_identifier) const override; gfx::ImageSkia icon_image_skia() const override; + void set_payment_handler_host( + mojom::PaymentHandlerHostPtrInfo payment_handler_host) { + payment_handler_host_ = std::move(payment_handler_host); + } + private: friend class ServiceWorkerPaymentInstrumentTest; @@ -103,6 +111,8 @@ // Weak pointer that must outlive this object. PaymentRequestDelegate* payment_request_delegate_; + mojom::PaymentHandlerHostPtrInfo payment_handler_host_; + // PaymentAppProvider::CanMakePayment result of this payment instrument. bool can_make_payment_result_; bool has_enrolled_instrument_result_;
diff --git a/components/payments/core/BUILD.gn b/components/payments/core/BUILD.gn index 0585f46e..d34b273 100644 --- a/components/payments/core/BUILD.gn +++ b/components/payments/core/BUILD.gn
@@ -86,6 +86,13 @@ ] } +jumbo_static_library("error_strings") { + sources = [ + "error_strings.cc", + "error_strings.h", + ] +} + jumbo_static_library("test_support") { testonly = true sources = [
diff --git a/components/payments/core/autofill_payment_instrument.cc b/components/payments/core/autofill_payment_instrument.cc index 09ca141..8195a87 100644 --- a/components/payments/core/autofill_payment_instrument.cc +++ b/components/payments/core/autofill_payment_instrument.cc
@@ -126,8 +126,7 @@ const std::set<std::string>& supported_networks, bool supported_types_specified, const std::set<autofill::CreditCard::CardType>& supported_types) const { - // This instrument only matches basic-card. - if (method != "basic-card") + if (!IsValidForPaymentMethodIdentifier(method)) return false; // If supported_types is not specified and this instrument matches the method, @@ -158,6 +157,12 @@ return true; } +bool AutofillPaymentInstrument::IsValidForPaymentMethodIdentifier( + const std::string& payment_method_identifier) const { + // This instrument only matches basic-card. + return payment_method_identifier == "basic-card"; +} + void AutofillPaymentInstrument::OnFullCardRequestSucceeded( const autofill::payments::FullCardRequest& /* full_card_request */, const autofill::CreditCard& card,
diff --git a/components/payments/core/autofill_payment_instrument.h b/components/payments/core/autofill_payment_instrument.h index b1859e6..c2dbd1a 100644 --- a/components/payments/core/autofill_payment_instrument.h +++ b/components/payments/core/autofill_payment_instrument.h
@@ -54,6 +54,8 @@ bool supported_types_specified, const std::set<autofill::CreditCard::CardType>& supported_types) const override; + bool IsValidForPaymentMethodIdentifier( + const std::string& payment_method_identifier) const override; // autofill::payments::FullCardRequest::ResultDelegate: void OnFullCardRequestSucceeded(
diff --git a/components/payments/core/error_strings.cc b/components/payments/core/error_strings.cc new file mode 100644 index 0000000..a877d771 --- /dev/null +++ b/components/payments/core/error_strings.cc
@@ -0,0 +1,47 @@ +// 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/payments/core/error_strings.h" + +namespace payments { +namespace errors { + +// Please keep the list alphabetized. + +const char* kAnotherUiShowing = "A PaymentRequest UI is already showing."; +const char* kAttemptedInitializationTwice = "Attempted initialization twice."; +const char* kCannotAbortWithoutInit = "Attempted abort without initialization."; +const char* kCannotAbortWithoutShow = "Attempted abort without show."; +const char* kCannotCallCanMakePaymentWithoutInit = + "Attempted canMakePayment without initialization."; +const char* kCannotCallHasEnrolledInstrumentWithoutInit = + "Attempted hasEnrolledInstrument without initialization."; +const char* kCannotCompleteWithoutInit = + "Attempted complete without initialization."; +const char* kCannotCompleteWithoutShow = "Attempted complete without show."; +const char* kCannotRetryWithoutInit = "Attempted retry without initialization."; +const char* kCannotRetryWithoutShow = "Attempted retry without show."; +const char* kCannotShowInBackgroundTab = + "Cannot show PaymentRequest UI in a background tab."; +const char* kCannotShowTwice = "Attempted show twice."; +const char* kCannotShowWithoutInit = "Attempted show without initialization."; +const char* kCannotUpdateWithoutInit = + "Attempted updateWith without initialization."; +const char* kCannotUpdateWithoutShow = "Attempted updateWith without show."; +const char* kInvalidSslCertificate = "SSL certificate is not valid."; +const char* kInvalidState = "Invalid state."; +const char* kMethodDataRequired = "Method data required."; +const char* kMethodNameRequired = "Method name required."; +const char* kNotInASecureOrigin = "Not in a secure origin."; +const char* kNotInitialized = "Not initialized."; +const char* kNotShown = "Not shown."; +const char* kProhibitedOrigin = + "Only localhost, file://, and cryptographic scheme origins allowed."; +const char* kProhibitedOriginOrInvalidSslExplanation = + "No UI will be shown. CanMakePayment and hasEnrolledInstrument will always " + "return false. Show will be rejected with NotSupportedError."; +const char* kTotalRequired = "Total required."; + +} // namespace errors +} // namespace payments
diff --git a/components/payments/core/error_strings.h b/components/payments/core/error_strings.h new file mode 100644 index 0000000..19d7256 --- /dev/null +++ b/components/payments/core/error_strings.h
@@ -0,0 +1,98 @@ +// 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_PAYMENTS_CORE_ERROR_STRINGS_H_ +#define COMPONENTS_PAYMENTS_CORE_ERROR_STRINGS_H_ + +namespace payments { +namespace errors { + +// Please keep the list alphabetized. + +// Only a single PaymentRequest UI can be displayed at a time. +extern const char* kAnotherUiShowing; + +// Mojo call PaymentRequest::Init() must precede PaymentRequest::Show(). +extern const char* kAttemptedInitializationTwice; + +// Mojo call PaymentRequest::Init() must precede PaymentRequest::Abort(). +extern const char* kCannotAbortWithoutInit; + +// Mojo call PaymentRequest::Show() must precede PaymentRequest::Abort(). +extern const char* kCannotAbortWithoutShow; + +// Mojo call PaymentRequest::Init() must precede +// PaymentRequest::CanMakePayment(). +extern const char* kCannotCallCanMakePaymentWithoutInit; + +// Mojo call PaymentRequest::Init() must precede +// PaymentRequest::HasEnrolledInstrument(). +extern const char* kCannotCallHasEnrolledInstrumentWithoutInit; + +// Mojo call PaymentRequest::Init() must precede PaymentRequest::Complete(). +extern const char* kCannotCompleteWithoutInit; + +// Mojo call PaymentRequest::Show() must precede PaymentRequest::Complete(). +extern const char* kCannotCompleteWithoutShow; + +// Mojo call PaymentRequest::Init() must precede PaymentRequest::Retry(). +extern const char* kCannotRetryWithoutInit; + +// Mojo call PaymentRequest::Show() must precede PaymentRequest::Retry(). +extern const char* kCannotRetryWithoutShow; + +// Payment Request UI must be shown in the foreground tab, as a result of user +// interaction. +extern const char* kCannotShowInBackgroundTab; + +// Mojo call PaymentRequest::Show() cannot happen more than once per Mojo pipe. +extern const char* kCannotShowTwice; + +// Mojo call PaymentRequest::Init() must precede PaymentRequest::Show(). +extern const char* kCannotShowWithoutInit; + +// Mojo call PaymentRequest::Init() must precede PaymentRequest::UpdateWith(). +extern const char* kCannotUpdateWithoutInit; + +// Mojo call PaymentRequest::Show() must precede PaymentRequest::UpdateWith(). +extern const char* kCannotUpdateWithoutShow; + +// Chrome refuses to provide any payment information to a website with an +// invalid SSL certificate. +extern const char* kInvalidSslCertificate; + +// Used when an invalid state is encountered generically. +extern const char* kInvalidState; + +// Used when the {"supportedMethods": "", data: {}} is required, but not +// provided. +extern const char* kMethodDataRequired; + +// Used when non-empty "supportedMethods": "" is required, but not provided. +extern const char* kMethodNameRequired; + +// The PaymentRequest API is available only on secure origins. +extern const char* kNotInASecureOrigin; + +// Used when PaymentRequest::Init() has not been called, but should have been. +extern const char* kNotInitialized; + +// Used when PaymentRequest::Show() has not been called, but should have been. +extern const char* kNotShown; + +// Chrome provides payment information only to a whitelist of origin types. +extern const char* kProhibitedOrigin; + +// A long form explanation of Chrome's behavior in the case of kProhibitedOrigin +// or kInvalidSslCertificate error. +extern const char* kProhibitedOriginOrInvalidSslExplanation; + +// Used when "total": {"label": "Total", "amount": {"currency": "USD", "value": +// "0.01"}} is required, bot not provided. +extern const char* kTotalRequired; + +} // namespace errors +} // namespace payments + +#endif // COMPONENTS_PAYMENTS_CORE_ERROR_STRINGS_H_
diff --git a/components/payments/core/payment_instrument.h b/components/payments/core/payment_instrument.h index d2a6863f..497479277 100644 --- a/components/payments/core/payment_instrument.h +++ b/components/payments/core/payment_instrument.h
@@ -64,7 +64,11 @@ virtual gfx::ImageSkia icon_image_skia() const; // Returns true if this payment instrument can be used to fulfill a request - // specifying |method| as supported method of payment, false otherwise. + // specifying |method| as supported method of payment, false otherwise. The + // parsed basic-card specific data (supported_networks, supported_types, etc) + // is relevant only for the AutofillPaymentInstrument, which runs inside of + // the browser process and thus should not be parsing untrusted JSON strings + // from the renderer. virtual bool IsValidForModifier( const std::string& method, bool supported_networks_specified, @@ -73,6 +77,11 @@ const std::set<autofill::CreditCard::CardType>& supported_types) const = 0; + // Returns true if this payment instrument can handle payments for the given + // |payment_method_identifier|. + virtual bool IsValidForPaymentMethodIdentifier( + const std::string& payment_method_identifier) const = 0; + int icon_resource_id() const { return icon_resource_id_; } Type type() { return type_; }
diff --git a/components/sync/BUILD.gn b/components/sync/BUILD.gn index 3074e3e..d1ad6c0 100644 --- a/components/sync/BUILD.gn +++ b/components/sync/BUILD.gn
@@ -16,9 +16,7 @@ } # Note: This target intentionally doesn't include test_support_fake_server - -# targets that need the fake server should depend on it explicitly. It also -# doesn't include test_support_user_events, which should be moved out of -# components/sync entirely. +# targets that need the fake server should depend on it explicitly. group("test_support") { testonly = true public_deps = [ @@ -433,24 +431,6 @@ configs += [ "//build/config/compiler:wexit_time_destructors" ] } -static_library("test_support_user_events") { - testonly = true - sources = [ - "user_events/fake_user_event_service.cc", - "user_events/fake_user_event_service.h", - ] - - public_deps = [ - "//components/sync/base:test_support", - ] - - deps = [ - ":sync", - ":test_support_model", - "//components/sync/user_events", - ] -} - static_library("test_support_engine") { testonly = true sources = [ @@ -672,8 +652,6 @@ "syncable/syncable_enum_conversions_unittest.cc", "syncable/syncable_id_unittest.cc", "syncable/syncable_unittest.cc", - "user_events/user_event_service_impl_unittest.cc", - "user_events/user_event_sync_bridge_unittest.cc", ] configs += [ "//build/config:precompiled_headers" ] @@ -681,16 +659,12 @@ data = [ "//chrome/test/data/sync/", "//net/tools/testserver/", - "//third_party/pyftpdlib/", - "//third_party/pywebsocket/src/mod_pywebsocket/", - "//third_party/tlslite/", ] deps = [ ":sync", ":test_support_engine", ":test_support_model", - ":test_support_user_events", "//base", "//base/test:test_support", "//components/invalidation/impl", @@ -701,7 +675,6 @@ "//components/sync/device_info:unit_tests", "//components/sync/driver:test_support", "//components/sync/js:test_support", - "//components/sync/user_events", "//components/sync_preferences", "//components/sync_preferences:test_support", "//components/version_info",
diff --git a/components/sync/user_events/BUILD.gn b/components/sync/user_events/BUILD.gn deleted file mode 100644 index 424901e..0000000 --- a/components/sync/user_events/BUILD.gn +++ /dev/null
@@ -1,31 +0,0 @@ -# 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("//build/buildflag_header.gni") -import("//build/config/features.gni") -import("//build/config/jumbo.gni") - -jumbo_static_library("user_events") { - sources = [ - "no_op_user_event_service.cc", - "no_op_user_event_service.h", - "user_event_model_type_controller.cc", - "user_event_model_type_controller.h", - "user_event_service.h", - "user_event_service_impl.cc", - "user_event_service_impl.h", - "user_event_sync_bridge.cc", - "user_event_sync_bridge.h", - ] - - public_deps = [ - "//base", - "//components/keyed_service/core", - "//components/sync", - "//components/sync/protocol", - ] - deps = [ - "//components/signin/core/browser:shared", - ] -}
diff --git a/components/sync/user_events/DEPS b/components/sync/user_events/DEPS deleted file mode 100644 index d55d81f..0000000 --- a/components/sync/user_events/DEPS +++ /dev/null
@@ -1,16 +0,0 @@ -include_rules = [ - "+components/keyed_service/core", - "+components/signin/core/browser", - # Use identity_manager.h instead of the below files; - # see https://groups.google.com/a/chromium.org/d/msg/chromium-dev/dgFLuxqZt1o/iEqkyoQQBwAJ for help and info. - "-components/signin/core/browser/fake_profile_oauth2_token_service.h", - "-components/signin/core/browser/profile_oauth2_token_service.h", - "-components/signin/core/browser/fake_signin_manager.h", - "-components/signin/core/browser/signin_manager.h", - "-components/signin/core/browser/signin_manager_base.h", - "+components/sync/base", - "+components/sync/driver", - "+components/sync/model", - "+components/sync/protocol", - "+components/variations", -]
diff --git a/components/sync_sessions/BUILD.gn b/components/sync_sessions/BUILD.gn index 7b639087..eff705de 100644 --- a/components/sync_sessions/BUILD.gn +++ b/components/sync_sessions/BUILD.gn
@@ -61,6 +61,7 @@ "//components/history/core/browser", "//components/keyed_service/core", "//components/prefs", + "//components/sync_user_events", "//components/variations", "//components/version_info", "//google_apis",
diff --git a/components/sync_sessions/DEPS b/components/sync_sessions/DEPS index 50c8e70..17e9019 100644 --- a/components/sync_sessions/DEPS +++ b/components/sync_sessions/DEPS
@@ -6,6 +6,7 @@ "+components/prefs", "+components/sessions", "+components/sync", + "+components/sync_user_events", "+components/variations", "+components/version_info", "+google_apis",
diff --git a/components/sync_sessions/sessions_global_id_mapper.h b/components/sync_sessions/sessions_global_id_mapper.h index 58b5b391..1eb8566e 100644 --- a/components/sync_sessions/sessions_global_id_mapper.h +++ b/components/sync_sessions/sessions_global_id_mapper.h
@@ -9,7 +9,7 @@ #include <vector> #include "base/time/time.h" -#include "components/sync/user_events/global_id_mapper.h" +#include "components/sync_user_events/global_id_mapper.h" namespace sync_sessions {
diff --git a/components/sync_user_events/BUILD.gn b/components/sync_user_events/BUILD.gn new file mode 100644 index 0000000..f3ff246 --- /dev/null +++ b/components/sync_user_events/BUILD.gn
@@ -0,0 +1,61 @@ +# 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("//build/buildflag_header.gni") +import("//build/config/features.gni") +import("//build/config/jumbo.gni") + +jumbo_static_library("sync_user_events") { + sources = [ + "global_id_mapper.h", + "no_op_user_event_service.cc", + "no_op_user_event_service.h", + "user_event_model_type_controller.cc", + "user_event_model_type_controller.h", + "user_event_service.h", + "user_event_service_impl.cc", + "user_event_service_impl.h", + "user_event_sync_bridge.cc", + "user_event_sync_bridge.h", + ] + + public_deps = [ + "//base", + "//components/keyed_service/core", + "//components/sync", + "//components/sync/protocol", + ] + deps = [ + "//components/signin/core/browser:shared", + ] +} + +static_library("test_support") { + testonly = true + sources = [ + "fake_user_event_service.cc", + "fake_user_event_service.h", + ] + + public_deps = [ + ":sync_user_events", + "//components/sync:test_support", + ] +} + +source_set("unit_tests") { + testonly = true + sources = [ + "user_event_service_impl_unittest.cc", + "user_event_sync_bridge_unittest.cc", + ] + + configs += [ "//build/config:precompiled_headers" ] + + deps = [ + ":sync_user_events", + ":test_support", + "//base/test:test_support", + ] +}
diff --git a/components/sync_user_events/DEPS b/components/sync_user_events/DEPS new file mode 100644 index 0000000..53d4a2c4 --- /dev/null +++ b/components/sync_user_events/DEPS
@@ -0,0 +1,7 @@ +include_rules = [ + "+components/keyed_service/core", + "+components/sync/base", + "+components/sync/driver", + "+components/sync/model", + "+components/sync/protocol", +]
diff --git a/components/sync/user_events/fake_user_event_service.cc b/components/sync_user_events/fake_user_event_service.cc similarity index 93% rename from components/sync/user_events/fake_user_event_service.cc rename to components/sync_user_events/fake_user_event_service.cc index 6a74efc..cdaddc8 100644 --- a/components/sync/user_events/fake_user_event_service.cc +++ b/components/sync_user_events/fake_user_event_service.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 "components/sync/user_events/fake_user_event_service.h" +#include "components/sync_user_events/fake_user_event_service.h" + #include "components/sync/model/fake_model_type_change_processor.h" using sync_pb::UserEventSpecifics;
diff --git a/components/sync/user_events/fake_user_event_service.h b/components/sync_user_events/fake_user_event_service.h similarity index 96% rename from components/sync/user_events/fake_user_event_service.h rename to components/sync_user_events/fake_user_event_service.h index cbd97a7..f0e7bc9 100644 --- a/components/sync/user_events/fake_user_event_service.h +++ b/components/sync_user_events/fake_user_event_service.h
@@ -12,7 +12,7 @@ #include "base/macros.h" #include "components/sync/model/fake_model_type_sync_bridge.h" #include "components/sync/protocol/user_event_specifics.pb.h" -#include "components/sync/user_events/user_event_service.h" +#include "components/sync_user_events/user_event_service.h" namespace syncer {
diff --git a/components/sync/user_events/global_id_mapper.h b/components/sync_user_events/global_id_mapper.h similarity index 100% rename from components/sync/user_events/global_id_mapper.h rename to components/sync_user_events/global_id_mapper.h
diff --git a/components/sync/user_events/no_op_user_event_service.cc b/components/sync_user_events/no_op_user_event_service.cc similarity index 90% rename from components/sync/user_events/no_op_user_event_service.cc rename to components/sync_user_events/no_op_user_event_service.cc index 29394de..78cb011a 100644 --- a/components/sync/user_events/no_op_user_event_service.cc +++ b/components/sync_user_events/no_op_user_event_service.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/sync/user_events/no_op_user_event_service.h" +#include "components/sync_user_events/no_op_user_event_service.h" #include "base/memory/weak_ptr.h"
diff --git a/components/sync/user_events/no_op_user_event_service.h b/components/sync_user_events/no_op_user_event_service.h similarity index 94% rename from components/sync/user_events/no_op_user_event_service.h rename to components/sync_user_events/no_op_user_event_service.h index d976998..0ae48ff 100644 --- a/components/sync/user_events/no_op_user_event_service.h +++ b/components/sync_user_events/no_op_user_event_service.h
@@ -9,7 +9,7 @@ #include <string> #include "base/macros.h" -#include "components/sync/user_events/user_event_service.h" +#include "components/sync_user_events/user_event_service.h" namespace syncer {
diff --git a/components/sync/user_events/user_event_model_type_controller.cc b/components/sync_user_events/user_event_model_type_controller.cc similarity index 95% rename from components/sync/user_events/user_event_model_type_controller.cc rename to components/sync_user_events/user_event_model_type_controller.cc index 53734b95..d1e615d 100644 --- a/components/sync/user_events/user_event_model_type_controller.cc +++ b/components/sync_user_events/user_event_model_type_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 "components/sync/user_events/user_event_model_type_controller.h" +#include "components/sync_user_events/user_event_model_type_controller.h" #include <utility>
diff --git a/components/sync/user_events/user_event_model_type_controller.h b/components/sync_user_events/user_event_model_type_controller.h similarity index 100% rename from components/sync/user_events/user_event_model_type_controller.h rename to components/sync_user_events/user_event_model_type_controller.h
diff --git a/components/sync/user_events/user_event_service.h b/components/sync_user_events/user_event_service.h similarity index 100% rename from components/sync/user_events/user_event_service.h rename to components/sync_user_events/user_event_service.h
diff --git a/components/sync/user_events/user_event_service_impl.cc b/components/sync_user_events/user_event_service_impl.cc similarity index 91% rename from components/sync/user_events/user_event_service_impl.cc rename to components/sync_user_events/user_event_service_impl.cc index c098acd..1749f86 100644 --- a/components/sync/user_events/user_event_service_impl.cc +++ b/components/sync_user_events/user_event_service_impl.cc
@@ -2,16 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/sync/user_events/user_event_service_impl.h" +#include "components/sync_user_events/user_event_service_impl.h" #include <utility> #include "base/rand_util.h" #include "base/stl_util.h" #include "base/time/time.h" -#include "components/sync/driver/sync_driver_switches.h" -#include "components/sync/driver/sync_user_settings.h" -#include "components/sync/user_events/user_event_sync_bridge.h" +#include "components/sync_user_events/user_event_sync_bridge.h" using sync_pb::UserEventSpecifics;
diff --git a/components/sync/user_events/user_event_service_impl.h b/components/sync_user_events/user_event_service_impl.h similarity index 96% rename from components/sync/user_events/user_event_service_impl.h rename to components/sync_user_events/user_event_service_impl.h index 35154c4..91e6182 100644 --- a/components/sync/user_events/user_event_service_impl.h +++ b/components/sync_user_events/user_event_service_impl.h
@@ -12,7 +12,7 @@ #include "base/memory/weak_ptr.h" #include "components/keyed_service/core/keyed_service.h" #include "components/sync/protocol/user_event_specifics.pb.h" -#include "components/sync/user_events/user_event_service.h" +#include "components/sync_user_events/user_event_service.h" namespace syncer {
diff --git a/components/sync/user_events/user_event_service_impl_unittest.cc b/components/sync_user_events/user_event_service_impl_unittest.cc similarity index 96% rename from components/sync/user_events/user_event_service_impl_unittest.cc rename to components/sync_user_events/user_event_service_impl_unittest.cc index c86e054..a0ca689 100644 --- a/components/sync/user_events/user_event_service_impl_unittest.cc +++ b/components/sync_user_events/user_event_service_impl_unittest.cc
@@ -2,19 +2,18 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/sync/user_events/user_event_service_impl.h" +#include "components/sync_user_events/user_event_service_impl.h" #include <utility> #include <vector> #include "base/test/scoped_task_environment.h" #include "components/sync/base/model_type.h" -#include "components/sync/driver/sync_driver_switches.h" #include "components/sync/driver/test_sync_service.h" #include "components/sync/model/mock_model_type_change_processor.h" #include "components/sync/model/model_type_store_test_util.h" #include "components/sync/protocol/sync.pb.h" -#include "components/sync/user_events/user_event_sync_bridge.h" +#include "components/sync_user_events/user_event_sync_bridge.h" #include "testing/gtest/include/gtest/gtest.h" using sync_pb::UserEventSpecifics;
diff --git a/components/sync/user_events/user_event_sync_bridge.cc b/components/sync_user_events/user_event_sync_bridge.cc similarity index 97% rename from components/sync/user_events/user_event_sync_bridge.cc rename to components/sync_user_events/user_event_sync_bridge.cc index 0b985e8..e6ff61d 100644 --- a/components/sync/user_events/user_event_sync_bridge.cc +++ b/components/sync_user_events/user_event_sync_bridge.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/sync/user_events/user_event_sync_bridge.h" +#include "components/sync_user_events/user_event_sync_bridge.h" #include <set> #include <utility> @@ -16,7 +16,6 @@ #include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "build/build_config.h" -#include "components/signin/core/browser/account_info.h" #include "components/sync/model/data_type_activation_request.h" #include "components/sync/model/entity_change.h" #include "components/sync/model/metadata_batch.h" @@ -25,8 +24,8 @@ namespace syncer { -using sync_pb::UserEventSpecifics; using sync_pb::ModelTypeState; +using sync_pb::UserEventSpecifics; using IdList = ModelTypeStore::IdList; using Record = ModelTypeStore::Record; using RecordList = ModelTypeStore::RecordList; @@ -73,8 +72,8 @@ .Run(USER_EVENTS, base::BindOnce(&UserEventSyncBridge::OnStoreCreated, weak_ptr_factory_.GetWeakPtr())); global_id_mapper_->AddGlobalIdChangeObserver( - base::Bind(&UserEventSyncBridge::HandleGlobalIdChange, - weak_ptr_factory_.GetWeakPtr())); + base::BindRepeating(&UserEventSyncBridge::HandleGlobalIdChange, + weak_ptr_factory_.GetWeakPtr())); } UserEventSyncBridge::~UserEventSyncBridge() = default;
diff --git a/components/sync/user_events/user_event_sync_bridge.h b/components/sync_user_events/user_event_sync_bridge.h similarity index 98% rename from components/sync/user_events/user_event_sync_bridge.h rename to components/sync_user_events/user_event_sync_bridge.h index a3300dc..0aed64668 100644 --- a/components/sync/user_events/user_event_sync_bridge.h +++ b/components/sync_user_events/user_event_sync_bridge.h
@@ -18,7 +18,7 @@ #include "components/sync/model/model_type_change_processor.h" #include "components/sync/model/model_type_store.h" #include "components/sync/model/model_type_sync_bridge.h" -#include "components/sync/user_events/global_id_mapper.h" +#include "components/sync_user_events/global_id_mapper.h" namespace syncer {
diff --git a/components/sync/user_events/user_event_sync_bridge_unittest.cc b/components/sync_user_events/user_event_sync_bridge_unittest.cc similarity index 99% rename from components/sync/user_events/user_event_sync_bridge_unittest.cc rename to components/sync_user_events/user_event_sync_bridge_unittest.cc index 599e110..ed11221 100644 --- a/components/sync/user_events/user_event_sync_bridge_unittest.cc +++ b/components/sync_user_events/user_event_sync_bridge_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 "components/sync/user_events/user_event_sync_bridge.h" +#include "components/sync_user_events/user_event_sync_bridge.h" #include <map> #include <set>
diff --git a/components/test/data/payments/change_payment_method.html b/components/test/data/payments/change_payment_method.html new file mode 100644 index 0000000..a7928001 --- /dev/null +++ b/components/test/data/payments/change_payment_method.html
@@ -0,0 +1,38 @@ +<!DOCTYPE html> +<!-- +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. +--> +<html lang="en"> + <head> + <meta charset="utf-8"> + <meta + name="viewport" + content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1"> + <title>Test For PaymentRequestEvent.changePaymentMethod()</title> + <link rel="stylesheet" type="text/css" href="style.css"> + </head> + <body> + <div> + <button onclick="install()" id="install">Install Service Worker</button> + </div> + <div> + <button onclick="test_no_handler()" id="test_no_handler"> + Test No Handler + </button> + </div> + <div> + <button onclick="test_reject()" id="test_reject">Test Rejection</button> + </div> + <div> + <button onclick="test_throw()" id="test_throw">Test Throw</button> + </div> + <div> + <button onclick="test_details()" id="test_details">Test Details</button> + </div> + <pre id="result"></pre> + <script src="util.js"></script> + <script src="change_payment_method.js"></script> + </body> +</html>
diff --git a/components/test/data/payments/change_payment_method.js b/components/test/data/payments/change_payment_method.js new file mode 100644 index 0000000..f891596 --- /dev/null +++ b/components/test/data/payments/change_payment_method.js
@@ -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. + */ + +const methodName = window.location.origin; + +/** Installs the payment handler. */ +function install() { // eslint-disable-line no-unused-vars + navigator.serviceWorker + .getRegistration('change_payment_method_app.js') + .then((registration) => { + if (registration) { + output( + 'serviceWorker.getRegistration()', + 'The ServiceWorker is already installed.' + ); + return; + } + navigator.serviceWorker + .register('change_payment_method_app.js') + .then(() => { + return navigator.serviceWorker.ready; + }) + .then((registration) => { + if (!registration.paymentManager) { + output('serviceWorker.register()', 'PaymentManager API not found.'); + return; + } + + registration.paymentManager.instruments + .set('instrument-id', { + name: 'Instrument Name', + method: methodName, + }) + .then(() => { + output('instruments.set()', 'Payment handler installed.'); + }) + .catch((error) => { + output('instruments.set() rejected with', error); + }); + }) + .catch((error) => { + output('serviceWorker.register() rejected with', error); + }); + }) + .catch((error) => { + output('serviceWorker.getRegistration() rejected with', error); + }); +} + +/** + * Shows the payment sheet and outputs the return value of + * PaymentRequestEvent.changePaymentMethod(). + * @param {PaymentRequest} request - The PaymentRequest object for showing the + * payment sheet. + */ +function outputChangePaymentMethodReturnValue(request) { + let returnValue; + request + .show() + .then((response) => { + returnValue = response.details.changePaymentMethodReturned; + return response.complete('success'); + }) + .catch((error) => { + output('PaymentRequest.show() rejected with', error); + }) + .then(() => { + output( + 'PaymentRequest.show()', + 'changePaymentMethod() returned: ' + JSON.stringify(returnValue) + ); + }); +} + +/** + * Verifies that PaymentRequestEvent.changePaymentMethod() returns null if there + * is no handler for the "paymentmethodchange" event in PaymentRequest. + */ +function testNoHandler() { // eslint-disable-line no-unused-vars + // Intentionally do not respond to the 'paymentmethodchange' event. + outputChangePaymentMethodReturnValue( + new PaymentRequest([{supportedMethods: methodName}], { + total: {label: 'Total', amount: {currency: 'USD', value: '0.01'}}, + }) + ); +} + +/** + * Verifies that PaymentRequest.show() is rejected if the promise passed into + * PaymentMethodChangeEvent.updateWith() is rejected. + */ +function testReject() { // eslint-disable-line no-unused-vars + const request = new PaymentRequest([{supportedMethods: methodName}], { + total: {label: 'Total', amount: {currency: 'USD', value: '0.01'}}, + }); + request.addEventListener('paymentmethodchange', (event) => { + event.updateWith(Promise.reject('Error for test')); + }); + outputChangePaymentMethodReturnValue(request); +} + +/** + * Verifies that PaymentRequest.show() is rejected if there is an exception in + * the promised passed into PaymentMethodChangeEvent.updateWith(). + */ +function testThrow() { // eslint-disable-line no-unused-vars + const request = new PaymentRequest([{supportedMethods: methodName}], { + total: {label: 'Total', amount: {currency: 'USD', value: '0.01'}}, + }); + request.addEventListener('paymentmethodchange', (event) => { + event.updateWith( + new Promise(() => { + throw new Error('Error for test'); + }) + ); + }); + outputChangePaymentMethodReturnValue(request); +} + +/** + * Verifies that PaymentRequestEvent.changePaymentMethod() returns a subset of + * details passed into PaymentMethodChangeEvent.updateWith() method. + */ +function testDetails() { // eslint-disable-line no-unused-vars + const request = new PaymentRequest([{supportedMethods: methodName}], { + total: {label: 'Total', amount: {currency: 'USD', value: '0.01'}}, + }); + request.addEventListener('paymentmethodchange', (event) => { + event.updateWith({ + total: {label: 'Total', amount: {currency: 'GBP', value: '0.02'}}, + error: 'Error for test', + modifiers: [ + { + supportedMethods: methodName, + data: {soup: 'potato'}, + total: { + label: 'Modified total', + amount: {currency: 'EUR', value: '0.03'}, + }, + additionalDisplayItems: [ + { + label: 'Modified display item', + amount: {currency: 'INR', value: '0.06'}, + }, + ], + }, + { + supportedMethods: methodName + '/2', + data: {soup: 'tomato'}, + total: { + label: 'Modified total #2', + amount: {currency: 'CHF', value: '0.07'}, + }, + additionalDisplayItems: [ + { + label: 'Modified display item #2', + amount: {currency: 'CAD', value: '0.08'}, + }, + ], + }, + ], + paymentMethodErrors: {country: 'Unsupported country'}, + displayItems: [ + { + label: 'Display item', + amount: {currency: 'CNY', value: '0.04'}, + }, + ], + shippingOptions: [ + { + label: 'Shipping option', + id: 'id', + amount: {currency: 'JPY', value: '0.05'}, + }, + ], + }); + }); + outputChangePaymentMethodReturnValue(request); +}
diff --git a/components/test/data/payments/change_payment_method_app.js b/components/test/data/payments/change_payment_method_app.js new file mode 100644 index 0000000..c64f5f5b --- /dev/null +++ b/components/test/data/payments/change_payment_method_app.js
@@ -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. + */ + +self.addEventListener('canmakepayment', (event) => { + event.respondWith(true); +}); + +/** + * Responds to the PaymentRequest |event| by calling its changePaymentMethod() + * method and returning its result, thus allowing for testing without user + * interaction with a skip-UI flow. + * + * @param {PaymentRequestEvent} event - The event to respond. + * @return {PamentDetailsUpdate} - The update to the payment details. + */ +async function responder(event) { + const methodName = event.methodData[0].supportedMethods; + if (!event.changePaymentMethod) { + return { + methodName, + details: { + changePaymentMethodReturned: + 'The changePaymentMethod() method is not implemented.', + }, + }; + } + let changePaymentMethodReturned; + try { + const response = await event.changePaymentMethod(methodName, { + country: 'US', + }); + changePaymentMethodReturned = response; + } catch (error) { + changePaymentMethodReturned = error.message; + } + return {methodName, details: {changePaymentMethodReturned}}; +} + +self.addEventListener('paymentrequest', (event) => { + event.respondWith(responder(event)); +});
diff --git a/components/test/data/payments/show_promise/app_installer.js b/components/test/data/payments/show_promise/app_installer.js index ae296caf..bfa9cf4 100644 --- a/components/test/data/payments/show_promise/app_installer.js +++ b/components/test/data/payments/show_promise/app_installer.js
@@ -5,25 +5,6 @@ */ /** - * Prints output. - * @param {String} src - Where the message is coming from. - * @param {String} txt - The text to print. - */ -function output(src, txt) { - // Handle DOMException: - if (txt.message) { - txt = txt.message; - } - txt = src + ': ' + txt; - if (window.domAutomationController) { - window.domAutomationController.send(txt); - } else { - txt += ' window.domAutomationController not found.'; - } - console.log(txt); -} - -/** * Installs the payment handler. */ function install() { // eslint-disable-line no-unused-vars
diff --git a/components/test/data/payments/util.js b/components/test/data/payments/util.js index 4284c7c..f5baea7 100644 --- a/components/test/data/payments/util.js +++ b/components/test/data/payments/util.js
@@ -5,9 +5,30 @@ */ /** - * Prints the message. + * Prints the message on the page. * @param {String} msg - The message to print. */ function print(msg) { // eslint-disable-line no-unused-vars document.getElementById('result').innerHTML = msg; } + +/** + * Prints output in developer console and sends it to the DOM automation + * controller. + * @param {String} src - Human-readable description of where the message is + * coming from. + * @param {String} txt - The text to print. + */ +function output(src, txt) { // eslint-disable-line no-unused-vars + // Handle DOMException: + if (txt && txt.message) { + txt = txt.message; + } + txt = src + ': ' + txt; + if (window.domAutomationController) { + window.domAutomationController.send(txt); + } else { + txt += ' window.domAutomationController not found.'; + } + console.log(txt); +}
diff --git a/content/browser/accessibility/accessibility_auralinux_browsertest.cc b/content/browser/accessibility/accessibility_auralinux_browsertest.cc index 9aa1e11..f27df5b 100644 --- a/content/browser/accessibility/accessibility_auralinux_browsertest.cc +++ b/content/browser/accessibility/accessibility_auralinux_browsertest.cc
@@ -685,4 +685,29 @@ g_free(selected_text); } +IN_PROC_BROWSER_TEST_F(AccessibilityAuraLinuxBrowserTest, TestAtkTextListItem) { + LoadInitialAccessibilityTreeFromHtml( + R"HTML(<!DOCTYPE html> + <html> + <body> + <li>Text</li> + </body> + </html>)HTML"); + + // Retrieve the AtkObject interface for the document node. + AtkObject* document = GetRendererAccessible(); + EXPECT_EQ(1, atk_object_get_n_accessible_children(document)); + AtkObject* list_item = atk_object_ref_accessible_child(document, 0); + + EXPECT_TRUE(ATK_IS_TEXT(list_item)); + + // The text of the list item should include the list marker and the text of + // the item itself. + gchar* text = atk_text_get_text(ATK_TEXT(list_item), 0, -1); + ASSERT_STREQ(text, "\xE2\x80\xA2 Text"); + g_free(text); + + g_object_unref(list_item); +} + } // namespace content
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc index ca78e34..df8fe7a 100644 --- a/content/browser/frame_host/navigation_request.cc +++ b/content/browser/frame_host/navigation_request.cc
@@ -644,7 +644,6 @@ // navigation just committed. navigation_request->state_ = RESPONSE_STARTED; navigation_request->render_frame_host_ = render_frame_host; - navigation_request->VerifyLoaderAndRenderFrameHostExpectations(); navigation_request->CreateNavigationHandle(true); DCHECK(navigation_request->navigation_handle()); return navigation_request; @@ -829,23 +828,11 @@ } void NavigationRequest::BeginNavigation() { - DCHECK(!loader_); - DCHECK(!render_frame_host_); - - // TODO(https://crbug.com/936962): Remove this when the bug is fixed. - if (loader_) { - FrameMsg_Navigate_Type::Value navigation_type = - common_params_.navigation_type; - base::debug::Alias(&navigation_type); - NavigationState state = state_; - base::debug::Alias(&state); - DEBUG_ALIAS_FOR_GURL(url, common_params_.url); - base::debug::DumpWithoutCrashing(); - loader_.reset(); - } DCHECK(state_ == NOT_STARTED || state_ == WAITING_FOR_RENDERER_RESPONSE); TRACE_EVENT_ASYNC_STEP_INTO0("navigation", "NavigationRequest", this, "BeginNavigation"); + DCHECK(!loader_); + DCHECK(!render_frame_host_); state_ = STARTED; @@ -947,7 +934,6 @@ // Select an appropriate RenderFrameHost. render_frame_host_ = frame_tree_node_->render_manager()->GetFrameHostForNavigation(*this); - VerifyLoaderAndRenderFrameHostExpectations(); NavigatorImpl::CheckWebUIRendererDoesNotDisplayNormalURL(render_frame_host_, common_params_.url); @@ -1395,7 +1381,6 @@ if (response_should_be_rendered_) { render_frame_host_ = frame_tree_node_->render_manager()->GetFrameHostForNavigation(*this); - VerifyLoaderAndRenderFrameHostExpectations(); NavigatorImpl::CheckWebUIRendererDoesNotDisplayNormalURL( render_frame_host_, common_params_.url); } else { @@ -1595,15 +1580,8 @@ // Sanity check that we haven't changed the RenderFrameHost picked for the // error page in OnRequestFailedInternal when running the WillFailRequest // checks. - // TODO(https://crbug.com/936962): Replace this by a CHECK when the bug is - // fixed. - DCHECK(!render_frame_host_ || render_frame_host_ == render_frame_host); - if (render_frame_host_ && render_frame_host_ != render_frame_host) - base::debug::DumpWithoutCrashing(); + CHECK(!render_frame_host_ || render_frame_host_ == render_frame_host); render_frame_host_ = render_frame_host; - VerifyLoaderAndRenderFrameHostExpectations(); - - DCHECK(render_frame_host_); // The check for WebUI should be performed only if error page isolation is // enabled for this failed navigation. It is possible for subframe error page @@ -1834,7 +1812,7 @@ std::move(navigation_ui_data), navigation_handle_->service_worker_handle(), appcache_handle_.get(), this); - VerifyLoaderAndRenderFrameHostExpectations(); + DCHECK(!render_frame_host_); } void NavigationRequest::OnRedirectChecksComplete( @@ -2409,18 +2387,6 @@ return FrameMsg_Navigate_Type::IsSameDocument(common_params_.navigation_type); } -void NavigationRequest::VerifyLoaderAndRenderFrameHostExpectations() { - if (!loader_ || !render_frame_host_) - return; - FrameMsg_Navigate_Type::Value navigation_type = - common_params_.navigation_type; - base::debug::Alias(&navigation_type); - NavigationState state = state_; - base::debug::Alias(&state); - DEBUG_ALIAS_FOR_GURL(url, common_params_.url); - base::debug::DumpWithoutCrashing(); -} - int NavigationRequest::EstimateHistoryOffset() { if (common_params_.should_replace_current_entry) return 0;
diff --git a/content/browser/frame_host/navigation_request.h b/content/browser/frame_host/navigation_request.h index 1811ea7e..c77843a6 100644 --- a/content/browser/frame_host/navigation_request.h +++ b/content/browser/frame_host/navigation_request.h
@@ -576,13 +576,6 @@ // Inform the RenderProcessHost to no longer expect a navigation. void ResetExpectedProcess(); - // https://crbug.com/936962 happens when a |render_frame_host_| has been - // selected and the |loader_| calls OnRequestFailed(). This shouldn't be - // possible, because |render_frame_host_| and |loader_| can't be non-null at - // the same time. - // TODO(https://crbug.com/936962): Remove this when the bug is fixed. - void VerifyLoaderAndRenderFrameHostExpectations(); - // Compute the history offset of the new document compared to the current one. // See navigation_history_offset_ for more details. int EstimateHistoryOffset(); @@ -683,6 +676,7 @@ FrameTreeNode* frame_tree_node_; + // Invariant: At least one of |loader_| or |render_frame_host_| is null. RenderFrameHostImpl* render_frame_host_ = nullptr; // Initialized on creation of the NavigationRequest. Sent to the renderer when
diff --git a/content/browser/manifest/manifest_manager_host.h b/content/browser/manifest/manifest_manager_host.h index a49af36..f001514 100644 --- a/content/browser/manifest/manifest_manager_host.h +++ b/content/browser/manifest/manifest_manager_host.h
@@ -8,10 +8,10 @@ #include "base/callback_forward.h" #include "base/containers/id_map.h" #include "base/macros.h" -#include "content/common/manifest_observer.mojom.h" #include "content/public/browser/web_contents_binding_set.h" #include "content/public/browser/web_contents_observer.h" #include "third_party/blink/public/mojom/manifest/manifest_manager.mojom.h" +#include "third_party/blink/public/mojom/manifest/manifest_observer.mojom.h" namespace blink { struct Manifest; @@ -27,7 +27,7 @@ // IPC messaging with the child process. // TODO(mlamouri): keep a cached version and a dirty bit here. class ManifestManagerHost : public WebContentsObserver, - public mojom::ManifestUrlChangeObserver { + public blink::mojom::ManifestUrlChangeObserver { public: explicit ManifestManagerHost(WebContents* web_contents); ~ManifestManagerHost() override; @@ -56,14 +56,14 @@ const GURL& url, const blink::Manifest& manifest); - // mojom::ManifestUrlChangeObserver: + // blink::mojom::ManifestUrlChangeObserver: void ManifestUrlChanged(const base::Optional<GURL>& manifest_url) override; RenderFrameHost* manifest_manager_frame_ = nullptr; blink::mojom::ManifestManagerPtr manifest_manager_; CallbackMap callbacks_; - WebContentsFrameBindingSet<mojom::ManifestUrlChangeObserver> + WebContentsFrameBindingSet<blink::mojom::ManifestUrlChangeObserver> manifest_url_change_observer_bindings_; DISALLOW_COPY_AND_ASSIGN(ManifestManagerHost);
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn index f7d55082..570125d2 100644 --- a/content/common/BUILD.gn +++ b/content/common/BUILD.gn
@@ -476,7 +476,6 @@ "input/input_handler.mojom", "input/input_injector.mojom", "input/synchronous_compositor.mojom", - "manifest_observer.mojom", "media/peer_connection_tracker.mojom", "media/renderer_audio_input_stream_factory.mojom", "media/renderer_audio_output_stream_factory.mojom",
diff --git a/content/public/renderer/render_frame_observer.h b/content/public/renderer/render_frame_observer.h index 89356971..795914e 100644 --- a/content/public/renderer/render_frame_observer.h +++ b/content/public/renderer/render_frame_observer.h
@@ -116,7 +116,6 @@ virtual void WillReleaseScriptContext(v8::Local<v8::Context> context, int world_id) {} virtual void DidClearWindowObject() {} - virtual void DidChangeManifest() {} virtual void DidChangeScrollOffset() {} virtual void WillSendSubmitEvent(const blink::WebFormElement& form) {} virtual void WillSubmitForm(const blink::WebFormElement& form) {}
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn index dea96bf..2948fbb 100644 --- a/content/renderer/BUILD.gn +++ b/content/renderer/BUILD.gn
@@ -188,10 +188,6 @@ "loader/web_worker_fetch_context_impl.h", "low_memory_mode_controller.cc", "low_memory_mode_controller.h", - "manifest/manifest_change_notifier.cc", - "manifest/manifest_change_notifier.h", - "manifest/manifest_uma_util.cc", - "manifest/manifest_uma_util.h", "media/android/flinging_renderer_client.cc", "media/android/flinging_renderer_client.h", "media/android/flinging_renderer_client_factory.cc",
diff --git a/content/renderer/manifest/OWNERS b/content/renderer/manifest/OWNERS deleted file mode 100644 index e60c0b9..0000000 --- a/content/renderer/manifest/OWNERS +++ /dev/null
@@ -1,3 +0,0 @@ -file://third_party/blink/renderer/modules/manifest/OWNERS - -# COMPONENT: Manifest
diff --git a/content/renderer/manifest/manifest_change_notifier.cc b/content/renderer/manifest/manifest_change_notifier.cc deleted file mode 100644 index dba510ff..0000000 --- a/content/renderer/manifest/manifest_change_notifier.cc +++ /dev/null
@@ -1,76 +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 "content/renderer/manifest/manifest_change_notifier.h" - -#include <utility> - -#include "base/bind.h" -#include "content/public/renderer/render_frame.h" -#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h" -#include "third_party/blink/public/web/web_document.h" -#include "third_party/blink/public/web/web_local_frame.h" -#include "third_party/blink/public/web/web_manifest_manager.h" - -namespace content { - -ManifestChangeNotifier::ManifestChangeNotifier(RenderFrame* render_frame) - : RenderFrameObserver(render_frame), weak_factory_(this) {} - -ManifestChangeNotifier::~ManifestChangeNotifier() = default; - -void ManifestChangeNotifier::DidChangeManifest() { - blink::WebManifestManager* manifest_manager = - blink::WebManifestManager::FromFrame(render_frame()->GetWebFrame()); - - // Manifests are not considered when the current page has a unique origin. - if (!manifest_manager || !manifest_manager->CanFetchManifest()) - return; - - if (weak_factory_.HasWeakPtrs()) - return; - - // Changing the manifest URL can trigger multiple notifications; the manifest - // URL update may involve removing the old manifest link before adding the new - // one, triggering multiple calls to DidChangeManifest(). Coalesce changes - // during a single event loop task to avoid sending spurious notifications to - // the browser. - // - // During document load, coalescing is disabled to maintain relative ordering - // of this notification and the favicon URL reporting. - if (!render_frame()->GetWebFrame()->IsLoading()) { - render_frame() - ->GetTaskRunner(blink::TaskType::kInternalLoading) - ->PostTask(FROM_HERE, - base::BindOnce(&ManifestChangeNotifier::ReportManifestChange, - weak_factory_.GetWeakPtr())); - return; - } - ReportManifestChange(); -} - -void ManifestChangeNotifier::OnDestruct() { - delete this; -} - -void ManifestChangeNotifier::ReportManifestChange() { - auto manifest_url = - render_frame()->GetWebFrame()->GetDocument().ManifestURL(); - if (manifest_url.IsNull()) { - GetManifestChangeObserver().ManifestUrlChanged(base::nullopt); - } else { - GetManifestChangeObserver().ManifestUrlChanged(GURL(manifest_url)); - } -} - -mojom::ManifestUrlChangeObserver& -ManifestChangeNotifier::GetManifestChangeObserver() { - if (!manifest_change_observer_) { - render_frame()->GetRemoteAssociatedInterfaces()->GetInterface( - &manifest_change_observer_); - } - return *manifest_change_observer_; -} - -} // namespace content
diff --git a/content/renderer/manifest/manifest_change_notifier.h b/content/renderer/manifest/manifest_change_notifier.h deleted file mode 100644 index cfc6238..0000000 --- a/content/renderer/manifest/manifest_change_notifier.h +++ /dev/null
@@ -1,37 +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 CONTENT_RENDERER_MANIFEST_MANIFEST_CHANGE_NOTIFIER_H_ -#define CONTENT_RENDERER_MANIFEST_MANIFEST_CHANGE_NOTIFIER_H_ - -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "content/common/manifest_observer.mojom.h" -#include "content/public/renderer/render_frame_observer.h" - -namespace content { - -class ManifestChangeNotifier : public RenderFrameObserver { - public: - explicit ManifestChangeNotifier(RenderFrame* render_frame); - ~ManifestChangeNotifier() override; - - private: - // RenderFrameObserver implementation. - void DidChangeManifest() override; - void OnDestruct() override; - - void ReportManifestChange(); - mojom::ManifestUrlChangeObserver& GetManifestChangeObserver(); - - mojom::ManifestUrlChangeObserverAssociatedPtr manifest_change_observer_; - - base::WeakPtrFactory<ManifestChangeNotifier> weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(ManifestChangeNotifier); -}; - -} // namespace content - -#endif // CONTENT_RENDERER_MANIFEST_MANIFEST_CHANGE_NOTIFIER_H_
diff --git a/content/renderer/manifest/manifest_uma_util.cc b/content/renderer/manifest/manifest_uma_util.cc deleted file mode 100644 index 7bb45b5c6..0000000 --- a/content/renderer/manifest/manifest_uma_util.cc +++ /dev/null
@@ -1,85 +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 "content/renderer/manifest/manifest_uma_util.h" - -#include "base/metrics/histogram_macros.h" -#include "third_party/blink/public/common/manifest/manifest.h" - -namespace content { - -namespace { - -static const char kUMANameParseSuccess[] = "Manifest.ParseSuccess"; -static const char kUMANameFetchResult[] = "Manifest.FetchResult"; - -// Enum for UMA purposes, make sure you update histograms.xml if you add new -// result types. Never delete or reorder an entry; only add new entries -// immediately before MANIFEST_FETCH_RESULT_TYPE_COUNT. -enum ManifestFetchResultType { - MANIFEST_FETCH_SUCCESS = 0, - MANIFEST_FETCH_ERROR_EMPTY_URL = 1, - MANIFEST_FETCH_ERROR_UNSPECIFIED = 2, - MANIFEST_FETCH_ERROR_FROM_UNIQUE_ORIGIN = 3, - - // Must stay at the end. - MANIFEST_FETCH_RESULT_TYPE_COUNT -}; - -} // anonymous namespace - -void ManifestUmaUtil::ParseSucceeded(const blink::Manifest& manifest) { - UMA_HISTOGRAM_BOOLEAN(kUMANameParseSuccess, true); - UMA_HISTOGRAM_BOOLEAN("Manifest.IsEmpty", manifest.IsEmpty()); - if (manifest.IsEmpty()) - return; - - UMA_HISTOGRAM_BOOLEAN("Manifest.HasProperty.name", !manifest.name.is_null()); - UMA_HISTOGRAM_BOOLEAN("Manifest.HasProperty.short_name", - !manifest.short_name.is_null()); - UMA_HISTOGRAM_BOOLEAN("Manifest.HasProperty.start_url", - !manifest.start_url.is_empty()); - UMA_HISTOGRAM_BOOLEAN("Manifest.HasProperty.display", - manifest.display != blink::kWebDisplayModeUndefined); - UMA_HISTOGRAM_BOOLEAN( - "Manifest.HasProperty.orientation", - manifest.orientation != blink::kWebScreenOrientationLockDefault); - UMA_HISTOGRAM_BOOLEAN("Manifest.HasProperty.icons", !manifest.icons.empty()); - UMA_HISTOGRAM_BOOLEAN("Manifest.HasProperty.share_target", - manifest.share_target.has_value()); - UMA_HISTOGRAM_BOOLEAN("Manifest.HasProperty.gcm_sender_id", - !manifest.gcm_sender_id.is_null()); -} - -void ManifestUmaUtil::ParseFailed() { - UMA_HISTOGRAM_BOOLEAN(kUMANameParseSuccess, false); -} - -void ManifestUmaUtil::FetchSucceeded() { - UMA_HISTOGRAM_ENUMERATION(kUMANameFetchResult, - MANIFEST_FETCH_SUCCESS, - MANIFEST_FETCH_RESULT_TYPE_COUNT); -} - -void ManifestUmaUtil::FetchFailed(FetchFailureReason reason) { - ManifestFetchResultType fetch_result_type = MANIFEST_FETCH_RESULT_TYPE_COUNT; - switch (reason) { - case FETCH_EMPTY_URL: - fetch_result_type = MANIFEST_FETCH_ERROR_EMPTY_URL; - break; - case FETCH_FROM_UNIQUE_ORIGIN: - fetch_result_type = MANIFEST_FETCH_ERROR_FROM_UNIQUE_ORIGIN; - break; - case FETCH_UNSPECIFIED_REASON: - fetch_result_type = MANIFEST_FETCH_ERROR_UNSPECIFIED; - break; - } - DCHECK_NE(fetch_result_type, MANIFEST_FETCH_RESULT_TYPE_COUNT); - - UMA_HISTOGRAM_ENUMERATION(kUMANameFetchResult, - fetch_result_type, - MANIFEST_FETCH_RESULT_TYPE_COUNT); -} - -} // namespace content
diff --git a/content/renderer/manifest/manifest_uma_util.h b/content/renderer/manifest/manifest_uma_util.h deleted file mode 100644 index 1bf569b..0000000 --- a/content/renderer/manifest/manifest_uma_util.h +++ /dev/null
@@ -1,40 +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 CONTENT_RENDERER_MANIFEST_MANIFEST_UMA_UTIL_H_ -#define CONTENT_RENDERER_MANIFEST_MANIFEST_UMA_UTIL_H_ - -namespace blink { -struct Manifest; -} - -namespace content { - -class ManifestUmaUtil { - public: - enum FetchFailureReason { - FETCH_EMPTY_URL = 0, - FETCH_FROM_UNIQUE_ORIGIN, - FETCH_UNSPECIFIED_REASON - }; - - // Record that the Manifest was successfully parsed. If it is an empty - // Manifest, it will recorded as so and nothing will happen. Otherwise, the - // presence of each properties will be recorded. - static void ParseSucceeded(const blink::Manifest& manifest); - - // Record that the Manifest parsing failed. - static void ParseFailed(); - - // Record that the Manifest fetching succeeded. - static void FetchSucceeded(); - - // Record that the Manifest fetching failed and takes the |reason| why it - // failed. - static void FetchFailed(FetchFailureReason reason); -}; - -} // namespace content - -#endif // CONTENT_RENDERER_MANIFEST_MANIFEST_UMA_UTIL_H_
diff --git a/content/renderer/media/stream/media_stream_constraints_util_audio.h b/content/renderer/media/stream/media_stream_constraints_util_audio.h index 62de3d7..40e99547 100644 --- a/content/renderer/media/stream/media_stream_constraints_util_audio.h +++ b/content/renderer/media/stream/media_stream_constraints_util_audio.h
@@ -144,8 +144,6 @@ // Moreover, the echo_cancellation constraint influences most other // audio-processing properties for which no explicit value is provided in // their corresponding constraints. -// TODO(guidou): Add support for other standard constraints such as sampleRate, -// channelCount and groupId. https://crbug.com/731170 CONTENT_EXPORT blink::AudioCaptureSettings SelectSettingsAudioCapture( const AudioDeviceCaptureCapabilities& capabilities, const blink::WebMediaConstraints& constraints,
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index a6b62dc..86237d1 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc
@@ -118,7 +118,6 @@ #include "content/renderer/loader/web_url_request_util.h" #include "content/renderer/loader/web_worker_fetch_context_impl.h" #include "content/renderer/low_memory_mode_controller.h" -#include "content/renderer/manifest/manifest_change_notifier.h" #include "content/renderer/media/audio/audio_device_factory.h" #include "content/renderer/media/audio/audio_output_ipc_factory.h" #include "content/renderer/media/audio/audio_renderer_sink_cache.h" @@ -1824,14 +1823,6 @@ // Manages its own lifetime. plugin_power_saver_helper_ = new PluginPowerSaverHelper(this); #endif - - // TODO(ajwong): This always returns true as is_main_frame_ gets initialized - // later in RenderFrameImpl::Initialize(). Should the conditional be in - // RenderFrameImpl::Initialize()? https://crbug.com/840533 - if (IsMainFrame()) { - // Manages its own lifetime. - new ManifestChangeNotifier(this); - } } mojom::FrameHost* RenderFrameImpl::GetFrameHost() { @@ -5627,11 +5618,6 @@ } } -void RenderFrameImpl::DidChangeManifest() { - for (auto& observer : observers_) - observer.DidChangeManifest(); -} - void RenderFrameImpl::EnterFullscreen( const blink::WebFullscreenOptions& options) { Send(new FrameHostMsg_EnterFullscreen(routing_id_, options));
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h index 4d8c563..2f0a5ac 100644 --- a/content/renderer/render_frame_impl.h +++ b/content/renderer/render_frame_impl.h
@@ -844,7 +844,6 @@ int start_offset, const blink::WebNode& end_node, int end_offset) override; - void DidChangeManifest() override; void EnterFullscreen(const blink::WebFullscreenOptions& options) override; void ExitFullscreen() override; void FullscreenStateChanged(bool is_fullscreen) override;
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc index 2a7e6da..b9bbb49e 100644 --- a/content/renderer/service_worker/service_worker_context_client.cc +++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -1190,9 +1190,10 @@ TRACE_ID_LOCAL(event_id)), TRACE_EVENT_FLAG_FLOW_OUT); - blink::WebPaymentRequestEventData webEventData = - mojo::ConvertTo<blink::WebPaymentRequestEventData>(std::move(eventData)); - proxy_->DispatchPaymentRequestEvent(event_id, webEventData); + auto webEventData = + mojo::ConvertTo<std::unique_ptr<blink::WebPaymentRequestEventData>>( + std::move(eventData)); + proxy_->DispatchPaymentRequestEvent(event_id, std::move(webEventData)); } void ServiceWorkerContextClient::OnNavigationPreloadResponse(
diff --git a/content/renderer/service_worker/service_worker_context_client_unittest.cc b/content/renderer/service_worker/service_worker_context_client_unittest.cc index 1beabf8..e3b62ea0 100644 --- a/content/renderer/service_worker/service_worker_context_client_unittest.cc +++ b/content/renderer/service_worker/service_worker_context_client_unittest.cc
@@ -182,7 +182,7 @@ } void DispatchPaymentRequestEvent( int event_id, - const blink::WebPaymentRequestEventData&) override { + std::unique_ptr<blink::WebPaymentRequestEventData>) override { NOTREACHED(); } void OnNavigationPreloadResponse(
diff --git a/content/renderer/service_worker/service_worker_type_converters.cc b/content/renderer/service_worker/service_worker_type_converters.cc index 638620cd..8f42273 100644 --- a/content/renderer/service_worker/service_worker_type_converters.cc +++ b/content/renderer/service_worker/service_worker_type_converters.cc
@@ -37,35 +37,38 @@ return output; } -blink::WebPaymentRequestEventData -TypeConverter<blink::WebPaymentRequestEventData, +std::unique_ptr<blink::WebPaymentRequestEventData> +TypeConverter<std::unique_ptr<blink::WebPaymentRequestEventData>, payments::mojom::PaymentRequestEventDataPtr>:: Convert(const payments::mojom::PaymentRequestEventDataPtr& input) { - blink::WebPaymentRequestEventData output; + auto output = std::make_unique<blink::WebPaymentRequestEventData>(); - output.top_origin = blink::WebString::FromUTF8(input->top_origin.spec()); - output.payment_request_origin = + output->top_origin = blink::WebString::FromUTF8(input->top_origin.spec()); + output->payment_request_origin = blink::WebString::FromUTF8(input->payment_request_origin.spec()); - output.payment_request_id = + output->payment_request_id = blink::WebString::FromUTF8(input->payment_request_id); - output.method_data = + output->method_data = blink::WebVector<blink::WebPaymentMethodData>(input->method_data.size()); for (size_t i = 0; i < input->method_data.size(); i++) { - output.method_data[i] = mojo::ConvertTo<blink::WebPaymentMethodData>( + output->method_data[i] = mojo::ConvertTo<blink::WebPaymentMethodData>( std::move(input->method_data[i])); } - output.total = mojo::ConvertTo<blink::WebPaymentCurrencyAmount>(input->total); + output->total = + mojo::ConvertTo<blink::WebPaymentCurrencyAmount>(input->total); - output.modifiers = blink::WebVector<blink::WebPaymentDetailsModifier>( + output->modifiers = blink::WebVector<blink::WebPaymentDetailsModifier>( input->modifiers.size()); for (size_t i = 0; i < input->modifiers.size(); i++) { - output.modifiers[i] = + output->modifiers[i] = mojo::ConvertTo<blink::WebPaymentDetailsModifier>(input->modifiers[i]); } - output.instrument_key = blink::WebString::FromUTF8(input->instrument_key); + output->instrument_key = blink::WebString::FromUTF8(input->instrument_key); + output->payment_handler_host_handle = + input->payment_handler_host.PassHandle(); return output; }
diff --git a/content/renderer/service_worker/service_worker_type_converters.h b/content/renderer/service_worker/service_worker_type_converters.h index aedfaea..80f74c2a 100644 --- a/content/renderer/service_worker/service_worker_type_converters.h +++ b/content/renderer/service_worker/service_worker_type_converters.h
@@ -5,6 +5,8 @@ #ifndef CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_TYPE_CONVERTERS_H_ #define CONTENT_RENDERER_SERVICE_WORKER_SERVICE_WORKER_TYPE_CONVERTERS_H_ +#include <memory> + #include "third_party/blink/public/common/service_worker/service_worker_status_code.h" #include "third_party/blink/public/mojom/payments/payment_app.mojom.h" #include "third_party/blink/public/mojom/service_worker/service_worker_event_status.mojom.h" @@ -26,9 +28,9 @@ }; template <> -struct TypeConverter<blink::WebPaymentRequestEventData, +struct TypeConverter<std::unique_ptr<blink::WebPaymentRequestEventData>, payments::mojom::PaymentRequestEventDataPtr> { - static blink::WebPaymentRequestEventData Convert( + static std::unique_ptr<blink::WebPaymentRequestEventData> Convert( const payments::mojom::PaymentRequestEventDataPtr& input); };
diff --git a/content/test/ct/OWNERS b/content/test/ct/OWNERS deleted file mode 100644 index ba6979dc..0000000 --- a/content/test/ct/OWNERS +++ /dev/null
@@ -1,4 +0,0 @@ -rmistry@chromium.org -benjaminwagner@chromium.org -borenet@chromium.org -jcgregorio@chromium.org
diff --git a/content/test/ct/run_ct_skps.py b/content/test/ct/run_ct_skps.py deleted file mode 100755 index b33f8a3..0000000 --- a/content/test/ct/run_ct_skps.py +++ /dev/null
@@ -1,99 +0,0 @@ -#!/usr/bin/env python -# 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 script is meant to be run on a Swarming bot.""" - -import argparse -import os -import subprocess -import sys - - -PARENT_DIR = os.path.dirname(os.path.realpath(__file__)) - -REPOS_BASE_DIR = os.path.normpath(os.path.join( - PARENT_DIR, os.pardir, os.pardir, os.pardir, os.pardir)) - -SKIA_SRC_DIR = os.path.join(REPOS_BASE_DIR, 'skia') - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument('-s', '--slave_num', required=True, type=int, - help='The slave num of this CT run.') - parser.add_argument('-t', '--tool', required=True, - choices=['dm', 'nanobench', 'get_images_from_skps'], - help='The tool to run on the SKPs.') - parser.add_argument('-g', '--git_hash', required=True, - help='The Skia hash the tool was built at.') - parser.add_argument('-c', '--configuration', required=True, - help='The build configuration to use.') - parser.add_argument('-i', '--isolated_outdir', required=True, - help='Swarming will automatically upload to ' - 'isolateserver all artifacts in this dir.') - parser.add_argument('-b', '--builder', required=True, - help='The name of the builder.') - args = parser.parse_args() - - tool_path = os.path.join(SKIA_SRC_DIR, 'out', args.configuration, args.tool) - skps_dir = os.path.join(REPOS_BASE_DIR, 'skps', 'slave%d' % args.slave_num) - resource_path = os.path.join(SKIA_SRC_DIR, 'resources') - - cmd = [tool_path] - if args.tool == 'dm': - # Add DM specific arguments. - cmd.extend([ - '--src', 'skp', - '--skps', skps_dir, - '--resourcePath', resource_path, - '--config', '8888', - '--verbose', - ]) - elif args.tool == 'nanobench': - # Add Nanobench specific arguments. - config = '8888' - cpu_or_gpu = 'CPU' - cpu_or_gpu_value = 'AVX2' - if 'GPU' in args.builder: - config = 'gpu' - cpu_or_gpu = 'GPU' - cpu_or_gpu_value = 'GT610' - - out_results_file = os.path.join( - args.isolated_outdir, 'nanobench_%s_%s_slave%d.json' % ( - args.git_hash, config, args.slave_num)) - cmd.extend([ - '--skps', skps_dir, - '--match', 'skp', - '--resourcePath', resource_path, - '--config', config, - '--outResultsFile', out_results_file, - '--properties', 'gitHash', args.git_hash, - '--key', 'arch', 'x86_64', - 'compiler', 'GCC', - 'cpu_or_gpu', cpu_or_gpu, - 'cpu_or_gpu_value', cpu_or_gpu_value, - 'model', 'SWARM', - 'os', 'Ubuntu', - '--verbose', - ]) - elif args.tool == 'get_images_from_skps': - # Add get_images_from_skps specific arguments. - img_out = os.path.join(args.isolated_outdir, 'img_out') - os.makedirs(img_out) - failures_json_out = os.path.join(args.isolated_outdir, 'failures.json') - cmd.extend([ - '--out', img_out, - '--skps', skps_dir, - '--failuresJsonPath', failures_json_out, - '--writeImages', 'false', - '--testDecode', - ]) - - return subprocess.call(cmd) - - -if __name__ == '__main__': - sys.exit(main())
diff --git a/content/test/net/OWNERS b/content/test/net/OWNERS deleted file mode 100644 index 75d5fc15..0000000 --- a/content/test/net/OWNERS +++ /dev/null
@@ -1,3 +0,0 @@ -file://net/OWNERS - -# COMPONENT: Internals>Network
diff --git a/courgette/disassembler_elf_32.cc b/courgette/disassembler_elf_32.cc index e5852080..1e8aa1d 100644 --- a/courgette/disassembler_elf_32.cc +++ b/courgette/disassembler_elf_32.cc
@@ -336,6 +336,11 @@ if (section_header->sh_type == SHT_REL) { const Elf32_Rel* relocs_table = reinterpret_cast<const Elf32_Rel*>(SectionBody(section_id)); + // Reject if malformed. + if (section_header->sh_entsize != sizeof(Elf32_Rel)) + return false; + if (section_header->sh_size % section_header->sh_entsize != 0) + return false; int relocs_table_count = section_header->sh_size / section_header->sh_entsize;
diff --git a/gpu/command_buffer/service/raster_decoder.cc b/gpu/command_buffer/service/raster_decoder.cc index 28ebdbe..4d3269fc 100644 --- a/gpu/command_buffer/service/raster_decoder.cc +++ b/gpu/command_buffer/service/raster_decoder.cc
@@ -2211,9 +2211,16 @@ }; CreateCleanupCallbackForSkiaFlush( shared_context_state_->vk_context_provider(), &flush_info); - auto result = sk_surface_->flush(SkSurface::BackendSurfaceAccess::kPresent, - flush_info); - DCHECK(result == GrSemaphoresSubmitted::kYes || end_semaphores_.empty()); + if (use_ddl_) { + // TODO(penghuang): Switch to sk_surface_->flush() when skia flush bug is + // fixed. https://crbug.com/958055 + auto result = gr_context()->flush(flush_info); + DCHECK(result == GrSemaphoresSubmitted::kYes || end_semaphores_.empty()); + } else { + auto result = sk_surface_->flush( + SkSurface::BackendSurfaceAccess::kPresent, flush_info); + DCHECK(result == GrSemaphoresSubmitted::kYes || end_semaphores_.empty()); + } end_semaphores_.clear(); }
diff --git a/ios/chrome/browser/DEPS b/ios/chrome/browser/DEPS index 671db27b..8fd081d8 100644 --- a/ios/chrome/browser/DEPS +++ b/ios/chrome/browser/DEPS
@@ -86,6 +86,7 @@ "+components/sync_bookmarks", "+components/sync_preferences", "+components/sync_sessions", + "+components/sync_user_events", "+components/thread_pool_util", "+components/translate", "+components/ui_metrics",
diff --git a/ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory_util.cc b/ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory_util.cc index 8847c73..704eb69 100644 --- a/ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory_util.cc +++ b/ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory_util.cc
@@ -71,10 +71,12 @@ const ntp_snippets::SuccessCallback& success_callback, const ntp_snippets::ErrorCallback& error_callback) { base::JSONReader json_reader; - std::unique_ptr<base::Value> value = json_reader.ReadToValueDeprecated(json); + base::Optional<base::Value> value = json_reader.ReadToValue(json); if (value) { base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(success_callback, std::move(value))); + FROM_HERE, + base::BindOnce(success_callback, + base::Value::ToUniquePtrValue(std::move(*value)))); } else { base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE,
diff --git a/ios/chrome/browser/payments/ios_payment_instrument.h b/ios/chrome/browser/payments/ios_payment_instrument.h index 617e435..c69c634 100644 --- a/ios/chrome/browser/payments/ios_payment_instrument.h +++ b/ios/chrome/browser/payments/ios_payment_instrument.h
@@ -62,6 +62,8 @@ bool supported_types_specified, const std::set<autofill::CreditCard::CardType>& supported_types) const override; + bool IsValidForPaymentMethodIdentifier( + const std::string& payment_method_identifier) const override; // Given that the icon for the iOS payment instrument can only be determined // at run-time, the icon is obtained using this UIImage object rather than
diff --git a/ios/chrome/browser/payments/ios_payment_instrument.mm b/ios/chrome/browser/payments/ios_payment_instrument.mm index cddb3d0..35f3353 100644 --- a/ios/chrome/browser/payments/ios_payment_instrument.mm +++ b/ios/chrome/browser/payments/ios_payment_instrument.mm
@@ -98,4 +98,9 @@ return method_name_ == method; } +bool IOSPaymentInstrument::IsValidForPaymentMethodIdentifier( + const std::string& payment_method_identifier) const { + return method_name_ == payment_method_identifier; +} + } // namespace payments
diff --git a/ios/chrome/browser/sync/BUILD.gn b/ios/chrome/browser/sync/BUILD.gn index 6c6c2ca..8014889 100644 --- a/ios/chrome/browser/sync/BUILD.gn +++ b/ios/chrome/browser/sync/BUILD.gn
@@ -55,9 +55,9 @@ "//components/signin/core/browser", "//components/sync", "//components/sync/device_info", - "//components/sync/user_events", "//components/sync_preferences", "//components/sync_sessions", + "//components/sync_user_events", "//components/unified_consent", "//components/version_info", "//google_apis",
diff --git a/ios/chrome/browser/sync/ios_chrome_sync_client.mm b/ios/chrome/browser/sync/ios_chrome_sync_client.mm index 0416916..f1db307 100644 --- a/ios/chrome/browser/sync/ios_chrome_sync_client.mm +++ b/ios/chrome/browser/sync/ios_chrome_sync_client.mm
@@ -41,10 +41,10 @@ #include "components/sync/engine/passive_model_worker.h" #include "components/sync/engine/sequenced_model_worker.h" #include "components/sync/engine/ui_model_worker.h" -#include "components/sync/user_events/user_event_service.h" #include "components/sync_preferences/pref_service_syncable.h" #include "components/sync_sessions/favicon_cache.h" #include "components/sync_sessions/session_sync_service.h" +#include "components/sync_user_events/user_event_service.h" #include "ios/chrome/browser/autofill/personal_data_manager_factory.h" #include "ios/chrome/browser/bookmarks/bookmark_model_factory.h" #include "ios/chrome/browser/bookmarks/bookmark_sync_service_factory.h"
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 1300ac3..a6786bf 100644 --- a/ios/chrome/browser/sync/ios_user_event_service_factory.cc +++ b/ios/chrome/browser/sync/ios_user_event_service_factory.cc
@@ -14,10 +14,10 @@ #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" -#include "components/sync/user_events/user_event_service_impl.h" -#include "components/sync/user_events/user_event_sync_bridge.h" #include "components/sync_sessions/session_sync_service.h" +#include "components/sync_user_events/no_op_user_event_service.h" +#include "components/sync_user_events/user_event_service_impl.h" +#include "components/sync_user_events/user_event_sync_bridge.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/sync/model_type_store_service_factory.h"
diff --git a/ios/chrome/browser/ui/authentication/BUILD.gn b/ios/chrome/browser/ui/authentication/BUILD.gn index cf578b6..c596be0 100644 --- a/ios/chrome/browser/ui/authentication/BUILD.gn +++ b/ios/chrome/browser/ui/authentication/BUILD.gn
@@ -166,6 +166,7 @@ "//ios/chrome/browser/ui/authentication/cells", "//ios/chrome/browser/ui/authentication/unified_consent:unified_consent_ui", "//ios/chrome/browser/ui/authentication/unified_consent/identity_chooser:identity_chooser_ui", + "//ios/chrome/browser/ui/util", "//ios/chrome/test/app:test_support", "//ios/chrome/test/earl_grey:test_support", "//ios/public/provider/chrome/browser/signin",
diff --git a/ios/chrome/browser/ui/authentication/signin_earl_grey_ui.h b/ios/chrome/browser/ui/authentication/signin_earl_grey_ui.h index 171f6542..aef92d1b 100644 --- a/ios/chrome/browser/ui/authentication/signin_earl_grey_ui.h +++ b/ios/chrome/browser/ui/authentication/signin_earl_grey_ui.h
@@ -17,6 +17,10 @@ // Adds the identity (if not already added), and perform a sign-in. + (void)signinWithIdentity:(ChromeIdentity*)identity; +// Taps on the settings link in the sign-in view. The sign-in view has to be +// opened before calling this method. ++ (void)tapSettingsLink; + // Selects an identity when the identity chooser dialog is presented. The dialog // is confirmed, but it doesn't validated the user consent page. + (void)selectIdentityWithEmail:(NSString*)userEmail;
diff --git a/ios/chrome/browser/ui/authentication/signin_earl_grey_ui.mm b/ios/chrome/browser/ui/authentication/signin_earl_grey_ui.mm index 2789367..07b65872 100644 --- a/ios/chrome/browser/ui/authentication/signin_earl_grey_ui.mm +++ b/ios/chrome/browser/ui/authentication/signin_earl_grey_ui.mm
@@ -13,6 +13,7 @@ #import "ios/chrome/browser/ui/authentication/unified_consent/identity_chooser/identity_chooser_cell.h" #import "ios/chrome/browser/ui/authentication/unified_consent/identity_picker_view.h" #import "ios/chrome/browser/ui/authentication/unified_consent/unified_consent_view_controller.h" +#import "ios/chrome/browser/ui/util/transparent_link_button.h" #include "ios/chrome/grit/ios_strings.h" #import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h" #import "ios/chrome/test/earl_grey/chrome_matchers.h" @@ -87,6 +88,14 @@ performAction:grey_tap()]; } ++ (void)tapSettingsLink { + id<GREYMatcher> settingsLinkMatcher = + grey_allOf(grey_kindOfClass([TransparentLinkButton class]), + grey_sufficientlyVisible(), nil); + [[EarlGrey selectElementWithMatcher:settingsLinkMatcher] + performAction:grey_tap()]; +} + + (void)confirmSigninConfirmationDialog { // To confirm the dialog, the scroll view content has to be scrolled to the // bottom to transform "MORE" button into the validation button.
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_mediator.mm b/ios/chrome/browser/ui/omnibox/omnibox_mediator.mm index 603de15b..dafa8a66 100644 --- a/ios/chrome/browser/ui/omnibox/omnibox_mediator.mm +++ b/ios/chrome/browser/ui/omnibox/omnibox_mediator.mm
@@ -19,7 +19,7 @@ #endif namespace { -const CGFloat kOmniboxIconSize = 20; +const CGFloat kOmniboxIconSize = 16; } // namespace @interface OmniboxMediator () <SearchEngineObserving>
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_util.mm b/ios/chrome/browser/ui/omnibox/omnibox_util.mm index 00b4a11b..d7f1c66 100644 --- a/ios/chrome/browser/ui/omnibox/omnibox_util.mm +++ b/ios/chrome/browser/ui/omnibox/omnibox_util.mm
@@ -123,7 +123,6 @@ case AutocompleteMatchType::HISTORY_KEYWORD: case AutocompleteMatchType::HISTORY_TITLE: case AutocompleteMatchType::HISTORY_URL: - case AutocompleteMatchType::SEARCH_HISTORY: case AutocompleteMatchType::TAB_SEARCH_DEPRECATED: return HISTORY; case AutocompleteMatchType::CONTACT_DEPRECATED: @@ -138,6 +137,9 @@ case AutocompleteMatchType::CLIPBOARD_TEXT: case AutocompleteMatchType::CLIPBOARD_IMAGE: return SEARCH; + case AutocompleteMatchType::SEARCH_HISTORY: + return base::FeatureList::IsEnabled(kNewOmniboxPopupLayout) ? SEARCH + : HISTORY; case AutocompleteMatchType::CALCULATOR: return CALCULATOR; case AutocompleteMatchType::EXTENSION_APP_DEPRECATED:
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm b/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm index 48335e8a..e73e5b23 100644 --- a/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm +++ b/ios/chrome/browser/ui/omnibox/omnibox_view_controller.mm
@@ -17,7 +17,6 @@ #include "ios/chrome/browser/ui/ui_feature_flags.h" #include "ios/chrome/browser/ui/util/ui_util.h" #include "ios/chrome/browser/ui/util/uikit_ui_util.h" -#import "ios/chrome/browser/ui/util/uikit_ui_util.h" #include "ios/chrome/grit/ios_strings.h" #include "ui/base/l10n/l10n_util.h"
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_mediator.mm b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_mediator.mm index de8fa91..aed8b27 100644 --- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_mediator.mm +++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_mediator.mm
@@ -26,7 +26,7 @@ #endif namespace { -const CGFloat kOmniboxIconSize = 20; +const CGFloat kOmniboxIconSize = 16; } // namespace @implementation OmniboxPopupMediator {
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row_cell.mm b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row_cell.mm index 8bc600086..c695c2e0 100644 --- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row_cell.mm +++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row_cell.mm
@@ -52,7 +52,7 @@ // Answers have slightly different display requirements, like possibility of // multiple lines and truncating with ellipses instead of a fade gradient. @property(nonatomic, strong) UILabel* detailAnswerLabel; -// Image view for the leading image (only appears on iPad). +// Image view for the leading image. @property(nonatomic, strong) UIImageView* leadingImageView; // Trailing button for appending suggestion into omnibox or switching to open // tab. @@ -256,10 +256,10 @@ [NSLayoutConstraint activateConstraints:@[ [self.leadingImageView.centerXAnchor constraintEqualToAnchor:imageLayoutGuide.centerXAnchor], - [self.textStackView.leadingAnchor - constraintEqualToAnchor:textLayoutGuide.leadingAnchor], [self.leadingImageView.widthAnchor constraintEqualToAnchor:imageLayoutGuide.widthAnchor], + [self.textStackView.leadingAnchor + constraintEqualToAnchor:textLayoutGuide.leadingAnchor], stackViewToLayoutGuideLeading, stackViewToLayoutGuideTrailing, stackViewToCellTrailing,
diff --git a/ios/chrome/browser/ui/recent_tabs/BUILD.gn b/ios/chrome/browser/ui/recent_tabs/BUILD.gn index d5a7fec..d783ff6 100644 --- a/ios/chrome/browser/ui/recent_tabs/BUILD.gn +++ b/ios/chrome/browser/ui/recent_tabs/BUILD.gn
@@ -101,6 +101,7 @@ "//components/browser_sync", "//components/sync:test_support_model", "//components/sync_sessions", + "//components/sync_user_events", "//ios/chrome/browser/browser_state:test_support", "//ios/chrome/browser/signin", "//ios/chrome/browser/sync",
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 84ffc499..8f20e0c 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
@@ -11,9 +11,9 @@ #include "base/bind.h" #include "components/sync/driver/sync_service.h" #include "components/sync/model/fake_model_type_controller_delegate.h" -#include "components/sync/user_events/global_id_mapper.h" #include "components/sync_sessions/open_tabs_ui_delegate.h" #include "components/sync_sessions/session_sync_service.h" +#include "components/sync_user_events/global_id_mapper.h" #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h" #include "ios/chrome/browser/sync/profile_sync_service_factory.h" #include "ios/chrome/browser/sync/session_sync_service_factory.h"
diff --git a/ios/chrome/browser/ui/settings/google_services/BUILD.gn b/ios/chrome/browser/ui/settings/google_services/BUILD.gn index 0884a20..6c8be8b 100644 --- a/ios/chrome/browser/ui/settings/google_services/BUILD.gn +++ b/ios/chrome/browser/ui/settings/google_services/BUILD.gn
@@ -123,6 +123,7 @@ "//ios/chrome/browser/ui/authentication:eg_test_support", "//ios/chrome/test/app:test_support", "//ios/chrome/test/earl_grey:test_support", + "//ios/public/provider/chrome/browser/signin:test_support", "//ui/base", ] libs = [
diff --git a/ios/chrome/browser/ui/settings/google_services/google_services_settings_coordinator.mm b/ios/chrome/browser/ui/settings/google_services/google_services_settings_coordinator.mm index 926b8a6..82a5ad9 100644 --- a/ios/chrome/browser/ui/settings/google_services/google_services_settings_coordinator.mm +++ b/ios/chrome/browser/ui/settings/google_services/google_services_settings_coordinator.mm
@@ -121,6 +121,13 @@ } syncSetupService->CommitSyncChanges(); } + if (self.signinInteractionCoordinator) { + [self.signinInteractionCoordinator cancel]; + // |self.signinInteractionCoordinator| is set to nil by + // the completion block called by -[GoogleServicesSettingsCoordinator + // signInInteractionCoordinatorDidComplete] + DCHECK(!self.signinInteractionCoordinator); + } self.stopDone = YES; }
diff --git a/ios/chrome/browser/ui/settings/google_services/google_services_settings_egtest.mm b/ios/chrome/browser/ui/settings/google_services/google_services_settings_egtest.mm index 7d61d4d..0f1835e 100644 --- a/ios/chrome/browser/ui/settings/google_services/google_services_settings_egtest.mm +++ b/ios/chrome/browser/ui/settings/google_services/google_services_settings_egtest.mm
@@ -16,6 +16,7 @@ #import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h" #import "ios/chrome/test/earl_grey/chrome_matchers.h" #import "ios/chrome/test/earl_grey/chrome_test_case.h" +#import "ios/public/provider/chrome/browser/signin/fake_chrome_identity_service.h" #import "ui/base/l10n/l10n_util.h" #if !defined(__has_feature) || !__has_feature(objc_arc) @@ -23,9 +24,7 @@ #endif using l10n_util::GetNSString; -using chrome_test_util::GetOriginalBrowserState; using chrome_test_util::GoogleServicesSettingsButton; -using chrome_test_util::SettingsMenuBackButton; using chrome_test_util::SettingsDoneButton; // Integration tests using the Google services settings screen. @@ -37,8 +36,6 @@ @implementation GoogleServicesSettingsTestCase -@synthesize scrollViewMatcher = _scrollViewMatcher; - // Opens the Google services settings view, and closes it. - (void)testOpenGoogleServicesSettings { [self openGoogleServicesSettings]; @@ -59,6 +56,43 @@ [self assertNonPersonalizedServices]; } +// Tests the following steps: +// + Opens sign-in from Google services +// + Taps on the settings link to open the advanced sign-in settings +// + Opens "Data from Chromium sync" to interrupt sign-in +- (void)testInterruptSigninFromGoogleServicesSettings { + // Adds default identity. + ios::FakeChromeIdentityService::GetInstanceFromChromeProvider()->AddIdentity( + [SigninEarlGreyUtils fakeIdentity1]); + // Open "Google Services" settings. + [self openGoogleServicesSettings]; + // Open sign-in. + id<GREYMatcher> signinCellMatcher = + [self cellMatcherWithTitleID:IDS_IOS_SIGN_IN_TO_CHROME_SETTING_TITLE + detailTextID: + IDS_IOS_GOOGLE_SERVICES_SETTINGS_SIGN_IN_DETAIL_TEXT]; + [[EarlGrey selectElementWithMatcher:signinCellMatcher] + performAction:grey_tap()]; + // Opens Settings link. + [SigninEarlGreyUI tapSettingsLink]; + // Opens "Manage Sync" settings. + id<GREYMatcher> manageSyncMatcher = + [self cellMatcherWithTitleID:IDS_IOS_MANAGE_SYNC_SETTINGS_TITLE + detailTextID:0]; + [[EarlGrey selectElementWithMatcher:manageSyncMatcher] + performAction:grey_tap()]; + // Opens "Data from Chrome sync". + id<GREYMatcher> manageSyncScrollViewMatcher = + grey_accessibilityID(@"manage_sync_settings_view_controller"); + id<GREYMatcher> dataFromChromeSyncMatcher = [self + cellMatcherWithTitleID:IDS_IOS_MANAGE_SYNC_DATA_FROM_CHROME_SYNC_TITLE + detailTextID: + IDS_IOS_MANAGE_SYNC_DATA_FROM_CHROME_SYNC_DESCRIPTION]; + [[self elementInteractionWithGreyMatcher:dataFromChromeSyncMatcher + scrollViewMatcher:manageSyncScrollViewMatcher] + performAction:grey_tap()]; +} + #pragma mark - Helpers // Opens the Google services settings. @@ -92,9 +126,11 @@ grey_sufficientlyVisible(), nil); } -// Returns GREYElementInteraction for |matcher|, with a scroll down action. -- (GREYElementInteraction*)elementInteractionWithGreyMatcher: - (id<GREYMatcher>)matcher { +// Returns GREYElementInteraction for |matcher|, using |scrollViewMatcher| to +// scroll. +- (GREYElementInteraction*) + elementInteractionWithGreyMatcher:(id<GREYMatcher>)matcher + scrollViewMatcher:(id<GREYMatcher>)scrollViewMatcher { // Needs to scroll slowly to make sure to not miss a cell if it is not // currently on the screen. It should not be bigger than the visible part // of the collection view. @@ -103,7 +139,15 @@ grey_scrollInDirection(kGREYDirectionDown, kPixelsToScroll); return [[EarlGrey selectElementWithMatcher:matcher] usingSearchAction:searchAction - onElementWithMatcher:self.scrollViewMatcher]; + onElementWithMatcher:scrollViewMatcher]; +} + +// Returns GREYElementInteraction for |matcher|, with |self.scrollViewMatcher| +// to scroll. +- (GREYElementInteraction*)elementInteractionWithGreyMatcher: + (id<GREYMatcher>)matcher { + return [self elementInteractionWithGreyMatcher:matcher + scrollViewMatcher:self.scrollViewMatcher]; } // Returns GREYElementInteraction for a cell based on the title string ID and
diff --git a/ios/web_view/BUILD.gn b/ios/web_view/BUILD.gn index 3e47d85..69f866b 100644 --- a/ios/web_view/BUILD.gn +++ b/ios/web_view/BUILD.gn
@@ -292,7 +292,7 @@ "//components/strings:components_strings_grit", "//components/sync", "//components/sync/device_info", - "//components/sync/user_events", + "//components/sync_user_events", "//components/language/ios/browser", "//components/sync_sessions", "//components/translate/core/browser",
diff --git a/ios/web_view/internal/DEPS b/ios/web_view/internal/DEPS index 51ed0531..574d893 100644 --- a/ios/web_view/internal/DEPS +++ b/ios/web_view/internal/DEPS
@@ -31,6 +31,7 @@ "+components/strings/grit", "+components/sync", "+components/sync_sessions", + "+components/sync_user_events", "+components/translate/core", "+components/translate/ios", "+components/language/ios",
diff --git a/ios/web_view/internal/sync/web_view_sync_client.mm b/ios/web_view/internal/sync/web_view_sync_client.mm index dfd30dc..5f2a17f 100644 --- a/ios/web_view/internal/sync/web_view_sync_client.mm +++ b/ios/web_view/internal/sync/web_view_sync_client.mm
@@ -28,7 +28,7 @@ #include "components/sync/engine/passive_model_worker.h" #include "components/sync/engine/sequenced_model_worker.h" #include "components/sync/engine/ui_model_worker.h" -#include "components/sync/user_events/user_event_service.h" +#include "components/sync_user_events/user_event_service.h" #include "components/version_info/version_info.h" #include "components/version_info/version_string.h" #include "ios/web/public/web_task_traits.h"
diff --git a/jingle/glue/thread_wrapper.cc b/jingle/glue/thread_wrapper.cc index 640fa6de..fcecbaf4 100644 --- a/jingle/glue/thread_wrapper.cc +++ b/jingle/glue/thread_wrapper.cc
@@ -6,6 +6,7 @@ #include <stddef.h> #include <stdint.h> +#include <memory> #include "base/bind.h" #include "base/bind_helpers.h" @@ -13,7 +14,7 @@ #include "base/stl_util.h" #include "base/threading/thread_local.h" #include "base/trace_event/trace_event.h" -#include "third_party/webrtc/rtc_base/null_socket_server.h" +#include "third_party/webrtc/rtc_base/physical_socket_server.h" namespace jingle_glue { @@ -64,7 +65,8 @@ JingleThreadWrapper::JingleThreadWrapper( scoped_refptr<base::SingleThreadTaskRunner> task_runner) - : task_runner_(task_runner), + : Thread(std::make_unique<rtc::PhysicalSocketServer>()), + task_runner_(task_runner), send_allowed_(false), last_task_id_(0), pending_send_event_(base::WaitableEvent::ResetPolicy::MANUAL,
diff --git a/media/base/unaligned_shared_memory.cc b/media/base/unaligned_shared_memory.cc index f4b7de7..3ac85579 100644 --- a/media/base/unaligned_shared_memory.cc +++ b/media/base/unaligned_shared_memory.cc
@@ -7,6 +7,7 @@ #include <limits> #include "base/logging.h" +#include "base/memory/read_only_shared_memory_region.h" #include "base/system/sys_info.h" #include "mojo/public/cpp/system/platform_handle.h" @@ -29,9 +30,10 @@ // Note: result of % computation may be off_t or size_t, depending on the // relative ranks of those types. In any case we assume that // VMAllocationGranularity() fits in both types, so the final result does too. + DCHECK_GE(offset, 0); *misalignment = offset % base::SysInfo::VMAllocationGranularity(); - // Above this |size_|, |size_| + |misalignment| overflows. + // Above this |max_size|, |size| + |*misalignment| overflows. size_t max_size = std::numeric_limits<size_t>::max() - *misalignment; if (size > max_size) { DLOG(ERROR) << "Invalid size"; @@ -48,7 +50,13 @@ const base::SharedMemoryHandle& handle, size_t size, bool read_only) - : shm_(handle, read_only), size_(size), misalignment_(0) {} + : shm_(handle, read_only), read_only_(read_only), size_(size) {} + +UnalignedSharedMemory::UnalignedSharedMemory( + base::subtle::PlatformSharedMemoryRegion region, + size_t size, + bool read_only) + : region_(std::move(region)), read_only_(read_only), size_(size) {} UnalignedSharedMemory::~UnalignedSharedMemory() = default; @@ -66,19 +74,47 @@ return false; } - if (!shm_.MapAt(adjusted_offset, size + misalignment)) { - DLOG(ERROR) << "Failed to map shared memory"; - return false; + if (region_.IsValid()) { + if (read_only_) { + auto shm = + base::ReadOnlySharedMemoryRegion::Deserialize(std::move(region_)); + read_only_mapping_ = shm.MapAt(adjusted_offset, size + misalignment); + if (!read_only_mapping_.IsValid()) { + DLOG(ERROR) << "Failed to map shared memory"; + return false; + } + // TODO(crbug.com/849207): this ugly const cast will go away when uses of + // UnalignedSharedMemory are converted to + // {Writable,ReadOnly}UnalignedMapping. + mapping_ptr_ = const_cast<uint8_t*>( + static_cast<const uint8_t*>(read_only_mapping_.memory())); + } else { + auto shm = + base::UnsafeSharedMemoryRegion::Deserialize(std::move(region_)); + writable_mapping_ = shm.MapAt(adjusted_offset, size + misalignment); + if (!writable_mapping_.IsValid()) { + DLOG(ERROR) << "Failed to map shared memory"; + return false; + } + mapping_ptr_ = static_cast<uint8_t*>(writable_mapping_.memory()); + } + } else { + if (!shm_.MapAt(adjusted_offset, size + misalignment)) { + DLOG(ERROR) << "Failed to map shared memory"; + return false; + } + mapping_ptr_ = static_cast<uint8_t*>(shm_.memory()); } - misalignment_ = misalignment; + DCHECK(mapping_ptr_); + // There should be no way for the IsValid() checks above to succeed and yet + // |mapping_ptr_| remain null. However, since an invalid but non-null pointer + // could be disastrous an extra-careful check is done. + if (mapping_ptr_) + mapping_ptr_ += misalignment; return true; } -void* UnalignedSharedMemory::memory() const { - return static_cast<uint8_t*>(shm_.memory()) + misalignment_; -} - WritableUnalignedMapping::WritableUnalignedMapping( const base::UnsafeSharedMemoryRegion& region, size_t size, @@ -111,15 +147,6 @@ } } -WritableUnalignedMapping::WritableUnalignedMapping( - const base::SharedMemoryHandle& handle, - size_t size, - off_t offset) - : WritableUnalignedMapping( - base::UnsafeSharedMemoryRegion::CreateFromHandle(handle), - size, - offset) {} - WritableUnalignedMapping::~WritableUnalignedMapping() = default; void* WritableUnalignedMapping::memory() const {
diff --git a/media/base/unaligned_shared_memory.h b/media/base/unaligned_shared_memory.h index 7e3cbbae..46341ca 100644 --- a/media/base/unaligned_shared_memory.h +++ b/media/base/unaligned_shared_memory.h
@@ -8,6 +8,7 @@ #include <stdint.h> #include "base/macros.h" +#include "base/memory/platform_shared_memory_region.h" #include "base/memory/read_only_shared_memory_region.h" #include "base/memory/shared_memory.h" #include "base/memory/shared_memory_mapping.h" @@ -26,23 +27,38 @@ UnalignedSharedMemory(const base::SharedMemoryHandle& handle, size_t size, bool read_only); + + // As above, but from a PlatformSharedMemoryRegion. + UnalignedSharedMemory(base::subtle::PlatformSharedMemoryRegion region, + size_t size, + bool read_only); + ~UnalignedSharedMemory(); // Map the shared memory region. Note that the passed |size| parameter should // be less than or equal to |size()|. bool MapAt(off_t offset, size_t size); size_t size() const { return size_; } - void* memory() const; + void* memory() const { return mapping_ptr_; } private: + // Either |shm_| or the set |region_| and one of the mappings are active, + // depending on which constructor was used and the value of read_only_. These + // variables are held to keep the shared memory mapping valid for the lifetime + // of this instance. base::SharedMemory shm_; + base::subtle::PlatformSharedMemoryRegion region_; + base::WritableSharedMemoryMapping writable_mapping_; + base::ReadOnlySharedMemoryMapping read_only_mapping_; + + // If the mapping should be made read-only. + bool read_only_; // The size of the region associated with |shm_|. size_t size_; - // Offset withing |shm_| memory that data has been mapped; strictly less than - // base::SysInfo::VMAllocationGranularity(). - size_t misalignment_; + // Pointer to the unaligned data in the shared memory mapping. + uint8_t* mapping_ptr_ = nullptr; DISALLOW_COPY_AND_ASSIGN(UnalignedSharedMemory); }; @@ -59,13 +75,6 @@ size_t size, off_t offset); - // As above, but creates from a handle. This region will own the handle. - // DEPRECATED: this should be used only for the legacy shared memory - // conversion project, see https://crbug.com/795291. - WritableUnalignedMapping(const base::SharedMemoryHandle& handle, - size_t size, - off_t offset); - ~WritableUnalignedMapping(); size_t size() const { return size_; }
diff --git a/media/base/unaligned_shared_memory_unittest.cc b/media/base/unaligned_shared_memory_unittest.cc index 067c3e1..f7311ef 100644 --- a/media/base/unaligned_shared_memory_unittest.cc +++ b/media/base/unaligned_shared_memory_unittest.cc
@@ -54,11 +54,32 @@ UnalignedSharedMemory shm(handle, kDataSize, true); } +TEST(UnalignedSharedMemoryTest, CreateAndDestroyRegion) { + auto region = CreateRegion(kData, kDataSize); + UnalignedSharedMemory shm( + base::UnsafeSharedMemoryRegion::TakeHandleForSerialization( + std::move(region)), + kDataSize, false); +} + +TEST(UnalignedSharedMemoryTest, CreateAndDestroyReadOnlyRegion) { + auto region = CreateReadOnlyRegion(kData, kDataSize); + UnalignedSharedMemory shm( + base::ReadOnlySharedMemoryRegion::TakeHandleForSerialization( + std::move(region)), + kDataSize, true); +} + TEST(UnalignedSharedMemoryTest, CreateAndDestroy_InvalidHandle) { base::SharedMemoryHandle handle; UnalignedSharedMemory shm(handle, kDataSize, true); } +TEST(UnalignedSharedMemoryTest, CreateAndDestroy_InvalidRegion) { + UnalignedSharedMemory shm(base::subtle::PlatformSharedMemoryRegion(), + kDataSize, false); +} + TEST(UnalignedSharedMemoryTest, Map) { auto handle = CreateHandle(kData, kDataSize); UnalignedSharedMemory shm(handle, kDataSize, true); @@ -66,6 +87,26 @@ EXPECT_EQ(0, memcmp(shm.memory(), kData, kDataSize)); } +TEST(UnalignedSharedMemoryTest, MapRegion) { + auto region = CreateRegion(kData, kDataSize); + UnalignedSharedMemory shm( + base::UnsafeSharedMemoryRegion::TakeHandleForSerialization( + std::move(region)), + kDataSize, false); + ASSERT_TRUE(shm.MapAt(0, kDataSize)); + EXPECT_EQ(0, memcmp(shm.memory(), kData, kDataSize)); +} + +TEST(UnalignedSharedMemoryTest, MapReadOnlyRegion) { + auto region = CreateReadOnlyRegion(kData, kDataSize); + UnalignedSharedMemory shm( + base::ReadOnlySharedMemoryRegion::TakeHandleForSerialization( + std::move(region)), + kDataSize, true); + ASSERT_TRUE(shm.MapAt(0, kDataSize)); + EXPECT_EQ(0, memcmp(shm.memory(), kData, kDataSize)); +} + TEST(UnalignedSharedMemoryTest, Map_Unaligned) { auto handle = CreateHandle(kUnalignedData, kUnalignedDataSize); UnalignedSharedMemory shm(handle, kUnalignedDataSize, true); @@ -73,6 +114,26 @@ EXPECT_EQ(0, memcmp(shm.memory(), kData, kDataSize)); } +TEST(UnalignedSharedMemoryTest, Map_UnalignedRegion) { + auto region = CreateRegion(kUnalignedData, kUnalignedDataSize); + UnalignedSharedMemory shm( + base::UnsafeSharedMemoryRegion::TakeHandleForSerialization( + std::move(region)), + kUnalignedDataSize, false); + ASSERT_TRUE(shm.MapAt(kUnalignedOffset, kDataSize)); + EXPECT_EQ(0, memcmp(shm.memory(), kData, kDataSize)); +} + +TEST(UnalignedSharedMemoryTest, Map_UnalignedReadOnlyRegion) { + auto region = CreateReadOnlyRegion(kUnalignedData, kUnalignedDataSize); + UnalignedSharedMemory shm( + base::ReadOnlySharedMemoryRegion::TakeHandleForSerialization( + std::move(region)), + kUnalignedDataSize, true); + ASSERT_TRUE(shm.MapAt(kUnalignedOffset, kDataSize)); + EXPECT_EQ(0, memcmp(shm.memory(), kData, kDataSize)); +} + TEST(UnalignedSharedMemoryTest, Map_InvalidHandle) { base::SharedMemoryHandle handle; UnalignedSharedMemory shm(handle, kDataSize, true); @@ -80,42 +141,91 @@ EXPECT_EQ(shm.memory(), nullptr); } +TEST(UnalignedSharedMemoryTest, Map_InvalidRegion) { + UnalignedSharedMemory shm(base::subtle::PlatformSharedMemoryRegion(), + kDataSize, true); + ASSERT_FALSE(shm.MapAt(1, kDataSize)); + EXPECT_EQ(shm.memory(), nullptr); +} + TEST(UnalignedSharedMemoryTest, Map_NegativeOffset) { auto handle = CreateHandle(kData, kDataSize); UnalignedSharedMemory shm(handle, kDataSize, true); ASSERT_FALSE(shm.MapAt(-1, kDataSize)); } +TEST(UnalignedSharedMemoryTest, Map_NegativeOffsetRegion) { + auto region = CreateRegion(kData, kDataSize); + UnalignedSharedMemory shm( + base::UnsafeSharedMemoryRegion::TakeHandleForSerialization( + std::move(region)), + kDataSize, false); + ASSERT_FALSE(shm.MapAt(-1, kDataSize)); +} + +TEST(UnalignedSharedMemoryTest, Map_NegativeOffsetReadOnlyRegion) { + auto region = CreateReadOnlyRegion(kData, kDataSize); + UnalignedSharedMemory shm( + base::ReadOnlySharedMemoryRegion::TakeHandleForSerialization( + std::move(region)), + kDataSize, true); + ASSERT_FALSE(shm.MapAt(-1, kDataSize)); +} + TEST(UnalignedSharedMemoryTest, Map_SizeOverflow) { auto handle = CreateHandle(kData, kDataSize); UnalignedSharedMemory shm(handle, kDataSize, true); ASSERT_FALSE(shm.MapAt(1, std::numeric_limits<size_t>::max())); } +TEST(UnalignedSharedMemoryTest, Map_SizeOverflowRegion) { + auto region = CreateRegion(kData, kDataSize); + UnalignedSharedMemory shm( + base::UnsafeSharedMemoryRegion::TakeHandleForSerialization( + std::move(region)), + kDataSize, false); + ASSERT_FALSE(shm.MapAt(1, std::numeric_limits<size_t>::max())); +} + +TEST(UnalignedSharedMemoryTest, Map_SizeOverflowReadOnlyRegion) { + auto region = CreateReadOnlyRegion(kData, kDataSize); + UnalignedSharedMemory shm( + base::ReadOnlySharedMemoryRegion::TakeHandleForSerialization( + std::move(region)), + kDataSize, true); + ASSERT_FALSE(shm.MapAt(1, std::numeric_limits<size_t>::max())); +} + TEST(UnalignedSharedMemoryTest, UnmappedIsNullptr) { auto handle = CreateHandle(kData, kDataSize); UnalignedSharedMemory shm(handle, kDataSize, true); ASSERT_EQ(shm.memory(), nullptr); } +TEST(UnalignedSharedMemoryTest, UnmappedRegionIsNullptr) { + auto region = CreateRegion(kData, kDataSize); + UnalignedSharedMemory shm( + base::UnsafeSharedMemoryRegion::TakeHandleForSerialization( + std::move(region)), + kDataSize, false); + ASSERT_EQ(shm.memory(), nullptr); +} + +TEST(UnalignedSharedMemoryTest, UnmappedReadOnlyRegionIsNullptr) { + auto region = CreateReadOnlyRegion(kData, kDataSize); + UnalignedSharedMemory shm( + base::ReadOnlySharedMemoryRegion::TakeHandleForSerialization( + std::move(region)), + kDataSize, true); + ASSERT_EQ(shm.memory(), nullptr); +} + TEST(WritableUnalignedMappingTest, CreateAndDestroy) { auto region = CreateRegion(kData, kDataSize); WritableUnalignedMapping shm(region, kDataSize, 0); EXPECT_TRUE(shm.IsValid()); } -TEST(WritableUnalignedMappingTest, CreateAndDestroy_InvalidHandle) { - base::SharedMemoryHandle handle; - WritableUnalignedMapping shm(handle, kDataSize, 0); - EXPECT_FALSE(shm.IsValid()); -} - -TEST(WritableUnalignedMappingTest, CreateAndDestroyHandle) { - auto handle = CreateHandle(kData, kDataSize); - WritableUnalignedMapping shm(handle, kDataSize, 0); - EXPECT_TRUE(shm.IsValid()); -} - TEST(WritableUnalignedMappingTest, CreateAndDestroy_InvalidRegion) { base::UnsafeSharedMemoryRegion region; WritableUnalignedMapping shm(region, kDataSize, 0); @@ -136,13 +246,6 @@ EXPECT_EQ(0, memcmp(shm.memory(), kData, kDataSize)); } -TEST(WritableUnalignedMappingTest, Map_UnalignedHandle) { - auto region = CreateHandle(kUnalignedData, kUnalignedDataSize); - WritableUnalignedMapping shm(region, kDataSize, kUnalignedOffset); - ASSERT_TRUE(shm.IsValid()); - EXPECT_EQ(0, memcmp(shm.memory(), kData, kDataSize)); -} - TEST(WritableUnalignedMappingTest, Map_InvalidRegion) { base::UnsafeSharedMemoryRegion region; WritableUnalignedMapping shm(region, kDataSize, 0);
diff --git a/media/gpu/fake_mjpeg_decode_accelerator.cc b/media/gpu/fake_mjpeg_decode_accelerator.cc index 66ce3dd..94a3424e 100644 --- a/media/gpu/fake_mjpeg_decode_accelerator.cc +++ b/media/gpu/fake_mjpeg_decode_accelerator.cc
@@ -41,11 +41,10 @@ const scoped_refptr<VideoFrame>& video_frame) { DCHECK(io_task_runner_->BelongsToCurrentThread()); - std::unique_ptr<WritableUnalignedMapping> src_shm( - new WritableUnalignedMapping(bitstream_buffer.handle(), - bitstream_buffer.size(), - bitstream_buffer.offset())); - if (!src_shm->IsValid()) { + auto src_shm = std::make_unique<UnalignedSharedMemory>( + bitstream_buffer.handle(), bitstream_buffer.size(), + false /* read_only */); + if (!src_shm->MapAt(bitstream_buffer.offset(), bitstream_buffer.size())) { DLOG(ERROR) << "Unable to map shared memory in FakeMjpegDecodeAccelerator"; NotifyError(bitstream_buffer.id(), MjpegDecodeAccelerator::UNREADABLE_INPUT); @@ -63,7 +62,7 @@ void FakeMjpegDecodeAccelerator::DecodeOnDecoderThread( const BitstreamBuffer& bitstream_buffer, const scoped_refptr<VideoFrame>& video_frame, - std::unique_ptr<WritableUnalignedMapping> src_shm) { + std::unique_ptr<UnalignedSharedMemory> src_shm) { DCHECK(decoder_task_runner_->BelongsToCurrentThread()); // Do not actually decode the Jpeg data.
diff --git a/media/gpu/fake_mjpeg_decode_accelerator.h b/media/gpu/fake_mjpeg_decode_accelerator.h index 30d9178..c6e56f6 100644 --- a/media/gpu/fake_mjpeg_decode_accelerator.h +++ b/media/gpu/fake_mjpeg_decode_accelerator.h
@@ -41,7 +41,7 @@ private: void DecodeOnDecoderThread(const BitstreamBuffer& bitstream_buffer, const scoped_refptr<VideoFrame>& video_frame, - std::unique_ptr<WritableUnalignedMapping> src_shm); + std::unique_ptr<UnalignedSharedMemory> src_shm); void NotifyError(int32_t bitstream_buffer_id, Error error); void NotifyErrorOnClientThread(int32_t bitstream_buffer_id, Error error); void OnDecodeDoneOnClientThread(int32_t input_buffer_id);
diff --git a/remoting/ios/facade/host_info.cc b/remoting/ios/facade/host_info.cc index a1cf275..e37817f4 100644 --- a/remoting/ios/facade/host_info.cc +++ b/remoting/ios/facade/host_info.cc
@@ -14,68 +14,87 @@ HostInfo::~HostInfo() {} -bool HostInfo::ParseHostInfo(const base::DictionaryValue& host_info) { - const base::ListValue* list_value = nullptr; - +bool HostInfo::ParseHostInfo(const base::Value& host_info) { // Add TokenUrlPatterns to HostInfo. - if (host_info.GetList("tokenUrlPatterns", &list_value)) { - if (!list_value->empty()) { - for (const auto& item : *list_value) { - std::string token_url_pattern; - if (!item.GetAsString(&token_url_pattern)) { - return false; - } - token_url_patterns.push_back(token_url_pattern); + const base::Value* list_value = host_info.FindListKey("tokenUrlPatterns"); + if (list_value) { + for (const base::Value& item : list_value->GetList()) { + if (!item.is_string()) { + return false; } + token_url_patterns.push_back(item.GetString()); } } - std::string response_status; - host_info.GetString("status", &response_status); - if (response_status == "ONLINE") { + const std::string* string_value; + + string_value = host_info.FindStringKey("status"); + if (string_value && *string_value == "ONLINE") { status = kHostStatusOnline; - } else if (response_status == "OFFLINE") { + } else if (string_value && *string_value == "OFFLINE") { status = kHostStatusOffline; } else { - LOG(ERROR) << "Unknown response status: " << response_status; + LOG(ERROR) << "Unknown response status: " + << (string_value ? *string_value : "<unset>"); return false; } - if (!host_info.GetString("hostId", &host_id)) { + string_value = host_info.FindStringKey("hostId"); + if (string_value) { + host_id = *string_value; + } else { LOG(ERROR) << "hostId was not found in host_info"; return false; } - if (!host_info.GetString("hostName", &host_name)) { + string_value = host_info.FindStringKey("hostName"); + if (string_value) { + host_name = *string_value; + } else { LOG(ERROR) << "hostName was not found in host_info"; return false; } - if (!host_info.GetString("publicKey", &public_key)) { + string_value = host_info.FindStringKey("publicKey"); + if (string_value) { + public_key = *string_value; + } else { LOG(ERROR) << "publicKey was not found for " << host_name; return false; } // If the host entry was created but the host was never online, then the jid // is never set. - if (!host_info.GetString("jabberId", &host_jid) && - status == kHostStatusOnline) { + string_value = host_info.FindStringKey("jabberId"); + if (string_value) { + host_jid = *string_value; + } else if (status == kHostStatusOnline) { LOG(ERROR) << host_name << " is online but is missing a jabberId"; return false; } - std::string updated_time_iso; - if (host_info.GetString("updatedTime", &updated_time_iso)) { - if (!base::Time::FromString(updated_time_iso.c_str(), &updated_time)) { + string_value = host_info.FindStringKey("updatedTime"); + if (string_value) { + if (!base::Time::FromString(string_value->c_str(), &updated_time)) { LOG(WARNING) << "Failed to parse updatedTime"; } } - host_info.GetString("hostOs", &host_os); - host_info.GetString("hostOsVersion", &host_os_version); - host_info.GetString("hostVersion", &host_version); + string_value = host_info.FindStringKey("hostOs"); + if (string_value) + host_os = *string_value; - host_info.GetString("hostOfflineReason", &offline_reason); + string_value = host_info.FindStringKey("hostOsVersion"); + if (string_value) + host_os_version = *string_value; + + string_value = host_info.FindStringKey("hostVersion"); + if (string_value) + host_version = *string_value; + + string_value = host_info.FindStringKey("hostOfflineReason"); + if (string_value) + offline_reason = *string_value; return true; }
diff --git a/remoting/ios/facade/host_info.h b/remoting/ios/facade/host_info.h index d8c5194..6f7f4e0 100644 --- a/remoting/ios/facade/host_info.h +++ b/remoting/ios/facade/host_info.h
@@ -23,7 +23,7 @@ ~HostInfo(); // Returns true if |host_info| is valid and initializes HostInfo. - bool ParseHostInfo(const base::DictionaryValue& host_info); + bool ParseHostInfo(const base::Value& host_info); // Returns true if the chromoting host is ready to accept connections. bool IsReadyForConnection() const;
diff --git a/remoting/ios/facade/host_list_fetcher.cc b/remoting/ios/facade/host_list_fetcher.cc index 8ce7eb18..485da78 100644 --- a/remoting/ios/facade/host_list_fetcher.cc +++ b/remoting/ios/facade/host_list_fetcher.cc
@@ -101,37 +101,34 @@ return false; } - std::unique_ptr<base::Value> response_value( - base::JSONReader::ReadDeprecated(response_string)); - if (!response_value || !response_value->is_dict()) { + base::Optional<base::Value> response = + base::JSONReader::Read(response_string); + if (!response) { LOG(ERROR) << "Failed to parse response string to JSON"; return false; } - const base::DictionaryValue* response; - if (!response_value->GetAsDictionary(&response)) { - LOG(ERROR) << "Failed to convert parsed JSON to a dictionary object"; + if (!response->is_dict()) { + LOG(ERROR) << "Parsed JSON is not a dictionary"; return false; } - const base::DictionaryValue* data = nullptr; - if (!response->GetDictionary("data", &data)) { + const base::Value* data = response->FindDictKey("data"); + if (!data) { LOG(ERROR) << "Hostlist response data is empty"; return false; } - const base::ListValue* hosts = nullptr; - if (!data->GetList("items", &hosts)) { + const base::Value* hosts = data->FindListKey("items"); + if (!hosts) { // This will happen if the user has no host. return true; } // Any host_info with malformed data will not be added to the hostlist. - const base::DictionaryValue* host_dict; - for (const auto& host_info : *hosts) { + for (const base::Value& host_info : hosts->GetList()) { remoting::HostInfo host; - if (host_info.GetAsDictionary(&host_dict) && - host.ParseHostInfo(*host_dict)) { + if (host_info.is_dict() && host.ParseHostInfo(host_info)) { hostlist->push_back(host); } }
diff --git a/remoting/test/host_info.cc b/remoting/test/host_info.cc index 54cc3bb..7393e03 100644 --- a/remoting/test/host_info.cc +++ b/remoting/test/host_info.cc
@@ -14,57 +14,68 @@ HostInfo::~HostInfo() = default; -bool HostInfo::ParseHostInfo(const base::DictionaryValue& host_info) { - const base::ListValue* list_value = nullptr; - +bool HostInfo::ParseHostInfo(const base::Value& host_info) { // Add TokenUrlPatterns to HostInfo. - if (host_info.GetList("tokenUrlPatterns", &list_value)) { - if (!list_value->empty()) { - for (const auto& item : *list_value) { - std::string token_url_pattern; - if (!item.GetAsString(&token_url_pattern)) { - return false; - } - token_url_patterns.push_back(token_url_pattern); + const base::Value* list_value = host_info.FindListKey("tokenUrlPatterns"); + if (list_value) { + for (const base::Value& item : list_value->GetList()) { + if (!item.is_string()) { + return false; } + token_url_patterns.push_back(item.GetString()); } } - std::string response_status; - host_info.GetString("status", &response_status); - if (response_status == "ONLINE") { + const std::string* string_value; + + string_value = host_info.FindStringKey("status"); + if (string_value && *string_value == "ONLINE") { status = kHostStatusOnline; - } else if (response_status == "OFFLINE") { + } else if (string_value && *string_value == "OFFLINE") { status = kHostStatusOffline; } else { - LOG(ERROR) << "Response Status is " << response_status; + LOG(ERROR) << "Response Status is " + << (string_value ? *string_value : "<unset>"); return false; } - if (!host_info.GetString("hostId", &host_id)) { + string_value = host_info.FindStringKey("hostId"); + if (string_value) { + host_id = *string_value; + } else { LOG(ERROR) << "hostId was not found in host_info"; return false; } - if (!host_info.GetString("hostName", &host_name)) { + string_value = host_info.FindStringKey("hostName"); + if (string_value) { + host_name = *string_value; + } else { LOG(ERROR) << "hostName was not found in host_info"; return false; } - if (!host_info.GetString("publicKey", &public_key)) { + string_value = host_info.FindStringKey("publicKey"); + if (string_value) { + public_key = *string_value; + } else { LOG(ERROR) << "publicKey was not found for " << host_name; return false; } // If the host entry was created but the host was never online, then the jid // is never set. - if (!host_info.GetString("jabberId", &host_jid) && - status == kHostStatusOnline) { + string_value = host_info.FindStringKey("jabberId"); + if (string_value) { + host_jid = *string_value; + } else if (status == kHostStatusOnline) { LOG(ERROR) << host_name << " is online but is missing a jabberId"; return false; } - host_info.GetString("hostOfflineReason", &offline_reason); + string_value = host_info.FindStringKey("hostOfflineReason"); + if (string_value) + offline_reason = *string_value; return true; }
diff --git a/remoting/test/host_info.h b/remoting/test/host_info.h index 41161a3..88feea88 100644 --- a/remoting/test/host_info.h +++ b/remoting/test/host_info.h
@@ -25,7 +25,7 @@ ~HostInfo(); // Returns true if |host_info| is valid and initializes HostInfo. - bool ParseHostInfo(const base::DictionaryValue& host_info); + bool ParseHostInfo(const base::Value& host_info); // Returns true if the chromoting host is ready to accept connections. bool IsReadyForConnection() const;
diff --git a/remoting/test/host_list_fetcher.cc b/remoting/test/host_list_fetcher.cc index 08f893a..a0b9bb76 100644 --- a/remoting/test/host_list_fetcher.cc +++ b/remoting/test/host_list_fetcher.cc
@@ -58,37 +58,34 @@ return false; } - std::unique_ptr<base::Value> response_value( - base::JSONReader::ReadDeprecated(response_string)); - if (!response_value || !response_value->is_dict()) { + base::Optional<base::Value> response = + base::JSONReader::Read(response_string); + if (!response) { LOG(ERROR) << "Failed to parse response string to JSON"; return false; } - const base::DictionaryValue* response; - if (!response_value->GetAsDictionary(&response)) { - LOG(ERROR) << "Failed to convert parsed JSON to a dictionary object"; + if (!response->is_dict()) { + LOG(ERROR) << "Parsed JSON is not a dictionary object"; return false; } - const base::DictionaryValue* data = nullptr; - if (!response->GetDictionary("data", &data)) { + const base::Value* data = response->FindDictKey("data"); + if (!data) { LOG(ERROR) << "Hostlist response data is empty"; return false; } - const base::ListValue* hosts = nullptr; - if (!data->GetList("items", &hosts)) { + const base::Value* hosts = data->FindListKey("items"); + if (!hosts) { LOG(ERROR) << "Failed to find hosts in Hostlist response data"; return false; } // Any host_info with malformed data will not be added to the hostlist. - const base::DictionaryValue* host_dict; - for (const auto& host_info : *hosts) { + for (const base::Value& host_info : hosts->GetList()) { HostInfo host; - if (host_info.GetAsDictionary(&host_dict) && - host.ParseHostInfo(*host_dict)) { + if (host_info.is_dict() && host.ParseHostInfo(host_info)) { hostlist->push_back(host); } }
diff --git a/services/identity/public/README.md b/services/identity/public/README.md index 83a0632..d3e9793 100644 --- a/services/identity/public/README.md +++ b/services/identity/public/README.md
@@ -1,13 +1,8 @@ //services/identity/public/cpp contains the next-generation C++ API for -interacting with the user's Google identities. In the long term, this library -will become a client library for the Identity Service. In the present, it is -being developed based directly on the internal C++ classes in -//components/signin and //google_apis/gaia. This library is almost certainly +interacting with the user's Google identities. This library is almost certainly what you want to use if you are developing a browser feature. See -//services/identity/public/cpp/README.md for details. +//services/identity/public/cpp/README.md for details. -If you are looking to connect to the Identity Service, the current way to do so -is via //services/identity/public/mojom. You may wish to do this if you are -developing a feature that is intended to run out of the browser process and -does not require having a view of Google identity that is synchronously updated -with the view of Google identity that the browser sees. +If you are looking to connect to the Identity Service (e.g., if you are +developing a feature that is intended to run out of the browser process), use +//services/identity/public/mojom.
diff --git a/services/identity/public/cpp/README.md b/services/identity/public/cpp/README.md index 71aa75c..a0dc8c1 100644 --- a/services/identity/public/cpp/README.md +++ b/services/identity/public/cpp/README.md
@@ -1,11 +1,5 @@ IdentityManager is the next-generation C++ API for interacting with Google -identity. It is currently backed by //components/signin (see IMPLEMENTATION -NOTES below); in the long-term it will serve as the primary client-side -interface to the Identity Service, encapsulating a connection to a remote -implementation of identity::mojom::IdentityManager. It provides conveniences -over the bare Identity Service Mojo interfaces such as: - -- Synchronous access to the information of the primary account (via caching) +identity. It is backed by //components/signin. Documentation on the mapping between usage of legacy signin classes (notably SigninManager(Base) and ProfileOAuth2TokenService) and usage of @@ -35,17 +29,3 @@ unittest are interacting with Profile (in particular, where the IdentityManager instance with which the test is interacting must be IdentityManagerFactory::GetForProfile(profile)). - -IMPLEMENTATION NOTES - -The Identity Service client library is being developed in parallel with the -implementation and interfaces of the Identity Service itself. The motivation is -to allow clients to be converted to use this client library in a parallel and -pipelined fashion with building out the Identity Service as the backing -implementation of the library. - -In the near term, this library is backed directly by //components/signin -classes. We are striving to make the interactions of this library with those -classes as similar as possible to its eventual interaction with the Identity -Service. In places where those interactions vary significantly from the -envisioned eventual interaction with the Identity Service, we have placed TODOs.
diff --git a/services/identity/public/cpp/identity_manager.cc b/services/identity/public/cpp/identity_manager.cc index 9e7c7e1..f86be86 100644 --- a/services/identity/public/cpp/identity_manager.cc +++ b/services/identity/public/cpp/identity_manager.cc
@@ -124,9 +124,6 @@ } AccountsInCookieJarInfo IdentityManager::GetAccountsInCookieJar() const { - // TODO(859882): Change this implementation to interact asynchronously with - // GaiaCookieManagerService as detailed in - // https://docs.google.com/document/d/1hcrJ44facCSHtMGBmPusvcoP-fAR300Hi-UFez8ffYQ/edit?pli=1#heading=h.w97eil1cygs2. std::vector<gaia::ListedAccount> signed_in_accounts; std::vector<gaia::ListedAccount> signed_out_accounts; bool accounts_are_fresh = gaia_cookie_manager_service_->ListAccounts( @@ -261,12 +258,6 @@ const std::string& account_id, const identity::ScopeSet& scopes, const std::string& access_token) { - // TODO(843510): Consider making the request to ProfileOAuth2TokenService - // asynchronously once there are no direct clients of PO2TS. This change would - // need to be made together with changing all callsites to - // ProfileOAuth2TokenService::RequestAccessToken() to be made asynchronously - // as well (to maintain ordering in the case where a client removes an access - // token from the cache and then immediately requests an access token). token_service_->InvalidateAccessToken(account_id, scopes, access_token); } @@ -540,8 +531,6 @@ const std::string& account_id, const std::string& consumer_id, const OAuth2TokenService::ScopeSet& scopes) { - // TODO(843510): Consider notifying observers asynchronously once there - // are no direct clients of ProfileOAuth2TokenService. for (auto& observer : diagnostics_observer_list_) { observer.OnAccessTokenRequested(account_id, consumer_id, scopes); }
diff --git a/services/identity/public/cpp/identity_manager.h b/services/identity/public/cpp/identity_manager.h index 17cc6bf..ce490af 100644 --- a/services/identity/public/cpp/identity_manager.h +++ b/services/identity/public/cpp/identity_manager.h
@@ -109,9 +109,6 @@ const GoogleServiceAuthError& error) {} // Called after refresh tokens are loaded. - // CAVEAT: On ChromeOS, this callback is not invoked during - // startup in all cases. See https://crbug.com/749535, which - // details the cases where it's not invoked. virtual void OnRefreshTokensLoaded() {} // Called whenever the list of Gaia accounts in the cookie jar has changed. @@ -177,7 +174,7 @@ bool is_refresh_token_valid, const std::string& source) {} - // Called when a refreh token is removed. Contains diagnostic information + // Called when a refresh token is removed. Contains diagnostic information // about the source that initiated the revokation operation. virtual void OnRefreshTokenRemovedForAccountFromSource( const std::string& account_id, @@ -224,8 +221,7 @@ // string. bool HasPrimaryAccount() const; - // Provides access to the latest cached information of all accounts that have - // refresh tokens. + // Provides the information of all accounts that have refresh tokens. // NOTE: The accounts should not be assumed to be in any particular order; in // particular, they are not guaranteed to be in the order in which the // refresh tokens were added. @@ -236,9 +232,8 @@ std::vector<AccountInfo> GetExtendedAccountInfoForAccountsWithRefreshToken() const; - // Provides access to the latest cached information of all accounts that are - // present in the Gaia cookie in the cookie jar, ordered by their order in - // the cookie. + // Provides the information of all accounts that are present in the Gaia + // cookie in the cookie jar, ordered by their order in the cookie. // If the returned accounts are not fresh, an internal update will be // triggered and there will be a subsequent invocation of // IdentityManager::Observer::OnAccountsInCookieJarChanged(). @@ -328,7 +323,7 @@ AccessTokenFetcher::TokenCallback callback, AccessTokenFetcher::Mode mode); - // If an entry exists in the Identity Service's cache corresponding to the + // If an entry exists in the cache of access tokens corresponding to the // given information, removes that entry; in this case, the next access token // request for |account_id| and |scopes| will fetch a new token from the // network. Otherwise, is a no-op. @@ -635,10 +630,7 @@ void OnAccountUpdated(const AccountInfo& info) override; void OnAccountRemoved(const AccountInfo& info) override; - // Backing signin classes. NOTE: We strive to limit synchronous access to - // these classes in the IdentityManager implementation, as all such - // synchronous access will become impossible when IdentityManager is - // backed by the Identity Service. + // Backing signin classes. std::unique_ptr<AccountTrackerService> account_tracker_service_; std::unique_ptr<ProfileOAuth2TokenService> token_service_; std::unique_ptr<GaiaCookieManagerService> gaia_cookie_manager_service_;
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index eda6dfb..86b63b1 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -5947,6 +5947,23 @@ ] } ], + "WebRTC-BweAllocProbingOnlyInAlr": [ + { + "platforms": [ + "windows", + "mac", + "chromeos", + "linux", + "ios", + "android" + ], + "experiments": [ + { + "name": "Enabled" + } + ] + } + ], "WebRTC-EnableWebRtcEcdsa": [ { "platforms": [
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc index 73af4e8..ca20e7e8 100644 --- a/third_party/blink/common/features.cc +++ b/third_party/blink/common/features.cc
@@ -218,6 +218,10 @@ const base::Feature kNativeFileSystemAPI{"NativeFileSystemAPI", base::FEATURE_DISABLED_BY_DEFAULT}; +// File handling integration. https://crbug.com/829689 +const base::Feature kFileHandlingAPI{"FileHandlingAPI", + base::FEATURE_DISABLED_BY_DEFAULT}; + // Allows for synchronous XHR requests during page dismissal const base::Feature kForbidSyncXHRInPageDismissal{ "ForbidSyncXHRInPageDismissal", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h index 139c5c1..d2213d3 100644 --- a/third_party/blink/public/common/features.h +++ b/third_party/blink/public/common/features.h
@@ -64,6 +64,7 @@ BLINK_COMMON_EXPORT extern const base::Feature kTextFragmentAnchor; BLINK_COMMON_EXPORT extern const base::Feature kWasmCodeCache; BLINK_COMMON_EXPORT extern const base::Feature kNativeFileSystemAPI; +BLINK_COMMON_EXPORT extern const base::Feature kFileHandlingAPI; BLINK_COMMON_EXPORT extern const base::Feature kForbidSyncXHRInPageDismissal; BLINK_COMMON_EXPORT extern const base::Feature kRestrictDeviceSensorEventsToSecureContexts;
diff --git a/third_party/blink/public/mojom/BUILD.gn b/third_party/blink/public/mojom/BUILD.gn index df8b95c6..cc5dd20 100644 --- a/third_party/blink/public/mojom/BUILD.gn +++ b/third_party/blink/public/mojom/BUILD.gn
@@ -66,6 +66,7 @@ "manifest/display_mode.mojom", "manifest/manifest.mojom", "manifest/manifest_manager.mojom", + "manifest/manifest_observer.mojom", "mediastream/media_devices.mojom", "mediastream/media_stream.mojom", "mime/mime_registry.mojom", @@ -193,6 +194,7 @@ "installedapp/installed_app_provider.mojom", "installedapp/related_application.mojom", "mediasession/media_session.mojom", + "payments/payment_handler_host.mojom", "payments/payment_request.mojom", "remote_objects/remote_objects.mojom", "webauthn/authenticator.mojom",
diff --git a/content/common/manifest_observer.mojom b/third_party/blink/public/mojom/manifest/manifest_observer.mojom similarity index 92% rename from content/common/manifest_observer.mojom rename to third_party/blink/public/mojom/manifest/manifest_observer.mojom index ad8cb03..1d2be9c 100644 --- a/content/common/manifest_observer.mojom +++ b/third_party/blink/public/mojom/manifest/manifest_observer.mojom
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -module content.mojom; +module blink.mojom; import "url/mojom/url.mojom";
diff --git a/third_party/blink/public/mojom/payments/payment_app.mojom b/third_party/blink/public/mojom/payments/payment_app.mojom index 49c95cf..4e7c72f 100644 --- a/third_party/blink/public/mojom/payments/payment_app.mojom +++ b/third_party/blink/public/mojom/payments/payment_app.mojom
@@ -8,6 +8,7 @@ import "mojo/public/mojom/base/time.mojom"; import "third_party/blink/public/mojom/manifest/manifest.mojom"; import "third_party/blink/public/mojom/payments/payment_request.mojom"; +import "third_party/blink/public/mojom/payments/payment_handler_host.mojom"; import "url/mojom/url.mojom"; enum PaymentHandlerStatus { @@ -76,6 +77,10 @@ PaymentCurrencyAmount total; array<PaymentDetailsModifier> modifiers; string instrument_key; + + // Handles events raised by the payment handler, such as "payment method + // changed" event. Null in content_browsertests. + PaymentHandlerHost? payment_handler_host; }; // This struct is provided to receive payment app response from render
diff --git a/third_party/blink/public/mojom/payments/payment_handler_host.mojom b/third_party/blink/public/mojom/payments/payment_handler_host.mojom new file mode 100644 index 0000000..b951796 --- /dev/null +++ b/third_party/blink/public/mojom/payments/payment_handler_host.mojom
@@ -0,0 +1,65 @@ +// 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. + +[JavaPackage="org.chromium.payments.mojom"] +module payments.mojom; + +import "components/payments/mojom/payment_request_data.mojom"; + +struct PaymentHandlerMethodData { + // Either a short string (e.g., "basic-string") or URL (e.g., + // "https://google.com/pay") payment method name. + string method_name; + + // A JSON string built by the renderer from a JavaScript object that the + // website provides. The renderer uses blink::JSONObject::toJSONString() to + // generate this string. The browser does not parse the string and passes it + // as-is directly to the payment handler. There's no one format for this + // object, so more specific types cannot be used. A simple example: + // + // {"supportedNetworks": ["visa"]} + string stringified_data; +}; + +struct PaymentHandlerModifier { + PaymentCurrencyAmount? total; + PaymentHandlerMethodData method_data; +}; + +// Constructed by the browser based on PaymentDetails from the Merchant +// renderer. The browser sends this to the Payment Handler renderer. +struct PaymentMethodChangeResponse { + PaymentCurrencyAmount? total; + array<PaymentHandlerModifier>? modifiers; + string error = ""; + string? stringified_payment_method_errors; +}; + +// The interface for a PaymentRequest object in the browser, so a PaymentHandler +// renderer can talk to it. +// +// Implemented in the browser process. Not sandboxed. +// Desktop (Windows, ChromeOS, Linux, MacOS) implementation: +// components/payments/content/payment_request.h +interface PaymentHandlerHost { + // Called by the Payment Handler renderer to let the browser know that the + // user has selected a different payment instrument. + // + // The browser validates the |method_data| and passes it on to the Merchant + // renderer via + // PaymentRequestClient.OnPaymentMethodChange(method_name,stringified_data), + // defined in third_party/blink/public/mojom/payments/payment_request.mojom. + // + // The Merchant renderer than responds to the browser via + // PaymentRequest.UpdateWith(details) to update the total based on the + // selected instrument or PaymentRequest.NoUpdatedPaymentDetails() if the + // total is unchanged. The total can change, for example, based on the + // billing address of the selected instrument. + // + // The browser validates the |details| from the Merchant renderer and sends + // their subset to the Payment Handler renderer as + // |PaymentMethodChangeResponse|, so it can show the updated total. + ChangePaymentMethod(PaymentHandlerMethodData method_data) => + (PaymentMethodChangeResponse response_data); +};
diff --git a/third_party/blink/public/mojom/payments/payment_request.mojom b/third_party/blink/public/mojom/payments/payment_request.mojom index 66b6cbc..07f0ead 100644 --- a/third_party/blink/public/mojom/payments/payment_request.mojom +++ b/third_party/blink/public/mojom/payments/payment_request.mojom
@@ -161,6 +161,8 @@ // by PaymentDetailsUpdate (next to PaymentDetailsInit) but // PaymentDetailsUpdate has no id. string? id; + + string? stringified_payment_method_errors; }; enum PaymentShippingType {
diff --git a/third_party/blink/public/platform/modules/payments/web_payment_request_event_data.h b/third_party/blink/public/platform/modules/payments/web_payment_request_event_data.h index ac4917a8..0fb042af 100644 --- a/third_party/blink/public/platform/modules/payments/web_payment_request_event_data.h +++ b/third_party/blink/public/platform/modules/payments/web_payment_request_event_data.h
@@ -5,6 +5,7 @@ #ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PAYMENTS_WEB_PAYMENT_REQUEST_EVENT_DATA_H_ #define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PAYMENTS_WEB_PAYMENT_REQUEST_EVENT_DATA_H_ +#include "mojo/public/cpp/system/message_pipe.h" #include "third_party/blink/public/platform/modules/payments/web_can_make_payment_event_data.h" #include "third_party/blink/public/platform/modules/payments/web_payment_currency_amount.h" #include "third_party/blink/public/platform/web_string.h" @@ -15,6 +16,8 @@ WebString payment_request_id; WebString instrument_key; WebPaymentCurrencyAmount total; + // For payments::mojom::blink::PaymentHandlerHost. + mojo::ScopedMessagePipeHandle payment_handler_host_handle; }; } // namespace blink
diff --git a/third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h b/third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h index 70834c8..af7d4c2 100644 --- a/third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h +++ b/third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h
@@ -126,7 +126,7 @@ virtual void DispatchPaymentRequestEvent( int event_id, - const WebPaymentRequestEventData&) = 0; + std::unique_ptr<WebPaymentRequestEventData>) = 0; virtual void OnNavigationPreloadResponse( int fetch_event_id,
diff --git a/third_party/blink/public/web/web_document.h b/third_party/blink/public/web/web_document.h index 14c13ae1..19117da 100644 --- a/third_party/blink/public/web/web_document.h +++ b/third_party/blink/public/web/web_document.h
@@ -123,8 +123,6 @@ BLINK_EXPORT WebVector<WebDraggableRegion> DraggableRegions() const; - BLINK_EXPORT WebURL ManifestURL() const; - BLINK_EXPORT WebURL CanonicalUrlForSharing() const; BLINK_EXPORT WebDistillabilityFeatures DistillabilityFeatures();
diff --git a/third_party/blink/public/web/web_local_frame_client.h b/third_party/blink/public/web/web_local_frame_client.h index dd31111..dfc009f 100644 --- a/third_party/blink/public/web/web_local_frame_client.h +++ b/third_party/blink/public/web/web_local_frame_client.h
@@ -484,9 +484,6 @@ // WARNING: This method may be called very frequently. virtual void DidUpdateCurrentHistoryItem() {} - // The frame's manifest has changed. - virtual void DidChangeManifest() {} - // The frame's theme color has changed. virtual void DidChangeThemeColor() {}
diff --git a/third_party/blink/public/web/web_manifest_manager.h b/third_party/blink/public/web/web_manifest_manager.h index 0052ef2f..2fc6c9a 100644 --- a/third_party/blink/public/web/web_manifest_manager.h +++ b/third_party/blink/public/web/web_manifest_manager.h
@@ -23,7 +23,6 @@ virtual ~WebManifestManager() = default; virtual void RequestManifest(WebCallback callback) = 0; - virtual bool CanFetchManifest() = 0; }; } // namespace blink
diff --git a/third_party/blink/renderer/bindings/modules/BUILD.gn b/third_party/blink/renderer/bindings/modules/BUILD.gn index 251dc682..86baaa73 100644 --- a/third_party/blink/renderer/bindings/modules/BUILD.gn +++ b/third_party/blink/renderer/bindings/modules/BUILD.gn
@@ -40,6 +40,7 @@ "//third_party/blink/renderer/modules/payments/can_make_payment_event.idl", "//third_party/blink/renderer/modules/payments/merchant_validation_event.idl", "//third_party/blink/renderer/modules/payments/payment_method_change_event.idl", + "//third_party/blink/renderer/modules/payments/payment_method_change_response.idl", "//third_party/blink/renderer/modules/payments/payment_request_event.idl", "//third_party/blink/renderer/modules/payments/payment_request_update_event.idl", "//third_party/blink/renderer/modules/peerconnection/rtc_data_channel_event.idl",
diff --git a/third_party/blink/renderer/core/css/parser/css_property_parser_test.cc b/third_party/blink/renderer/core/css/parser/css_property_parser_test.cc index d25892af..2c309c0 100644 --- a/third_party/blink/renderer/core/css/parser/css_property_parser_test.cc +++ b/third_party/blink/renderer/core/css/parser/css_property_parser_test.cc
@@ -442,9 +442,9 @@ return UseCounter::IsCounted(GetDocument(), feature); } - private: Document& GetDocument() { return dummy_page_holder_->GetDocument(); } + private: std::unique_ptr<DummyPageHolder> dummy_page_holder_; }; @@ -518,6 +518,18 @@ EXPECT_TRUE(IsCounted(feature)); } +TEST_F(CSSPropertyUseCounterTest, UnitlessPresentationAttributesNotCounted) { + WebFeature feature = WebFeature::kSVGGeometryPropertyHasNonZeroUnitlessValue; + EXPECT_FALSE(IsCounted(feature)); + GetDocument().body()->SetInnerHTMLFromString(R"HTML( + <svg> + <rect x="42" y="42" rx="42" ry="42"/> + <circle cx="42" cy="42" r="42"/> + </svg> + )HTML"); + EXPECT_FALSE(IsCounted(feature)); +} + TEST_F(CSSPropertyUseCounterTest, CSSPropertyAnimationNameCustomIdentUseCount) { WebFeature feature = WebFeature::kDefaultInCustomIdent; EXPECT_FALSE(IsCounted(feature));
diff --git a/third_party/blink/renderer/core/css/properties/computed_style_utils.cc b/third_party/blink/renderer/core/css/properties/computed_style_utils.cc index d9fbad0..eeb8310d 100644 --- a/third_party/blink/renderer/core/css/properties/computed_style_utils.cc +++ b/third_party/blink/renderer/core/css/properties/computed_style_utils.cc
@@ -2116,11 +2116,10 @@ case EBreakBetween::kColumn: case EBreakBetween::kRecto: case EBreakBetween::kVerso: - return CSSIdentifierValue::Create(CSSValueID::kAuto); + case EBreakBetween::kAvoidPage: + return nullptr; case EBreakBetween::kPage: return CSSIdentifierValue::Create(CSSValueID::kAlways); - case EBreakBetween::kAvoidPage: - return CSSIdentifierValue::Create(CSSValueID::kAvoid); default: return CSSIdentifierValue::Create(break_value); } @@ -2138,7 +2137,7 @@ case EBreakBetween::kRecto: case EBreakBetween::kRight: case EBreakBetween::kVerso: - return CSSIdentifierValue::Create(CSSValueID::kAuto); + return nullptr; case EBreakBetween::kColumn: return CSSIdentifierValue::Create(CSSValueID::kAlways); case EBreakBetween::kAvoidColumn: @@ -2154,7 +2153,7 @@ EBreakInside break_value) { switch (break_value) { case EBreakInside::kAvoidColumn: - return CSSIdentifierValue::Create(CSSValueID::kAuto); + return nullptr; case EBreakInside::kAvoidPage: return CSSIdentifierValue::Create(CSSValueID::kAvoid); default: @@ -2168,7 +2167,7 @@ EBreakInside break_value) { switch (break_value) { case EBreakInside::kAvoidPage: - return CSSIdentifierValue::Create(CSSValueID::kAuto); + return nullptr; case EBreakInside::kAvoidColumn: return CSSIdentifierValue::Create(CSSValueID::kAvoid); default:
diff --git a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc index b85f5c142..049ec64 100644 --- a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc +++ b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
@@ -5561,17 +5561,16 @@ css_property_parser_helpers::ConsumeImageOrNone(range, &context)) return image_value; CSSValueList* list = CSSValueList::CreateSpaceSeparated(); - if (CSSValue* box_value = css_property_parser_helpers::ConsumeShapeBox(range)) - list->Append(*box_value); + CSSValue* box_value = css_property_parser_helpers::ConsumeShapeBox(range); if (CSSValue* shape_value = css_parsing_utils::ConsumeBasicShape(range, context)) { list->Append(*shape_value); - if (list->length() < 2) { - if (CSSValue* box_value = - css_property_parser_helpers::ConsumeShapeBox(range)) - list->Append(*box_value); + if (!box_value) { + box_value = css_property_parser_helpers::ConsumeShapeBox(range); } } + if (box_value) + list->Append(*box_value); if (!list->length()) return nullptr; return list;
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc index 3bac040..ad52d4c 100644 --- a/third_party/blink/renderer/core/dom/document.cc +++ b/third_party/blink/renderer/core/dom/document.cc
@@ -6208,22 +6208,6 @@ }); } -KURL Document::ManifestURL() const { - HTMLLinkElement* link_element = LinkManifest(); - if (!link_element) - return KURL(); - return link_element->Href(); -} - -bool Document::ManifestUseCredentials() const { - HTMLLinkElement* link_element = LinkManifest(); - if (!link_element) - return false; - return EqualIgnoringASCIICase( - link_element->FastGetAttribute(html_names::kCrossoriginAttr), - "use-credentials"); -} - void Document::ApplyFeaturePolicyFromHeader( const String& feature_policy_header) { if (!feature_policy_header.IsEmpty())
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h index 082f9545..5625f23f 100644 --- a/third_party/blink/renderer/core/dom/document.h +++ b/third_party/blink/renderer/core/dom/document.h
@@ -1052,9 +1052,6 @@ // there is no such element. HTMLLinkElement* LinkCanonical() const; - KURL ManifestURL() const; - bool ManifestUseCredentials() const; - void UpdateFocusAppearanceAfterLayout(); void CancelFocusAppearanceUpdate(); // Return true after UpdateFocusAppearanceAfterLayout() call and before
diff --git a/third_party/blink/renderer/core/dom/document_test.cc b/third_party/blink/renderer/core/dom/document_test.cc index 3a0a3015..3afa424 100644 --- a/third_party/blink/renderer/core/dom/document_test.cc +++ b/third_party/blink/renderer/core/dom/document_test.cc
@@ -495,58 +495,6 @@ EXPECT_EQ(link, GetDocument().LinkManifest()); } -TEST_F(DocumentTest, ManifestURL) { - // Test the default result. - EXPECT_EQ(nullptr, GetDocument().LinkManifest()); - - // Check that we use the first manifest with <link rel=manifest> - auto* link_manifest = MakeGarbageCollected<HTMLLinkElement>( - GetDocument(), CreateElementFlags()); - link_manifest->setAttribute(blink::html_names::kRelAttr, "manifest"); - GetDocument().head()->AppendChild(link_manifest); - EXPECT_EQ(link_manifest, GetDocument().LinkManifest()); - - // No href attribute was set. - EXPECT_EQ(KURL(), GetDocument().ManifestURL()); - - // Set to some absolute url. - link_manifest->setAttribute(html_names::kHrefAttr, - "http://example.com/manifest.json"); - ASSERT_EQ(link_manifest->Href(), GetDocument().ManifestURL()); - - // Set to some relative url. - link_manifest->setAttribute(html_names::kHrefAttr, "static/manifest.json"); - ASSERT_EQ(link_manifest->Href(), GetDocument().ManifestURL()); -} - -TEST_F(DocumentTest, ManifestUseCredentials) { - // Test the default result. - EXPECT_EQ(nullptr, GetDocument().LinkManifest()); - - // Check that we use the first manifest with <link rel=manifest> - auto* link_manifest = MakeGarbageCollected<HTMLLinkElement>( - GetDocument(), CreateElementFlags()); - link_manifest->setAttribute(blink::html_names::kRelAttr, "manifest"); - GetDocument().head()->AppendChild(link_manifest); - EXPECT_EQ(link_manifest, GetDocument().LinkManifest()); - - // No crossorigin attribute was set so credentials shouldn't be used. - ASSERT_FALSE(link_manifest->FastHasAttribute(html_names::kCrossoriginAttr)); - ASSERT_FALSE(GetDocument().ManifestUseCredentials()); - - // Crossorigin set to a random string shouldn't trigger using credentials. - link_manifest->setAttribute(html_names::kCrossoriginAttr, "foobar"); - ASSERT_FALSE(GetDocument().ManifestUseCredentials()); - - // Crossorigin set to 'anonymous' shouldn't trigger using credentials. - link_manifest->setAttribute(html_names::kCrossoriginAttr, "anonymous"); - ASSERT_FALSE(GetDocument().ManifestUseCredentials()); - - // Crossorigin set to 'use-credentials' should trigger using credentials. - link_manifest->setAttribute(html_names::kCrossoriginAttr, "use-credentials"); - ASSERT_TRUE(GetDocument().ManifestUseCredentials()); -} - TEST_F(DocumentTest, referrerPolicyParsing) { EXPECT_EQ(network::mojom::ReferrerPolicy::kDefault, GetDocument().GetReferrerPolicy());
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc index 70d44ec..88a3620 100644 --- a/third_party/blink/renderer/core/dom/element.cc +++ b/third_party/blink/renderer/core/dom/element.cc
@@ -2095,18 +2095,6 @@ void Element::RemovedFrom(ContainerNode& insertion_point) { bool was_in_document = insertion_point.isConnected(); - if (HasRareData()) { - // If we detached the layout tree with LazyReattachIfAttached, we might not - // have cleared the pseudo elements if we remove the element before calling - // AttachLayoutTree again. We don't clear pseudo elements on - // DetachLayoutTree() if we intend to attach again to avoid recreating the - // pseudo elements. - // - // TODO(futhark): This block can be removed when LazyReattachIfAttached is - // removed. - ElementRareData* rare_data = GetElementRareData(); - rare_data->ClearPseudoElements(); - } SetComputedStyle(nullptr); @@ -2170,6 +2158,7 @@ GetDocument().EnsureIntersectionObserverController().RemoveTrackedTarget( *this); } + DCHECK(!data->HasPseudoElements()); } if (GetDocument().GetFrame())
diff --git a/third_party/blink/renderer/core/dom/node.cc b/third_party/blink/renderer/core/dom/node.cc index ff0972046..8f0d63e 100644 --- a/third_party/blink/renderer/core/dom/node.cc +++ b/third_party/blink/renderer/core/dom/node.cc
@@ -1436,25 +1436,6 @@ : nullptr; } -void Node::LazyReattachIfAttached() { - if (!InActiveDocument()) - return; - if (!IsContainerNode() && !IsTextNode()) - return; - - AttachContext context; - context.performing_reattach = true; - DetachLayoutTree(context); - - if (GetDocument().GetStyleEngine().InRebuildLayoutTree()) - return; - - SetFlag(kForceReattachLayoutTree); - SetNeedsStyleRecalc( - kSubtreeStyleChange, - StyleChangeReasonForTracing::Create(style_change_reason::kLazyReattach)); -} - void Node::SetForceReattachLayoutTree() { DCHECK(!GetDocument().GetStyleEngine().InRebuildLayoutTree()); if (GetForceReattachLayoutTree())
diff --git a/third_party/blink/renderer/core/dom/node.h b/third_party/blink/renderer/core/dom/node.h index 8c5fc88a..449e87bc 100644 --- a/third_party/blink/renderer/core/dom/node.h +++ b/third_party/blink/renderer/core/dom/node.h
@@ -700,11 +700,6 @@ } void ReattachLayoutTree(AttachContext&); - // TODO(futhark): Get rid of this method by replacing it with - // SetForceReattachLayoutTree + SetNeedsStyleRecalc, or DetachLayoutTree as - // appropriate. - void LazyReattachIfAttached(); - // --------------------------------------------------------------------------- // Inline ComputedStyle accessors //
diff --git a/third_party/blink/renderer/core/dom/node_test.cc b/third_party/blink/renderer/core/dom/node_test.cc index 9e2a8294..a5993f72 100644 --- a/third_party/blink/renderer/core/dom/node_test.cc +++ b/third_party/blink/renderer/core/dom/node_test.cc
@@ -325,27 +325,4 @@ EXPECT_FALSE(GetDocument().ChildNeedsStyleRecalc()); } -TEST_F(NodeTest, LazyReattachCommentAndPI) { - // TODO(futhark): Remove this test when LazyReattachIfAttached is removed. - SetBodyContent("<!-- -->"); - HTMLElement* body = GetDocument().body(); - ProcessingInstruction* pi = - ProcessingInstruction::Create(GetDocument(), "A", "B"); - body->appendChild(pi, ASSERT_NO_EXCEPTION); - UpdateAllLifecyclePhasesForTest(); - - Node* comment = body->firstChild(); - EXPECT_EQ(Node::kCommentNode, comment->getNodeType()); - - comment->LazyReattachIfAttached(); - EXPECT_FALSE(body->ChildNeedsStyleRecalc()); - EXPECT_FALSE(comment->GetForceReattachLayoutTree()); - EXPECT_FALSE(comment->NeedsStyleRecalc()); - - pi->LazyReattachIfAttached(); - EXPECT_FALSE(body->ChildNeedsStyleRecalc()); - EXPECT_FALSE(pi->GetForceReattachLayoutTree()); - EXPECT_FALSE(pi->NeedsStyleRecalc()); -} - } // namespace blink
diff --git a/third_party/blink/renderer/core/dom/range_test.cc b/third_party/blink/renderer/core/dom/range_test.cc index 35ade003..2308287d 100644 --- a/third_party/blink/renderer/core/dom/range_test.cc +++ b/third_party/blink/renderer/core/dom/range_test.cc
@@ -278,7 +278,7 @@ } TEST_F(RangeTest, ToPosition) { - Node& textarea = *HTMLTextAreaElement::Create(GetDocument()); + auto& textarea = *MakeGarbageCollected<HTMLTextAreaElement>(GetDocument()); Range& range = *Range::Create(GetDocument()); const Position position = Position(&textarea, 0); range.setStart(position, ASSERT_NO_EXCEPTION);
diff --git a/third_party/blink/renderer/core/exported/local_frame_client_impl.cc b/third_party/blink/renderer/core/exported/local_frame_client_impl.cc index e5a29c2..fcdea6f 100644 --- a/third_party/blink/renderer/core/exported/local_frame_client_impl.cc +++ b/third_party/blink/renderer/core/exported/local_frame_client_impl.cc
@@ -1013,8 +1013,6 @@ void LocalFrameClientImpl::DispatchDidChangeManifest() { CoreInitializer::GetInstance().DidChangeManifest(*web_frame_->GetFrame()); - if (web_frame_->Client()) - web_frame_->Client()->DidChangeManifest(); } unsigned LocalFrameClientImpl::BackForwardLength() {
diff --git a/third_party/blink/renderer/core/exported/web_document.cc b/third_party/blink/renderer/core/exported/web_document.cc index 5c58ab20..b9ab7b0 100644 --- a/third_party/blink/renderer/core/exported/web_document.cc +++ b/third_party/blink/renderer/core/exported/web_document.cc
@@ -252,12 +252,6 @@ return draggable_regions; } -// TODO(crbug.com/704441): Remove it after moving ManifestChangeNotifier to -// blink. -WebURL WebDocument::ManifestURL() const { - return ConstUnwrap<Document>()->ManifestURL(); -} - WebURL WebDocument::CanonicalUrlForSharing() const { const Document* document = ConstUnwrap<Document>(); HTMLLinkElement* link_element = document->LinkCanonical();
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 30c2cf2..9f168bd 100644 --- a/third_party/blink/renderer/core/exported/web_frame_test.cc +++ b/third_party/blink/renderer/core/exported/web_frame_test.cc
@@ -8561,32 +8561,6 @@ } } -class ManifestChangeWebFrameClient - : public frame_test_helpers::TestWebFrameClient { - public: - ManifestChangeWebFrameClient() : manifest_change_count_(0) {} - ~ManifestChangeWebFrameClient() override = default; - - // frame_test_helpers::TestWebFrameClient: - void DidChangeManifest() override { ++manifest_change_count_; } - - int ManifestChangeCount() { return manifest_change_count_; } - - private: - int manifest_change_count_; -}; - -TEST_F(WebFrameTest, NotifyManifestChange) { - RegisterMockedHttpURLLoad("link-manifest-change.html"); - - ManifestChangeWebFrameClient web_frame_client; - frame_test_helpers::WebViewHelper web_view_helper; - web_view_helper.InitializeAndLoad(base_url_ + "link-manifest-change.html", - &web_frame_client); - - EXPECT_EQ(14, web_frame_client.ManifestChangeCount()); -} - static Resource* FetchManifest(Document* document, const KURL& url) { FetchParameters fetch_parameters{ResourceRequest(url)}; fetch_parameters.SetRequestContext(mojom::RequestContextType::MANIFEST);
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.cc b/third_party/blink/renderer/core/frame/local_dom_window.cc index 519003fe..0e506d3c 100644 --- a/third_party/blink/renderer/core/frame/local_dom_window.cc +++ b/third_party/blink/renderer/core/frame/local_dom_window.cc
@@ -108,6 +108,7 @@ #include "third_party/blink/renderer/core/trustedtypes/trusted_types_util.h" #include "third_party/blink/renderer/platform/bindings/exception_messages.h" #include "third_party/blink/renderer/platform/bindings/microtask.h" +#include "third_party/blink/renderer/platform/heap/heap.h" #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h" #include "third_party/blink/renderer/platform/timer.h" #include "third_party/blink/renderer/platform/weborigin/security_origin.h" @@ -1256,7 +1257,7 @@ CustomElementRegistry* LocalDOMWindow::customElements() const { if (!custom_elements_ && document_) - custom_elements_ = CustomElementRegistry::Create(this); + custom_elements_ = MakeGarbageCollected<CustomElementRegistry>(this); return custom_elements_; }
diff --git a/third_party/blink/renderer/core/html/custom/custom_element_registry.cc b/third_party/blink/renderer/core/html/custom/custom_element_registry.cc index 13d7a65..d6fae1d 100644 --- a/third_party/blink/renderer/core/html/custom/custom_element_registry.cc +++ b/third_party/blink/renderer/core/html/custom/custom_element_registry.cc
@@ -75,23 +75,17 @@ } // namespace -CustomElementRegistry* CustomElementRegistry::Create( - const LocalDOMWindow* owner) { - CustomElementRegistry* registry = - MakeGarbageCollected<CustomElementRegistry>(owner); - Document* document = owner->document(); - if (V0CustomElementRegistrationContext* v0 = - document ? document->RegistrationContext() : nullptr) - registry->Entangle(v0); - return registry; -} - CustomElementRegistry::CustomElementRegistry(const LocalDOMWindow* owner) : element_definition_is_running_(false), owner_(owner), v0_(MakeGarbageCollected<V0RegistrySet>()), upgrade_candidates_(MakeGarbageCollected<UpgradeCandidateMap>()), - reaction_stack_(&CustomElementReactionStack::Current()) {} + reaction_stack_(&CustomElementReactionStack::Current()) { + Document* document = owner->document(); + if (V0CustomElementRegistrationContext* v0 = + document ? document->RegistrationContext() : nullptr) + Entangle(v0); +} void CustomElementRegistry::Trace(Visitor* visitor) { visitor->Trace(definitions_);
diff --git a/third_party/blink/renderer/core/html/custom/custom_element_registry.h b/third_party/blink/renderer/core/html/custom/custom_element_registry.h index 8f3ae3e3..3c959f9 100644 --- a/third_party/blink/renderer/core/html/custom/custom_element_registry.h +++ b/third_party/blink/renderer/core/html/custom/custom_element_registry.h
@@ -34,8 +34,6 @@ DEFINE_WRAPPERTYPEINFO(); public: - static CustomElementRegistry* Create(const LocalDOMWindow*); - CustomElementRegistry(const LocalDOMWindow*); ~CustomElementRegistry() override = default;
diff --git a/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_resolution_step.cc b/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_resolution_step.cc index ca126aa0..54603695 100644 --- a/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_resolution_step.cc +++ b/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_resolution_step.cc
@@ -35,15 +35,6 @@ namespace blink { -V0CustomElementMicrotaskResolutionStep* -V0CustomElementMicrotaskResolutionStep::Create( - V0CustomElementRegistrationContext* context, - Element* element, - const V0CustomElementDescriptor& descriptor) { - return MakeGarbageCollected<V0CustomElementMicrotaskResolutionStep>( - context, element, descriptor); -} - V0CustomElementMicrotaskResolutionStep::V0CustomElementMicrotaskResolutionStep( V0CustomElementRegistrationContext* context, Element* element,
diff --git a/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_resolution_step.h b/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_resolution_step.h index 320286e..2d28a2dc 100644 --- a/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_resolution_step.h +++ b/third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_resolution_step.h
@@ -43,11 +43,6 @@ class V0CustomElementMicrotaskResolutionStep final : public V0CustomElementMicrotaskStep { public: - static V0CustomElementMicrotaskResolutionStep* Create( - V0CustomElementRegistrationContext*, - Element*, - const V0CustomElementDescriptor&); - V0CustomElementMicrotaskResolutionStep(V0CustomElementRegistrationContext*, Element*, const V0CustomElementDescriptor&);
diff --git a/third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.h b/third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.h index 92e29a30..83c4f53 100644 --- a/third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.h +++ b/third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.h
@@ -45,10 +45,6 @@ class V0CustomElementRegistrationContext final : public GarbageCollectedFinalized<V0CustomElementRegistrationContext> { public: - static V0CustomElementRegistrationContext* Create() { - return MakeGarbageCollected<V0CustomElementRegistrationContext>(); - } - V0CustomElementRegistrationContext(); ~V0CustomElementRegistrationContext() = default; void DocumentWasDetached() { registry_.DocumentWasDetached(); }
diff --git a/third_party/blink/renderer/core/html/custom/v0_custom_element_scheduler.cc b/third_party/blink/renderer/core/html/custom/v0_custom_element_scheduler.cc index 0cc3000..7e9edad 100644 --- a/third_party/blink/renderer/core/html/custom/v0_custom_element_scheduler.cc +++ b/third_party/blink/renderer/core/html/custom/v0_custom_element_scheduler.cc
@@ -43,6 +43,7 @@ #include "third_party/blink/renderer/core/html/custom/v0_custom_element_sync_microtask_queue.h" #include "third_party/blink/renderer/core/html/imports/html_import_child.h" #include "third_party/blink/renderer/core/html/imports/html_imports_controller.h" +#include "third_party/blink/renderer/platform/heap/heap.h" namespace blink { @@ -125,9 +126,8 @@ } Document& document = element->GetDocument(); - V0CustomElementMicrotaskResolutionStep* step = - V0CustomElementMicrotaskResolutionStep::Create(context, element, - descriptor); + auto* step = MakeGarbageCollected<V0CustomElementMicrotaskResolutionStep>( + context, element, descriptor); EnqueueMicrotaskStep(document, step); }
diff --git a/third_party/blink/renderer/core/html/document_name_collection.h b/third_party/blink/renderer/core/html/document_name_collection.h index 09463fa..792d702 100644 --- a/third_party/blink/renderer/core/html/document_name_collection.h +++ b/third_party/blink/renderer/core/html/document_name_collection.h
@@ -12,13 +12,6 @@ class DocumentNameCollection final : public HTMLNameCollection { public: - static DocumentNameCollection* Create(ContainerNode& document, - CollectionType type, - const AtomicString& name) { - DCHECK_EQ(type, kDocumentNamedItems); - return MakeGarbageCollected<DocumentNameCollection>(document, name); - } - DocumentNameCollection(ContainerNode& document, const AtomicString& name); DocumentNameCollection(ContainerNode& document, CollectionType type,
diff --git a/third_party/blink/renderer/core/html/forms/button_input_type.cc b/third_party/blink/renderer/core/html/forms/button_input_type.cc index bd17ef8..9003997 100644 --- a/third_party/blink/renderer/core/html/forms/button_input_type.cc +++ b/third_party/blink/renderer/core/html/forms/button_input_type.cc
@@ -35,10 +35,6 @@ namespace blink { -InputType* ButtonInputType::Create(HTMLInputElement& element) { - return MakeGarbageCollected<ButtonInputType>(element); -} - void ButtonInputType::CountUsage() { CountUsageIfVisible(WebFeature::kInputTypeButton); }
diff --git a/third_party/blink/renderer/core/html/forms/button_input_type.h b/third_party/blink/renderer/core/html/forms/button_input_type.h index b9abffe..d53bdce 100644 --- a/third_party/blink/renderer/core/html/forms/button_input_type.h +++ b/third_party/blink/renderer/core/html/forms/button_input_type.h
@@ -37,8 +37,6 @@ class ButtonInputType final : public BaseButtonInputType { public: - static InputType* Create(HTMLInputElement&); - ButtonInputType(HTMLInputElement& element) : BaseButtonInputType(element) {} private:
diff --git a/third_party/blink/renderer/core/html/forms/checkbox_input_type.cc b/third_party/blink/renderer/core/html/forms/checkbox_input_type.cc index d5d1c2c..3c929e7 100644 --- a/third_party/blink/renderer/core/html/forms/checkbox_input_type.cc +++ b/third_party/blink/renderer/core/html/forms/checkbox_input_type.cc
@@ -40,10 +40,6 @@ namespace blink { -InputType* CheckboxInputType::Create(HTMLInputElement& element) { - return MakeGarbageCollected<CheckboxInputType>(element); -} - void CheckboxInputType::CountUsage() { CountUsageIfVisible(WebFeature::kInputTypeCheckbox); }
diff --git a/third_party/blink/renderer/core/html/forms/checkbox_input_type.h b/third_party/blink/renderer/core/html/forms/checkbox_input_type.h index ab00d840..afca5bb9 100644 --- a/third_party/blink/renderer/core/html/forms/checkbox_input_type.h +++ b/third_party/blink/renderer/core/html/forms/checkbox_input_type.h
@@ -37,8 +37,6 @@ class CheckboxInputType final : public BaseCheckableInputType { public: - static InputType* Create(HTMLInputElement&); - CheckboxInputType(HTMLInputElement& element) : BaseCheckableInputType(element) {}
diff --git a/third_party/blink/renderer/core/html/forms/color_input_type.cc b/third_party/blink/renderer/core/html/forms/color_input_type.cc index c7615ac5..c2f6fef 100644 --- a/third_party/blink/renderer/core/html/forms/color_input_type.cc +++ b/third_party/blink/renderer/core/html/forms/color_input_type.cc
@@ -77,10 +77,6 @@ ColorInputType::ColorInputType(HTMLInputElement& element) : InputType(element), KeyboardClickableInputTypeView(element) {} -InputType* ColorInputType::Create(HTMLInputElement& element) { - return MakeGarbageCollected<ColorInputType>(element); -} - ColorInputType::~ColorInputType() = default; void ColorInputType::Trace(Visitor* visitor) {
diff --git a/third_party/blink/renderer/core/html/forms/color_input_type.h b/third_party/blink/renderer/core/html/forms/color_input_type.h index f755a60e4..19cfe68 100644 --- a/third_party/blink/renderer/core/html/forms/color_input_type.h +++ b/third_party/blink/renderer/core/html/forms/color_input_type.h
@@ -45,7 +45,6 @@ USING_GARBAGE_COLLECTED_MIXIN(ColorInputType); public: - static InputType* Create(HTMLInputElement&); explicit ColorInputType(HTMLInputElement&); ~ColorInputType() override; void Trace(Visitor*) override;
diff --git a/third_party/blink/renderer/core/html/forms/date_input_type.cc b/third_party/blink/renderer/core/html/forms/date_input_type.cc index 0bd61ed..999f2243 100644 --- a/third_party/blink/renderer/core/html/forms/date_input_type.cc +++ b/third_party/blink/renderer/core/html/forms/date_input_type.cc
@@ -48,13 +48,9 @@ static const int kDateDefaultStepBase = 0; static const int kDateStepScaleFactor = 86400000; -inline DateInputType::DateInputType(HTMLInputElement& element) +DateInputType::DateInputType(HTMLInputElement& element) : BaseTemporalInputType(element) {} -InputType* DateInputType::Create(HTMLInputElement& element) { - return MakeGarbageCollected<DateInputType>(element); -} - void DateInputType::CountUsage() { CountUsageIfVisible(WebFeature::kInputTypeDate); }
diff --git a/third_party/blink/renderer/core/html/forms/date_input_type.h b/third_party/blink/renderer/core/html/forms/date_input_type.h index b5a8e7eb..24bac53 100644 --- a/third_party/blink/renderer/core/html/forms/date_input_type.h +++ b/third_party/blink/renderer/core/html/forms/date_input_type.h
@@ -37,8 +37,6 @@ class DateInputType final : public BaseTemporalInputType { public: - static InputType* Create(HTMLInputElement&); - explicit DateInputType(HTMLInputElement&); private:
diff --git a/third_party/blink/renderer/core/html/forms/date_time_local_input_type.cc b/third_party/blink/renderer/core/html/forms/date_time_local_input_type.cc index ddf1980..0f12fd7b 100644 --- a/third_party/blink/renderer/core/html/forms/date_time_local_input_type.cc +++ b/third_party/blink/renderer/core/html/forms/date_time_local_input_type.cc
@@ -49,10 +49,6 @@ static const int kDateTimeLocalDefaultStepBase = 0; static const int kDateTimeLocalStepScaleFactor = 1000; -InputType* DateTimeLocalInputType::Create(HTMLInputElement& element) { - return MakeGarbageCollected<DateTimeLocalInputType>(element); -} - void DateTimeLocalInputType::CountUsage() { CountUsageIfVisible(WebFeature::kInputTypeDateTimeLocal); }
diff --git a/third_party/blink/renderer/core/html/forms/date_time_local_input_type.h b/third_party/blink/renderer/core/html/forms/date_time_local_input_type.h index 8404bdf4b..7dbfce0 100644 --- a/third_party/blink/renderer/core/html/forms/date_time_local_input_type.h +++ b/third_party/blink/renderer/core/html/forms/date_time_local_input_type.h
@@ -39,8 +39,6 @@ class DateTimeLocalInputType final : public BaseTemporalInputType { public: - static InputType* Create(HTMLInputElement&); - explicit DateTimeLocalInputType(HTMLInputElement& element) : BaseTemporalInputType(element) {}
diff --git a/third_party/blink/renderer/core/html/forms/email_input_type.cc b/third_party/blink/renderer/core/html/forms/email_input_type.cc index dd937e4a47..699cd73 100644 --- a/third_party/blink/renderer/core/html/forms/email_input_type.cc +++ b/third_party/blink/renderer/core/html/forms/email_input_type.cc
@@ -159,10 +159,6 @@ EmailInputType::EmailInputType(HTMLInputElement& element) : BaseTextInputType(element) {} -InputType* EmailInputType::Create(HTMLInputElement& element) { - return MakeGarbageCollected<EmailInputType>(element); -} - void EmailInputType::CountUsage() { CountUsageIfVisible(WebFeature::kInputTypeEmail); bool has_max_length =
diff --git a/third_party/blink/renderer/core/html/forms/email_input_type.h b/third_party/blink/renderer/core/html/forms/email_input_type.h index 0e37b497..f63fa717 100644 --- a/third_party/blink/renderer/core/html/forms/email_input_type.h +++ b/third_party/blink/renderer/core/html/forms/email_input_type.h
@@ -37,8 +37,6 @@ class EmailInputType final : public BaseTextInputType { public: - static InputType* Create(HTMLInputElement&); - explicit EmailInputType(HTMLInputElement&); // They are public for unit testing.
diff --git a/third_party/blink/renderer/core/html/forms/file_input_type.cc b/third_party/blink/renderer/core/html/forms/file_input_type.cc index 50f8f66..61c2ceb 100644 --- a/third_party/blink/renderer/core/html/forms/file_input_type.cc +++ b/third_party/blink/renderer/core/html/forms/file_input_type.cc
@@ -67,15 +67,11 @@ } // namespace -inline FileInputType::FileInputType(HTMLInputElement& element) +FileInputType::FileInputType(HTMLInputElement& element) : InputType(element), KeyboardClickableInputTypeView(element), file_list_(MakeGarbageCollected<FileList>()) {} -InputType* FileInputType::Create(HTMLInputElement& element) { - return MakeGarbageCollected<FileInputType>(element); -} - void FileInputType::Trace(Visitor* visitor) { visitor->Trace(file_list_); KeyboardClickableInputTypeView::Trace(visitor);
diff --git a/third_party/blink/renderer/core/html/forms/file_input_type.h b/third_party/blink/renderer/core/html/forms/file_input_type.h index 4af28a5..256a752 100644 --- a/third_party/blink/renderer/core/html/forms/file_input_type.h +++ b/third_party/blink/renderer/core/html/forms/file_input_type.h
@@ -51,8 +51,6 @@ USING_GARBAGE_COLLECTED_MIXIN(FileInputType); public: - static InputType* Create(HTMLInputElement&); - FileInputType(HTMLInputElement&); void Trace(Visitor*) override;
diff --git a/third_party/blink/renderer/core/html/forms/file_input_type_test.cc b/third_party/blink/renderer/core/html/forms/file_input_type_test.cc index 33f2d2a..613906d 100644 --- a/third_party/blink/renderer/core/html/forms/file_input_type_test.cc +++ b/third_party/blink/renderer/core/html/forms/file_input_type_test.cc
@@ -15,6 +15,7 @@ #include "third_party/blink/renderer/core/page/drag_data.h" #include "third_party/blink/renderer/core/testing/dummy_page_holder.h" #include "third_party/blink/renderer/platform/file_metadata.h" +#include "third_party/blink/renderer/platform/heap/heap.h" #include "third_party/blink/renderer/platform/wtf/date_math.h" namespace blink { @@ -63,7 +64,7 @@ TEST(FileInputTypeTest, ignoreDroppedNonNativeFiles) { Document* document = Document::CreateForTest(); auto* input = HTMLInputElement::Create(*document, CreateElementFlags()); - InputType* file_input = FileInputType::Create(*input); + InputType* file_input = MakeGarbageCollected<FileInputType>(*input); DataObject* native_file_raw_drag_data = DataObject::Create(); const DragData native_file_drag_data(native_file_raw_drag_data, FloatPoint(), @@ -95,7 +96,7 @@ TEST(FileInputTypeTest, setFilesFromPaths) { Document* document = Document::CreateForTest(); auto* input = HTMLInputElement::Create(*document, CreateElementFlags()); - InputType* file_input = FileInputType::Create(*input); + InputType* file_input = MakeGarbageCollected<FileInputType>(*input); Vector<String> paths; paths.push_back("/native/path"); paths.push_back("/native/path2");
diff --git a/third_party/blink/renderer/core/html/forms/hidden_input_type.cc b/third_party/blink/renderer/core/html/forms/hidden_input_type.cc index c2cde6d..773f9cf 100644 --- a/third_party/blink/renderer/core/html/forms/hidden_input_type.cc +++ b/third_party/blink/renderer/core/html/forms/hidden_input_type.cc
@@ -43,10 +43,6 @@ using namespace html_names; -InputType* HiddenInputType::Create(HTMLInputElement& element) { - return MakeGarbageCollected<HiddenInputType>(element); -} - void HiddenInputType::CountUsage() { UseCounter::Count(GetElement().GetDocument(), WebFeature::kInputTypeHidden); }
diff --git a/third_party/blink/renderer/core/html/forms/hidden_input_type.h b/third_party/blink/renderer/core/html/forms/hidden_input_type.h index eddb2e1..5e211f6 100644 --- a/third_party/blink/renderer/core/html/forms/hidden_input_type.h +++ b/third_party/blink/renderer/core/html/forms/hidden_input_type.h
@@ -40,8 +40,6 @@ USING_GARBAGE_COLLECTED_MIXIN(HiddenInputType); public: - static InputType* Create(HTMLInputElement&); - HiddenInputType(HTMLInputElement& element) : InputType(element), InputTypeView(element) {}
diff --git a/third_party/blink/renderer/core/html/forms/html_form_control_element.cc b/third_party/blink/renderer/core/html/forms/html_form_control_element.cc index 1957d11..fc8f2ab 100644 --- a/third_party/blink/renderer/core/html/forms/html_form_control_element.cc +++ b/third_party/blink/renderer/core/html/forms/html_form_control_element.cc
@@ -324,7 +324,9 @@ return FastGetAttribute(kValueAttr); } -void HTMLFormControlElement::DidRecalcStyle(const StyleRecalcChange) { +void HTMLFormControlElement::DidRecalcStyle(const StyleRecalcChange change) { + if (change.ReattachLayoutTree()) + return; if (LayoutObject* layout_object = GetLayoutObject()) layout_object->UpdateFromElement(); }
diff --git a/third_party/blink/renderer/core/html/forms/html_select_element.cc b/third_party/blink/renderer/core/html/forms/html_select_element.cc index fc80925..7f53ca55 100644 --- a/third_party/blink/renderer/core/html/forms/html_select_element.cc +++ b/third_party/blink/renderer/core/html/forms/html_select_element.cc
@@ -34,6 +34,7 @@ #include "third_party/blink/renderer/bindings/core/v8/html_element_or_long.h" #include "third_party/blink/renderer/bindings/core/v8/html_option_element_or_html_opt_group_element.h" #include "third_party/blink/renderer/core/accessibility/ax_object_cache.h" +#include "third_party/blink/renderer/core/css/style_change_reason.h" #include "third_party/blink/renderer/core/dom/attribute.h" #include "third_party/blink/renderer/core/dom/element_traversal.h" #include "third_party/blink/renderer/core/dom/events/scoped_event_queue.h" @@ -303,8 +304,7 @@ size_ = 0; SetNeedsValidityCheck(); if (size_ != old_size) { - if (InActiveDocument()) - LazyReattachIfAttached(); + ChangeRendering(); ResetToDefaultSelection(); if (!UsesMenuList()) SaveListboxActiveSelection(); @@ -1213,7 +1213,7 @@ HTMLOptionElement* old_selected_option = SelectedOption(); is_multiple_ = !value.IsNull(); SetNeedsValidityCheck(); - LazyReattachIfAttached(); + ChangeRendering(); // Restore selectedIndex after changing the multiple flag to preserve // selection as single-line and multi-line has different defaults. if (old_multiple != is_multiple_) { @@ -1997,7 +1997,7 @@ void HTMLSelectElement::DidRecalcStyle(const StyleRecalcChange change) { HTMLFormControlElementWithState::DidRecalcStyle(change); - if (PopupIsVisible()) + if (!change.ReattachLayoutTree() && PopupIsVisible()) popup_->UpdateFromElement(PopupMenu::kByStyleChange); } @@ -2108,4 +2108,15 @@ HTMLFormControlElement::CloneNonAttributePropertiesFrom(source, flag); } +void HTMLSelectElement::ChangeRendering() { + if (!InActiveDocument()) + return; + // TODO(futhark): SetForceReattachLayoutTree() should be the correct way to + // create a new layout tree, but the code for updating the selected index + // relies on the layout tree to be nuked. + DetachLayoutTree(); + SetNeedsStyleRecalc(kLocalStyleChange, StyleChangeReasonForTracing::Create( + style_change_reason::kControl)); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/html/forms/html_select_element.h b/third_party/blink/renderer/core/html/forms/html_select_element.h index b386e10..8c20767c 100644 --- a/third_party/blink/renderer/core/html/forms/html_select_element.h +++ b/third_party/blink/renderer/core/html/forms/html_select_element.h
@@ -283,6 +283,10 @@ void ObserveTreeMutation(); void UnobserveTreeMutation(); + // Apply changes to rendering as a result of attribute changes (multiple, + // size). + void ChangeRendering(); + // list_items_ contains HTMLOptionElement, HTMLOptGroupElement, and // HTMLHRElement objects. mutable ListItems list_items_;
diff --git a/third_party/blink/renderer/core/html/forms/html_text_area_element.cc b/third_party/blink/renderer/core/html/forms/html_text_area_element.cc index 29dca452..bc97294 100644 --- a/third_party/blink/renderer/core/html/forms/html_text_area_element.cc +++ b/third_party/blink/renderer/core/html/forms/html_text_area_element.cc
@@ -80,10 +80,6 @@ EnsureUserAgentShadowRoot(); } -HTMLTextAreaElement* HTMLTextAreaElement::Create(Document& document) { - return MakeGarbageCollected<HTMLTextAreaElement>(document); -} - void HTMLTextAreaElement::DidAddUserAgentShadowRoot(ShadowRoot& root) { root.AppendChild(CreateInnerEditorElement()); }
diff --git a/third_party/blink/renderer/core/html/forms/html_text_area_element.h b/third_party/blink/renderer/core/html/forms/html_text_area_element.h index 88c44967..8bbd305ac 100644 --- a/third_party/blink/renderer/core/html/forms/html_text_area_element.h +++ b/third_party/blink/renderer/core/html/forms/html_text_area_element.h
@@ -36,8 +36,6 @@ DEFINE_WRAPPERTYPEINFO(); public: - static HTMLTextAreaElement* Create(Document&); - explicit HTMLTextAreaElement(Document&); unsigned cols() const { return cols_; }
diff --git a/third_party/blink/renderer/core/html/forms/image_input_type.cc b/third_party/blink/renderer/core/html/forms/image_input_type.cc index 35a4b1ba..3db1b975 100644 --- a/third_party/blink/renderer/core/html/forms/image_input_type.cc +++ b/third_party/blink/renderer/core/html/forms/image_input_type.cc
@@ -45,13 +45,9 @@ using namespace html_names; -inline ImageInputType::ImageInputType(HTMLInputElement& element) +ImageInputType::ImageInputType(HTMLInputElement& element) : BaseButtonInputType(element), use_fallback_content_(false) {} -InputType* ImageInputType::Create(HTMLInputElement& element) { - return MakeGarbageCollected<ImageInputType>(element); -} - void ImageInputType::CountUsage() { CountUsageIfVisible(WebFeature::kInputTypeImage); }
diff --git a/third_party/blink/renderer/core/html/forms/image_input_type.h b/third_party/blink/renderer/core/html/forms/image_input_type.h index b9ed1e9..01d26bee 100644 --- a/third_party/blink/renderer/core/html/forms/image_input_type.h +++ b/third_party/blink/renderer/core/html/forms/image_input_type.h
@@ -40,8 +40,7 @@ class ImageInputType final : public BaseButtonInputType { public: - static InputType* Create(HTMLInputElement&); - ImageInputType(HTMLInputElement&); + explicit ImageInputType(HTMLInputElement&); scoped_refptr<ComputedStyle> CustomStyleForLayoutObject( scoped_refptr<ComputedStyle>) override;
diff --git a/third_party/blink/renderer/core/html/forms/input_type.cc b/third_party/blink/renderer/core/html/forms/input_type.cc index 9b06bd484..29ef685d8 100644 --- a/third_party/blink/renderer/core/html/forms/input_type.cc +++ b/third_party/blink/renderer/core/html/forms/input_type.cc
@@ -84,27 +84,90 @@ static std::unique_ptr<InputTypeFactoryMap> CreateInputTypeFactoryMap() { std::unique_ptr<InputTypeFactoryMap> map = std::make_unique<InputTypeFactoryMap>(); - map->insert(input_type_names::kButton, ButtonInputType::Create); - map->insert(input_type_names::kCheckbox, CheckboxInputType::Create); - map->insert(input_type_names::kColor, ColorInputType::Create); - map->insert(input_type_names::kDate, DateInputType::Create); - map->insert(input_type_names::kDatetimeLocal, DateTimeLocalInputType::Create); - map->insert(input_type_names::kEmail, EmailInputType::Create); - map->insert(input_type_names::kFile, FileInputType::Create); - map->insert(input_type_names::kHidden, HiddenInputType::Create); - map->insert(input_type_names::kImage, ImageInputType::Create); - map->insert(input_type_names::kMonth, MonthInputType::Create); - map->insert(input_type_names::kNumber, NumberInputType::Create); - map->insert(input_type_names::kPassword, PasswordInputType::Create); - map->insert(input_type_names::kRadio, RadioInputType::Create); - map->insert(input_type_names::kRange, RangeInputType::Create); - map->insert(input_type_names::kReset, ResetInputType::Create); - map->insert(input_type_names::kSearch, SearchInputType::Create); - map->insert(input_type_names::kSubmit, SubmitInputType::Create); - map->insert(input_type_names::kTel, TelephoneInputType::Create); - map->insert(input_type_names::kTime, TimeInputType::Create); - map->insert(input_type_names::kUrl, URLInputType::Create); - map->insert(input_type_names::kWeek, WeekInputType::Create); + map->insert(input_type_names::kButton, + [](HTMLInputElement& element) -> InputType* { + return MakeGarbageCollected<ButtonInputType>(element); + }); + map->insert(input_type_names::kCheckbox, + [](HTMLInputElement& element) -> InputType* { + return MakeGarbageCollected<CheckboxInputType>(element); + }); + map->insert(input_type_names::kColor, + [](HTMLInputElement& element) -> InputType* { + return MakeGarbageCollected<ColorInputType>(element); + }); + map->insert(input_type_names::kDate, + [](HTMLInputElement& element) -> InputType* { + return MakeGarbageCollected<DateInputType>(element); + }); + map->insert(input_type_names::kDatetimeLocal, + [](HTMLInputElement& element) -> InputType* { + return MakeGarbageCollected<DateTimeLocalInputType>(element); + }); + map->insert(input_type_names::kEmail, + [](HTMLInputElement& element) -> InputType* { + return MakeGarbageCollected<EmailInputType>(element); + }); + map->insert(input_type_names::kFile, + [](HTMLInputElement& element) -> InputType* { + return MakeGarbageCollected<FileInputType>(element); + }); + map->insert(input_type_names::kHidden, + [](HTMLInputElement& element) -> InputType* { + return MakeGarbageCollected<HiddenInputType>(element); + }); + map->insert(input_type_names::kImage, + [](HTMLInputElement& element) -> InputType* { + return MakeGarbageCollected<ImageInputType>(element); + }); + map->insert(input_type_names::kMonth, + [](HTMLInputElement& element) -> InputType* { + return MakeGarbageCollected<MonthInputType>(element); + }); + map->insert(input_type_names::kNumber, + [](HTMLInputElement& element) -> InputType* { + return MakeGarbageCollected<NumberInputType>(element); + }); + map->insert(input_type_names::kPassword, + [](HTMLInputElement& element) -> InputType* { + return MakeGarbageCollected<PasswordInputType>(element); + }); + map->insert(input_type_names::kRadio, + [](HTMLInputElement& element) -> InputType* { + return MakeGarbageCollected<RadioInputType>(element); + }); + map->insert(input_type_names::kRange, + [](HTMLInputElement& element) -> InputType* { + return MakeGarbageCollected<RangeInputType>(element); + }); + map->insert(input_type_names::kReset, + [](HTMLInputElement& element) -> InputType* { + return MakeGarbageCollected<ResetInputType>(element); + }); + map->insert(input_type_names::kSearch, + [](HTMLInputElement& element) -> InputType* { + return MakeGarbageCollected<SearchInputType>(element); + }); + map->insert(input_type_names::kSubmit, + [](HTMLInputElement& element) -> InputType* { + return MakeGarbageCollected<SubmitInputType>(element); + }); + map->insert(input_type_names::kTel, + [](HTMLInputElement& element) -> InputType* { + return MakeGarbageCollected<TelephoneInputType>(element); + }); + map->insert(input_type_names::kTime, + [](HTMLInputElement& element) -> InputType* { + return MakeGarbageCollected<TimeInputType>(element); + }); + map->insert(input_type_names::kUrl, + [](HTMLInputElement& element) -> InputType* { + return MakeGarbageCollected<URLInputType>(element); + }); + map->insert(input_type_names::kWeek, + [](HTMLInputElement& element) -> InputType* { + return MakeGarbageCollected<WeekInputType>(element); + }); // No need to register "text" because it is the default type. return map; }
diff --git a/third_party/blink/renderer/core/html/forms/month_input_type.cc b/third_party/blink/renderer/core/html/forms/month_input_type.cc index 2dca735..32b4dc8 100644 --- a/third_party/blink/renderer/core/html/forms/month_input_type.cc +++ b/third_party/blink/renderer/core/html/forms/month_input_type.cc
@@ -50,10 +50,6 @@ static const int kMonthDefaultStepBase = 0; static const int kMonthStepScaleFactor = 1; -InputType* MonthInputType::Create(HTMLInputElement& element) { - return MakeGarbageCollected<MonthInputType>(element); -} - void MonthInputType::CountUsage() { CountUsageIfVisible(WebFeature::kInputTypeMonth); }
diff --git a/third_party/blink/renderer/core/html/forms/month_input_type.h b/third_party/blink/renderer/core/html/forms/month_input_type.h index 43d0733..a577873 100644 --- a/third_party/blink/renderer/core/html/forms/month_input_type.h +++ b/third_party/blink/renderer/core/html/forms/month_input_type.h
@@ -37,8 +37,6 @@ class MonthInputType final : public BaseTemporalInputType { public: - static InputType* Create(HTMLInputElement&); - explicit MonthInputType(HTMLInputElement& element) : BaseTemporalInputType(element) {}
diff --git a/third_party/blink/renderer/core/html/forms/number_input_type.cc b/third_party/blink/renderer/core/html/forms/number_input_type.cc index 12b5b06..e6f3a8d8 100644 --- a/third_party/blink/renderer/core/html/forms/number_input_type.cc +++ b/third_party/blink/renderer/core/html/forms/number_input_type.cc
@@ -94,10 +94,6 @@ number_of_zero_after_decimal_point + size_of_digits); } -InputType* NumberInputType::Create(HTMLInputElement& element) { - return MakeGarbageCollected<NumberInputType>(element); -} - void NumberInputType::CountUsage() { CountUsageIfVisible(WebFeature::kInputTypeNumber); }
diff --git a/third_party/blink/renderer/core/html/forms/number_input_type.h b/third_party/blink/renderer/core/html/forms/number_input_type.h index fe94317f..fcb364e 100644 --- a/third_party/blink/renderer/core/html/forms/number_input_type.h +++ b/third_party/blink/renderer/core/html/forms/number_input_type.h
@@ -39,9 +39,8 @@ class NumberInputType final : public TextFieldInputType { public: - static InputType* Create(HTMLInputElement&); - - NumberInputType(HTMLInputElement& element) : TextFieldInputType(element) {} + explicit NumberInputType(HTMLInputElement& element) + : TextFieldInputType(element) {} private: void CountUsage() override;
diff --git a/third_party/blink/renderer/core/html/forms/password_input_type.cc b/third_party/blink/renderer/core/html/forms/password_input_type.cc index 0fb452d..13f82af 100644 --- a/third_party/blink/renderer/core/html/forms/password_input_type.cc +++ b/third_party/blink/renderer/core/html/forms/password_input_type.cc
@@ -44,10 +44,6 @@ namespace blink { -InputType* PasswordInputType::Create(HTMLInputElement& element) { - return MakeGarbageCollected<PasswordInputType>(element); -} - void PasswordInputType::CountUsage() { CountUsageIfVisible(WebFeature::kInputTypePassword); if (GetElement().FastHasAttribute(html_names::kMaxlengthAttr))
diff --git a/third_party/blink/renderer/core/html/forms/password_input_type.h b/third_party/blink/renderer/core/html/forms/password_input_type.h index c113962..33997fcf 100644 --- a/third_party/blink/renderer/core/html/forms/password_input_type.h +++ b/third_party/blink/renderer/core/html/forms/password_input_type.h
@@ -37,8 +37,6 @@ class PasswordInputType final : public BaseTextInputType { public: - static InputType* Create(HTMLInputElement&); - explicit PasswordInputType(HTMLInputElement& element) : BaseTextInputType(element) {}
diff --git a/third_party/blink/renderer/core/html/forms/radio_input_type.cc b/third_party/blink/renderer/core/html/forms/radio_input_type.cc index 390b1424..730db85 100644 --- a/third_party/blink/renderer/core/html/forms/radio_input_type.cc +++ b/third_party/blink/renderer/core/html/forms/radio_input_type.cc
@@ -46,10 +46,6 @@ } // namespace -InputType* RadioInputType::Create(HTMLInputElement& element) { - return MakeGarbageCollected<RadioInputType>(element); -} - void RadioInputType::CountUsage() { CountUsageIfVisible(WebFeature::kInputTypeRadio); }
diff --git a/third_party/blink/renderer/core/html/forms/radio_input_type.h b/third_party/blink/renderer/core/html/forms/radio_input_type.h index c790686..5c0b43d 100644 --- a/third_party/blink/renderer/core/html/forms/radio_input_type.h +++ b/third_party/blink/renderer/core/html/forms/radio_input_type.h
@@ -38,7 +38,6 @@ class RadioInputType final : public BaseCheckableInputType { public: - static InputType* Create(HTMLInputElement&); CORE_EXPORT static HTMLInputElement* NextRadioButtonInGroup(HTMLInputElement*, bool forward);
diff --git a/third_party/blink/renderer/core/html/forms/range_input_type.cc b/third_party/blink/renderer/core/html/forms/range_input_type.cc index e3d19561..a43070f 100644 --- a/third_party/blink/renderer/core/html/forms/range_input_type.cc +++ b/third_party/blink/renderer/core/html/forms/range_input_type.cc
@@ -72,10 +72,6 @@ return proposed_value >= minimum ? proposed_value : minimum; } -InputType* RangeInputType::Create(HTMLInputElement& element) { - return MakeGarbageCollected<RangeInputType>(element); -} - RangeInputType::RangeInputType(HTMLInputElement& element) : InputType(element), InputTypeView(element),
diff --git a/third_party/blink/renderer/core/html/forms/range_input_type.h b/third_party/blink/renderer/core/html/forms/range_input_type.h index ebee693..1ff7566 100644 --- a/third_party/blink/renderer/core/html/forms/range_input_type.h +++ b/third_party/blink/renderer/core/html/forms/range_input_type.h
@@ -43,9 +43,7 @@ USING_GARBAGE_COLLECTED_MIXIN(RangeInputType); public: - static InputType* Create(HTMLInputElement&); - - RangeInputType(HTMLInputElement&); + explicit RangeInputType(HTMLInputElement&); void Trace(Visitor*) override; using InputType::GetElement;
diff --git a/third_party/blink/renderer/core/html/forms/reset_input_type.cc b/third_party/blink/renderer/core/html/forms/reset_input_type.cc index 8d69a7d..73c5cf0 100644 --- a/third_party/blink/renderer/core/html/forms/reset_input_type.cc +++ b/third_party/blink/renderer/core/html/forms/reset_input_type.cc
@@ -40,10 +40,6 @@ namespace blink { -InputType* ResetInputType::Create(HTMLInputElement& element) { - return MakeGarbageCollected<ResetInputType>(element); -} - void ResetInputType::CountUsage() { CountUsageIfVisible(WebFeature::kInputTypeReset); }
diff --git a/third_party/blink/renderer/core/html/forms/reset_input_type.h b/third_party/blink/renderer/core/html/forms/reset_input_type.h index 6bafa1b..1672ed9 100644 --- a/third_party/blink/renderer/core/html/forms/reset_input_type.h +++ b/third_party/blink/renderer/core/html/forms/reset_input_type.h
@@ -37,9 +37,8 @@ class ResetInputType final : public BaseButtonInputType { public: - static InputType* Create(HTMLInputElement&); - - ResetInputType(HTMLInputElement& element) : BaseButtonInputType(element) {} + explicit ResetInputType(HTMLInputElement& element) + : BaseButtonInputType(element) {} private: void CountUsage() override;
diff --git a/third_party/blink/renderer/core/html/forms/search_input_type.cc b/third_party/blink/renderer/core/html/forms/search_input_type.cc index 65b60e9f7..2a2e080 100644 --- a/third_party/blink/renderer/core/html/forms/search_input_type.cc +++ b/third_party/blink/renderer/core/html/forms/search_input_type.cc
@@ -46,17 +46,13 @@ using namespace html_names; -inline SearchInputType::SearchInputType(HTMLInputElement& element) +SearchInputType::SearchInputType(HTMLInputElement& element) : BaseTextInputType(element), search_event_timer_( element.GetDocument().GetTaskRunner(TaskType::kUserInteraction), this, &SearchInputType::SearchEventTimerFired) {} -InputType* SearchInputType::Create(HTMLInputElement& element) { - return MakeGarbageCollected<SearchInputType>(element); -} - void SearchInputType::CountUsage() { CountUsageIfVisible(WebFeature::kInputTypeSearch); }
diff --git a/third_party/blink/renderer/core/html/forms/search_input_type.h b/third_party/blink/renderer/core/html/forms/search_input_type.h index b27f3f0..34a6f6b 100644 --- a/third_party/blink/renderer/core/html/forms/search_input_type.h +++ b/third_party/blink/renderer/core/html/forms/search_input_type.h
@@ -38,8 +38,6 @@ class SearchInputType final : public BaseTextInputType { public: - static InputType* Create(HTMLInputElement&); - SearchInputType(HTMLInputElement&); private:
diff --git a/third_party/blink/renderer/core/html/forms/submit_input_type.cc b/third_party/blink/renderer/core/html/forms/submit_input_type.cc index 0cf4396..6ab4816 100644 --- a/third_party/blink/renderer/core/html/forms/submit_input_type.cc +++ b/third_party/blink/renderer/core/html/forms/submit_input_type.cc
@@ -41,9 +41,9 @@ namespace blink { -InputType* SubmitInputType::Create(HTMLInputElement& element) { +SubmitInputType::SubmitInputType(HTMLInputElement& element) + : BaseButtonInputType(element) { UseCounter::Count(element.GetDocument(), WebFeature::kInputTypeSubmit); - return MakeGarbageCollected<SubmitInputType>(element); } const AtomicString& SubmitInputType::FormControlType() const {
diff --git a/third_party/blink/renderer/core/html/forms/submit_input_type.h b/third_party/blink/renderer/core/html/forms/submit_input_type.h index 7dc51ffe..bacca2800 100644 --- a/third_party/blink/renderer/core/html/forms/submit_input_type.h +++ b/third_party/blink/renderer/core/html/forms/submit_input_type.h
@@ -37,9 +37,7 @@ class SubmitInputType final : public BaseButtonInputType { public: - static InputType* Create(HTMLInputElement&); - - SubmitInputType(HTMLInputElement& element) : BaseButtonInputType(element) {} + explicit SubmitInputType(HTMLInputElement& element); private: const AtomicString& FormControlType() const override;
diff --git a/third_party/blink/renderer/core/html/forms/telephone_input_type.cc b/third_party/blink/renderer/core/html/forms/telephone_input_type.cc index 2dde47f..908e990 100644 --- a/third_party/blink/renderer/core/html/forms/telephone_input_type.cc +++ b/third_party/blink/renderer/core/html/forms/telephone_input_type.cc
@@ -35,10 +35,6 @@ namespace blink { -InputType* TelephoneInputType::Create(HTMLInputElement& element) { - return MakeGarbageCollected<TelephoneInputType>(element); -} - void TelephoneInputType::CountUsage() { CountUsageIfVisible(WebFeature::kInputTypeTel); }
diff --git a/third_party/blink/renderer/core/html/forms/telephone_input_type.h b/third_party/blink/renderer/core/html/forms/telephone_input_type.h index 6ffc76b..1584006b 100644 --- a/third_party/blink/renderer/core/html/forms/telephone_input_type.h +++ b/third_party/blink/renderer/core/html/forms/telephone_input_type.h
@@ -37,9 +37,8 @@ class TelephoneInputType final : public BaseTextInputType { public: - static InputType* Create(HTMLInputElement&); - - TelephoneInputType(HTMLInputElement& element) : BaseTextInputType(element) {} + explicit TelephoneInputType(HTMLInputElement& element) + : BaseTextInputType(element) {} private: void CountUsage() override;
diff --git a/third_party/blink/renderer/core/html/forms/time_input_type.cc b/third_party/blink/renderer/core/html/forms/time_input_type.cc index 05d60c1..eaabf37 100644 --- a/third_party/blink/renderer/core/html/forms/time_input_type.cc +++ b/third_party/blink/renderer/core/html/forms/time_input_type.cc
@@ -55,10 +55,6 @@ TimeInputType::TimeInputType(HTMLInputElement& element) : BaseTemporalInputType(element) {} -InputType* TimeInputType::Create(HTMLInputElement& element) { - return MakeGarbageCollected<TimeInputType>(element); -} - void TimeInputType::CountUsage() { CountUsageIfVisible(WebFeature::kInputTypeTime); }
diff --git a/third_party/blink/renderer/core/html/forms/time_input_type.h b/third_party/blink/renderer/core/html/forms/time_input_type.h index d5d74cf..58711ec4 100644 --- a/third_party/blink/renderer/core/html/forms/time_input_type.h +++ b/third_party/blink/renderer/core/html/forms/time_input_type.h
@@ -37,8 +37,6 @@ class TimeInputType final : public BaseTemporalInputType { public: - static InputType* Create(HTMLInputElement&); - explicit TimeInputType(HTMLInputElement&); private:
diff --git a/third_party/blink/renderer/core/html/forms/url_input_type.cc b/third_party/blink/renderer/core/html/forms/url_input_type.cc index c58aa25..d672297 100644 --- a/third_party/blink/renderer/core/html/forms/url_input_type.cc +++ b/third_party/blink/renderer/core/html/forms/url_input_type.cc
@@ -38,10 +38,6 @@ namespace blink { -InputType* URLInputType::Create(HTMLInputElement& element) { - return MakeGarbageCollected<URLInputType>(element); -} - void URLInputType::CountUsage() { CountUsageIfVisible(WebFeature::kInputTypeURL); }
diff --git a/third_party/blink/renderer/core/html/forms/url_input_type.h b/third_party/blink/renderer/core/html/forms/url_input_type.h index 8d1ec15..bbbd410 100644 --- a/third_party/blink/renderer/core/html/forms/url_input_type.h +++ b/third_party/blink/renderer/core/html/forms/url_input_type.h
@@ -37,8 +37,6 @@ class URLInputType final : public BaseTextInputType { public: - static InputType* Create(HTMLInputElement&); - URLInputType(HTMLInputElement& element) : BaseTextInputType(element) {} private:
diff --git a/third_party/blink/renderer/core/html/forms/week_input_type.cc b/third_party/blink/renderer/core/html/forms/week_input_type.cc index 6a27534..c78dbcdd 100644 --- a/third_party/blink/renderer/core/html/forms/week_input_type.cc +++ b/third_party/blink/renderer/core/html/forms/week_input_type.cc
@@ -48,10 +48,6 @@ static const int kWeekDefaultStep = 1; static const int kWeekStepScaleFactor = 604800000; -InputType* WeekInputType::Create(HTMLInputElement& element) { - return MakeGarbageCollected<WeekInputType>(element); -} - void WeekInputType::CountUsage() { CountUsageIfVisible(WebFeature::kInputTypeWeek); }
diff --git a/third_party/blink/renderer/core/html/forms/week_input_type.h b/third_party/blink/renderer/core/html/forms/week_input_type.h index f4ed68e..783aeff 100644 --- a/third_party/blink/renderer/core/html/forms/week_input_type.h +++ b/third_party/blink/renderer/core/html/forms/week_input_type.h
@@ -37,8 +37,6 @@ class WeekInputType final : public BaseTemporalInputType { public: - static InputType* Create(HTMLInputElement&); - explicit WeekInputType(HTMLInputElement& element) : BaseTemporalInputType(element) {}
diff --git a/third_party/blink/renderer/core/html/html_all_collection.cc b/third_party/blink/renderer/core/html/html_all_collection.cc index b18da7f..bf74ee9d 100644 --- a/third_party/blink/renderer/core/html/html_all_collection.cc +++ b/third_party/blink/renderer/core/html/html_all_collection.cc
@@ -29,12 +29,6 @@ namespace blink { -HTMLAllCollection* HTMLAllCollection::Create(ContainerNode& node, - CollectionType type) { - DCHECK_EQ(type, kDocAll); - return MakeGarbageCollected<HTMLAllCollection>(node); -} - HTMLAllCollection::HTMLAllCollection(ContainerNode& node) : HTMLCollection(node, kDocAll, kDoesNotOverrideItemAfter) {}
diff --git a/third_party/blink/renderer/core/html/html_all_collection.h b/third_party/blink/renderer/core/html/html_all_collection.h index 8dcf8bb..c01c8bf 100644 --- a/third_party/blink/renderer/core/html/html_all_collection.h +++ b/third_party/blink/renderer/core/html/html_all_collection.h
@@ -37,8 +37,6 @@ DEFINE_WRAPPERTYPEINFO(); public: - static HTMLAllCollection* Create(ContainerNode&, CollectionType); - explicit HTMLAllCollection(ContainerNode&); HTMLAllCollection(ContainerNode&, CollectionType); ~HTMLAllCollection() override;
diff --git a/third_party/blink/renderer/core/html/html_collection.cc b/third_party/blink/renderer/core/html/html_collection.cc index c6f2b64..b13e8fa8 100644 --- a/third_party/blink/renderer/core/html/html_collection.cc +++ b/third_party/blink/renderer/core/html/html_collection.cc
@@ -191,12 +191,6 @@ GetDocument().RegisterNodeList(this); } -HTMLCollection* HTMLCollection::Create(ContainerNode& base, - CollectionType type) { - return MakeGarbageCollected<HTMLCollection>(base, type, - kDoesNotOverrideItemAfter); -} - HTMLCollection::~HTMLCollection() = default; void HTMLCollection::InvalidateCache(Document* old_document) const {
diff --git a/third_party/blink/renderer/core/html/html_collection.h b/third_party/blink/renderer/core/html/html_collection.h index 8e768da..d1388a8 100644 --- a/third_party/blink/renderer/core/html/html_collection.h +++ b/third_party/blink/renderer/core/html/html_collection.h
@@ -76,7 +76,6 @@ kDoesNotOverrideItemAfter, }; - static HTMLCollection* Create(ContainerNode& base, CollectionType); HTMLCollection(ContainerNode& base, CollectionType, ItemAfterOverrideType = kDoesNotOverrideItemAfter);
diff --git a/third_party/blink/renderer/core/html/media/html_audio_element.cc b/third_party/blink/renderer/core/html/media/html_audio_element.cc index 79368e1..2f27358 100644 --- a/third_party/blink/renderer/core/html/media/html_audio_element.cc +++ b/third_party/blink/renderer/core/html/media/html_audio_element.cc
@@ -38,10 +38,6 @@ UpdateStateIfNeeded(); } -HTMLAudioElement* HTMLAudioElement::Create(Document& document) { - return MakeGarbageCollected<HTMLAudioElement>(document); -} - HTMLAudioElement* HTMLAudioElement::CreateForJSConstructor( Document& document, const AtomicString& src) {
diff --git a/third_party/blink/renderer/core/html/media/html_audio_element.h b/third_party/blink/renderer/core/html/media/html_audio_element.h index c345675..bafd92f 100644 --- a/third_party/blink/renderer/core/html/media/html_audio_element.h +++ b/third_party/blink/renderer/core/html/media/html_audio_element.h
@@ -38,7 +38,6 @@ DEFINE_WRAPPERTYPEINFO(); public: - static HTMLAudioElement* Create(Document&); static HTMLAudioElement* CreateForJSConstructor( Document&, const AtomicString& src = g_null_atom);
diff --git a/third_party/blink/renderer/core/html/media/html_media_element.cc b/third_party/blink/renderer/core/html/media/html_media_element.cc index aa97892..da2d6d7 100644 --- a/third_party/blink/renderer/core/html/media/html_media_element.cc +++ b/third_party/blink/renderer/core/html/media/html_media_element.cc
@@ -725,8 +725,8 @@ GetLayoutObject()->UpdateFromElement(); } -void HTMLMediaElement::DidRecalcStyle(const StyleRecalcChange) { - if (GetLayoutObject()) +void HTMLMediaElement::DidRecalcStyle(const StyleRecalcChange change) { + if (!change.ReattachLayoutTree() && GetLayoutObject()) GetLayoutObject()->UpdateFromElement(); }
diff --git a/third_party/blink/renderer/core/html/media/html_media_element_controls_list.h b/third_party/blink/renderer/core/html/media/html_media_element_controls_list.h index d7787fa9..6fa86cb 100644 --- a/third_party/blink/renderer/core/html/media/html_media_element_controls_list.h +++ b/third_party/blink/renderer/core/html/media/html_media_element_controls_list.h
@@ -15,10 +15,6 @@ class CORE_EXPORT HTMLMediaElementControlsList final : public DOMTokenList { public: - static HTMLMediaElementControlsList* Create(HTMLMediaElement* element) { - return MakeGarbageCollected<HTMLMediaElementControlsList>(element); - } - explicit HTMLMediaElementControlsList(HTMLMediaElement*); // Whether the list dictates to hide a certain control.
diff --git a/third_party/blink/renderer/core/html/media/html_media_element_test.cc b/third_party/blink/renderer/core/html/media/html_media_element_test.cc index 5efa46c1..783b3fc 100644 --- a/third_party/blink/renderer/core/html/media/html_media_element_test.cc +++ b/third_party/blink/renderer/core/html/media/html_media_element_test.cc
@@ -16,6 +16,7 @@ #include "third_party/blink/renderer/core/html/track/video_track_list.h" #include "third_party/blink/renderer/core/loader/empty_clients.h" #include "third_party/blink/renderer/core/testing/dummy_page_holder.h" +#include "third_party/blink/renderer/platform/heap/heap.h" #include "third_party/blink/renderer/platform/network/network_state_notifier.h" #include "third_party/blink/renderer/platform/testing/empty_web_media_player.h" #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h" @@ -91,10 +92,12 @@ std::move(mock_media_player)), nullptr); - if (GetParam() == MediaTestParam::kAudio) - media_ = HTMLAudioElement::Create(dummy_page_holder_->GetDocument()); - else + if (GetParam() == MediaTestParam::kAudio) { + media_ = MakeGarbageCollected<HTMLAudioElement>( + dummy_page_holder_->GetDocument()); + } else { media_ = HTMLVideoElement::Create(dummy_page_holder_->GetDocument()); + } } HTMLMediaElement* Media() const { return media_.Get(); }
diff --git a/third_party/blink/renderer/core/html/media/html_media_test_helper.h b/third_party/blink/renderer/core/html/media/html_media_test_helper.h index 93d163a..4a35eb1ed 100644 --- a/third_party/blink/renderer/core/html/media/html_media_test_helper.h +++ b/third_party/blink/renderer/core/html/media/html_media_test_helper.h
@@ -16,9 +16,6 @@ // WebMediaPlayerimplementation. class MediaStubLocalFrameClient : public EmptyLocalFrameClient { public: - // Creates a LocalFrameClient that will use the given media player. - static MediaStubLocalFrameClient* Create(std::unique_ptr<WebMediaPlayer>); - explicit MediaStubLocalFrameClient(std::unique_ptr<WebMediaPlayer>); std::unique_ptr<WebMediaPlayer> CreateWebMediaPlayer(
diff --git a/third_party/blink/renderer/core/html/track/html_track_element.cc b/third_party/blink/renderer/core/html/track/html_track_element.cc index 6b3cbe0..52747a1 100644 --- a/third_party/blink/renderer/core/html/track/html_track_element.cc +++ b/third_party/blink/renderer/core/html/track/html_track_element.cc
@@ -33,6 +33,7 @@ #include "third_party/blink/renderer/core/html/media/html_media_element.h" #include "third_party/blink/renderer/core/html/track/loadable_text_track.h" #include "third_party/blink/renderer/core/html_names.h" +#include "third_party/blink/renderer/platform/heap/heap.h" #define TRACK_LOG_LEVEL 3 @@ -217,7 +218,9 @@ if (loader_) loader_->CancelLoad(); - loader_ = TextTrackLoader::Create(*this, GetDocument()); + loader_ = + MakeGarbageCollected<TextTrackLoader, TextTrackLoaderClient&, Document&>( + *this, GetDocument()); if (!loader_->Load(url_, GetCrossOriginAttributeValue(cors_mode))) DidCompleteLoad(kFailure); }
diff --git a/third_party/blink/renderer/core/html/track/vtt/vtt_cue.cc b/third_party/blink/renderer/core/html/track/vtt/vtt_cue.cc index 3abddfc..8252c3af 100644 --- a/third_party/blink/renderer/core/html/track/vtt/vtt_cue.cc +++ b/third_party/blink/renderer/core/html/track/vtt/vtt_cue.cc
@@ -794,7 +794,7 @@ DCHECK(track() && track()->IsRendered() && IsActive()); if (!display_tree_) { - display_tree_ = VTTCueBox::Create(GetDocument()); + display_tree_ = MakeGarbageCollected<VTTCueBox>(GetDocument()); display_tree_->AppendChild(cue_background_box_); }
diff --git a/third_party/blink/renderer/core/html/track/vtt/vtt_cue.h b/third_party/blink/renderer/core/html/track/vtt/vtt_cue.h index 9194c39..f4eed44 100644 --- a/third_party/blink/renderer/core/html/track/vtt/vtt_cue.h +++ b/third_party/blink/renderer/core/html/track/vtt/vtt_cue.h
@@ -61,10 +61,6 @@ class VTTCueBox final : public HTMLDivElement { public: - static VTTCueBox* Create(Document& document) { - return MakeGarbageCollected<VTTCueBox>(document); - } - explicit VTTCueBox(Document&); void ApplyCSSProperties(const VTTDisplayParameters&);
diff --git a/third_party/blink/renderer/core/html/track/vtt/vtt_element.cc b/third_party/blink/renderer/core/html/track/vtt/vtt_element.cc index e2362cd9..b8c1512 100644 --- a/third_party/blink/renderer/core/html/track/vtt/vtt_element.cc +++ b/third_party/blink/renderer/core/html/track/vtt/vtt_element.cc
@@ -27,6 +27,7 @@ #include "third_party/blink/renderer/core/css/style_change_reason.h" #include "third_party/blink/renderer/core/dom/document.h" +#include "third_party/blink/renderer/platform/heap/heap.h" namespace blink { @@ -70,16 +71,12 @@ is_past_node_(0), web_vtt_node_type_(node_type) {} -VTTElement* VTTElement::Create(VTTNodeType node_type, Document* document) { - return MakeGarbageCollected<VTTElement>(node_type, document); -} - Element& VTTElement::CloneWithoutAttributesAndChildren( Document& factory) const { - VTTElement& clone = - *Create(static_cast<VTTNodeType>(web_vtt_node_type_), &factory); - clone.SetLanguage(language_); - return clone; + auto* clone = MakeGarbageCollected<VTTElement>( + static_cast<VTTNodeType>(web_vtt_node_type_), &factory); + clone->SetLanguage(language_); + return *clone; } HTMLElement* VTTElement::CreateEquivalentHTMLElement(Document& document) {
diff --git a/third_party/blink/renderer/core/html/track/vtt/vtt_element.h b/third_party/blink/renderer/core/html/track/vtt/vtt_element.h index 82c0e91..f27e8e70 100644 --- a/third_party/blink/renderer/core/html/track/vtt/vtt_element.h +++ b/third_party/blink/renderer/core/html/track/vtt/vtt_element.h
@@ -45,8 +45,6 @@ class VTTElement final : public Element { public: - static VTTElement* Create(const VTTNodeType, Document*); - static VTTElement* Create(const QualifiedName&, Document*); HTMLElement* CreateEquivalentHTMLElement(Document&); VTTElement(const QualifiedName&, Document*);
diff --git a/third_party/blink/renderer/core/html/track/vtt/vtt_parser.cc b/third_party/blink/renderer/core/html/track/vtt/vtt_parser.cc index b9e81a8..7bc15cc5 100644 --- a/third_party/blink/renderer/core/html/track/vtt/vtt_parser.cc +++ b/third_party/blink/renderer/core/html/track/vtt/vtt_parser.cc
@@ -36,6 +36,7 @@ #include "third_party/blink/renderer/core/html/track/vtt/vtt_element.h" #include "third_party/blink/renderer/core/html/track/vtt/vtt_region.h" #include "third_party/blink/renderer/core/html/track/vtt/vtt_scanner.h" +#include "third_party/blink/renderer/platform/heap/heap.h" #include "third_party/blink/renderer/platform/loader/fetch/text_resource_decoder_options.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" #include "third_party/blink/renderer/platform/text/segmented_string.h" @@ -540,7 +541,7 @@ if (node_type == kVTTNodeTypeRubyText && current_type != kVTTNodeTypeRuby) break; - VTTElement* child = VTTElement::Create(node_type, &document); + auto* child = MakeGarbageCollected<VTTElement>(node_type, &document); if (!token_.Classes().IsEmpty()) child->setAttribute(kClassAttr, token_.Classes());
diff --git a/third_party/blink/renderer/core/html/track/vtt/vtt_parser.h b/third_party/blink/renderer/core/html/track/vtt/vtt_parser.h index cad46f9..41fd662f 100644 --- a/third_party/blink/renderer/core/html/track/vtt/vtt_parser.h +++ b/third_party/blink/renderer/core/html/track/vtt/vtt_parser.h
@@ -70,10 +70,6 @@ kBadCue }; - static VTTParser* Create(VTTParserClient* client, Document& document) { - return MakeGarbageCollected<VTTParser>(client, document); - } - VTTParser(VTTParserClient*, Document&); ~VTTParser() = default;
diff --git a/third_party/blink/renderer/core/layout/BUILD.gn b/third_party/blink/renderer/core/layout/BUILD.gn index 7d63fa1..8ddc952 100644 --- a/third_party/blink/renderer/core/layout/BUILD.gn +++ b/third_party/blink/renderer/core/layout/BUILD.gn
@@ -335,6 +335,8 @@ "ng/inline/ng_caret_position.h", "ng/inline/ng_caret_rect.cc", "ng/inline/ng_caret_rect.h", + "ng/inline/ng_dirty_lines.cc", + "ng/inline/ng_dirty_lines.h", "ng/inline/ng_inline_box_state.cc", "ng/inline/ng_inline_box_state.h", "ng/inline/ng_inline_break_token.cc",
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_dirty_lines.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_dirty_lines.cc new file mode 100644 index 0000000..61a0ecf --- /dev/null +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_dirty_lines.cc
@@ -0,0 +1,50 @@ +// 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/layout/ng/inline/ng_dirty_lines.h" + +#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h" +#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h" + +namespace blink { + +void NGDirtyLines::MarkLastFragment() { + if (last_fragment_) { + // Changes in this LayoutObject may affect the line that contains its + // previous object. Mark the line box that contains the last fragment + // of the previous object. + last_fragment_->LastForSameLayoutObject()->MarkContainingLineBoxDirty(); + } else { + // If there were no fragments so far in this pre-order traversal, mark + // the first line box dirty. + DCHECK(block_fragment_); + if (NGPaintFragment* first_line = block_fragment_->FirstLineBox()) + first_line->MarkLineBoxDirty(); + } +} + +void NGDirtyLines::MarkAtTextOffset(unsigned offset) { + for (NGPaintFragment* child : block_fragment_->Children()) { + // Only the first dirty line is relevant. + if (child->IsDirty()) + break; + + const auto* line = + DynamicTo<NGPhysicalLineBoxFragment>(child->PhysicalFragment()); + if (!line) + continue; + + const auto* break_token = To<NGInlineBreakToken>(line->BreakToken()); + DCHECK(break_token); + if (break_token->IsFinished()) + break; + + if (offset < break_token->TextOffset()) { + child->MarkLineBoxDirty(); + break; + } + } +} + +} // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_dirty_lines.h b/third_party/blink/renderer/core/layout/ng/inline/ng_dirty_lines.h new file mode 100644 index 0000000..1dadc97 --- /dev/null +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_dirty_lines.h
@@ -0,0 +1,81 @@ +// 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_CORE_LAYOUT_NG_INLINE_NG_DIRTY_LINES_H_ +#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_DIRTY_LINES_H_ + +#include "third_party/blink/renderer/core/core_export.h" +#include "third_party/blink/renderer/core/layout/layout_box.h" +#include "third_party/blink/renderer/core/layout/layout_inline.h" +#include "third_party/blink/renderer/core/layout/layout_text.h" +#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h" + +namespace blink { + +// This class computes dirty line boxes. +class CORE_EXPORT NGDirtyLines { + STACK_ALLOCATED(); + + public: + explicit NGDirtyLines(NGPaintFragment* block_fragment) + : block_fragment_(block_fragment) { + DCHECK(block_fragment_); + } + + // Call |Handle*| functions for each object by traversing the LayoutObject + // tree in pre-order DFS. + // + // They return |true| when a dirty line was found. Because only the first + // dirty line is relevant, no further calls are necessary. + bool HandleText(LayoutText* layout_text) { + if (layout_text->SelfNeedsLayout()) { + MarkLastFragment(); + return true; + } + UpdateLastFragment(layout_text->FirstInlineFragment()); + return false; + } + + bool HandleInlineBox(LayoutInline* layout_inline) { + if (layout_inline->SelfNeedsLayout()) { + MarkLastFragment(); + return true; + } + // Do not keep fragments of LayoutInline unless it's a leaf, because + // the last fragment of LayoutInline is not the previous fragment of its + // descendants. + if (UNLIKELY(!layout_inline->FirstChild())) + UpdateLastFragment(layout_inline->FirstInlineFragment()); + return false; + } + + bool HandleAtomicInline(LayoutBox* layout_box) { + if (layout_box->NeedsLayout()) { + MarkLastFragment(); + return true; + } + UpdateLastFragment(layout_box->FirstInlineFragment()); + return false; + } + + // Mark the line box at the specified text offset dirty. + void MarkAtTextOffset(unsigned offset); + + private: + void UpdateLastFragment(NGPaintFragment* fragment) { + if (fragment) + last_fragment_ = fragment; + } + + // Mark the line box that contains |last_fragment_| dirty. If |last_fragment_| + // is |nullptr|, the first line box is marked as dirty. + void MarkLastFragment(); + + NGPaintFragment* block_fragment_; + NGPaintFragment* last_fragment_ = nullptr; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_DIRTY_LINES_H_
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc index 18f9bd9c..1d9d97b 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc
@@ -9,6 +9,7 @@ #include "third_party/blink/renderer/core/layout/layout_inline.h" #include "third_party/blink/renderer/core/layout/layout_text.h" #include "third_party/blink/renderer/core/layout/ng/inline/layout_ng_text.h" +#include "third_party/blink/renderer/core/layout/ng/inline/ng_dirty_lines.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_builder.h" #include "third_party/blink/renderer/core/style/computed_style.h" @@ -406,6 +407,30 @@ template <typename OffsetMappingBuilder> void NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::AppendText( + LayoutText* layout_text, + const String* previous_text) { + // Mark dirty lines. Clear if marked, only the first dirty line is relevant. + if (dirty_lines_ && dirty_lines_->HandleText(layout_text)) + dirty_lines_ = nullptr; + + // If the LayoutText element hasn't changed, reuse the existing items. + if (previous_text && layout_text->HasValidInlineItems()) { + if (AppendTextReusing(*previous_text, layout_text)) { + return; + } + } + + // If not create a new item as needed. + if (UNLIKELY(layout_text->IsWordBreak())) { + AppendBreakOpportunity(layout_text); + return; + } + + AppendText(layout_text->GetText(), layout_text); +} + +template <typename OffsetMappingBuilder> +void NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::AppendText( const String& string, LayoutText* layout_object) { DCHECK(layout_object); @@ -773,6 +798,11 @@ Append(NGInlineItem::kAtomicInline, kObjectReplacementCharacter, layout_object); + // Mark dirty lines. Clear if marked, only the first dirty line is relevant. + if (dirty_lines_ && + dirty_lines_->HandleAtomicInline(ToLayoutBox(layout_object))) + dirty_lines_ = nullptr; + // When this atomic inline is inside of an inline box, the height of the // inline box can be different from the height of the atomic inline. Ensure // the inline box creates a box fragment so that its height is available in @@ -855,6 +885,12 @@ text_.erase(space_offset); mapping_builder_.CollapseTrailingSpace(space_offset); + // Mark dirty lines. Clear if marked, only the first dirty line is relevant. + if (dirty_lines_) { + dirty_lines_->MarkAtTextOffset(space_offset); + dirty_lines_ = nullptr; + } + // Keep the item even if the length became zero. This is not needed for // the layout purposes, but needed to maintain LayoutObject states. See // |AddEmptyTextItem()|. @@ -970,7 +1006,7 @@ template <typename OffsetMappingBuilder> void NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::EnterInline( - LayoutObject* node) { + LayoutInline* node) { DCHECK(node); // https://drafts.csswg.org/css-writing-modes-3/#bidi-control-codes-injection-table @@ -1011,6 +1047,10 @@ AppendOpaque(NGInlineItem::kOpenTag, node); + // Mark dirty lines. Clear if marked, only the first dirty line is relevant. + if (dirty_lines_ && dirty_lines_->HandleInlineBox(node)) + dirty_lines_ = nullptr; + if (!NeedsBoxInfo()) return; @@ -1070,7 +1110,8 @@ template <typename OffsetMappingBuilder> void NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::ClearInlineFragment( LayoutObject* object) { - NGInlineNode::ClearInlineFragment(object); + object->SetIsInLayoutNGInlineFormattingContext(true); + object->SetFirstInlineFragment(nullptr); } template <typename OffsetMappingBuilder>
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h index 9d04bba..30ebd77 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h
@@ -21,6 +21,7 @@ class LayoutInline; class LayoutObject; class LayoutText; +class NGDirtyLines; // NGInlineItemsBuilder builds a string and a list of NGInlineItem from inlines. // @@ -42,8 +43,13 @@ STACK_ALLOCATED(); public: - explicit NGInlineItemsBuilderTemplate(Vector<NGInlineItem>* items) - : items_(items) {} + // Create a builder that appends items to |items|. + // + // If |dirty_lines| is given, this builder calls its functions to mark lines + // dirty. + explicit NGInlineItemsBuilderTemplate(Vector<NGInlineItem>* items, + NGDirtyLines* dirty_lines = nullptr) + : items_(items), dirty_lines_(dirty_lines) {} ~NGInlineItemsBuilderTemplate(); String ToString(); @@ -62,6 +68,12 @@ return changes_may_affect_earlier_lines_; } + // Append a string from |LayoutText|. + // + // If |previous_text| is given, reuse existing items if they exist and are + // reusable. Otherwise appends new items. + void AppendText(LayoutText* layout_text, const String* previous_text); + // Append existing items from an unchanged LayoutObject. // Returns whether the existing items could be reused. // NOTE: The state of the builder remains unchanged if the append operation @@ -114,7 +126,7 @@ void EnterBlock(const ComputedStyle*); void ExitBlock(); - void EnterInline(LayoutObject*); + void EnterInline(LayoutInline*); void ExitInline(LayoutObject*); OffsetMappingBuilder& GetOffsetMappingBuilder() { return mapping_builder_; } @@ -134,6 +146,8 @@ Vector<NGInlineItem>* items_; StringBuilder text_; + NGDirtyLines* dirty_lines_; + // |mapping_builder_| builds the whitespace-collapsed offset mapping // during inline collection. It is updated whenever |text_| is modified or a // white space is collapsed.
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc index 8a6e1cc..5aaa49a 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
@@ -15,6 +15,7 @@ #include "third_party/blink/renderer/core/layout/logical_values.h" #include "third_party/blink/renderer/core/layout/ng/inline/layout_ng_text.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_bidi_paragraph.h" +#include "third_party/blink/renderer/core/layout/ng/inline/ng_dirty_lines.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h" @@ -62,83 +63,28 @@ return EstimateInlineItemsCount(block) / 4; } -// This class marks appropriate line box fragments as dirty. -// -// |CollectInlinesInternal| calls this class when traversing the LayoutObject -// tree in pre-order DFS -class NGLineBoxMarker { - STACK_ALLOCATED(); - - public: - NGLineBoxMarker(NGPaintFragment* block_fragment) - : block_fragment_(block_fragment) { - DCHECK(block_fragment_); - } - - bool HandleText(LayoutText* layout_text) { - if (layout_text->SelfNeedsLayout()) - return Mark(); - return UpdateLastFragment(layout_text->FirstInlineFragment()); - } - - bool HandleInlineBox(LayoutInline* layout_inline) { - if (layout_inline->SelfNeedsLayout()) - return Mark(); - - // Do not keep fragments of LayoutInline unless it's a leaf, because - // the last fragment of LayoutInline is not the previous fragment of its - // descendants. - if (layout_inline->FirstChild()) - return false; - return UpdateLastFragment(layout_inline->FirstInlineFragment()); - } - - bool HandleAtomicInline(LayoutBox* layout_box) { - if (layout_box->NeedsLayout()) - return Mark(); - return UpdateLastFragment(layout_box->FirstInlineFragment()); - } - - private: - bool Mark() { - if (last_fragment_) { - // Changes in this LayoutObject may affect the line that contains its - // previous object. Mark the line box that contains the last fragment - // of the previous object. - last_fragment_->LastForSameLayoutObject()->MarkContainingLineBoxDirty(); - } else { - // If there were no fragments so far in this pre-order traversal, mark - // the first line box dirty. - DCHECK(block_fragment_); - if (NGPaintFragment* first_line = block_fragment_->FirstLineBox()) - first_line->MarkLineBoxDirty(); - } - return true; - } - - bool UpdateLastFragment(NGPaintFragment* fragment) { - if (fragment) - last_fragment_ = fragment; - return false; - } - - NGPaintFragment* block_fragment_; - NGPaintFragment* last_fragment_ = nullptr; -}; - // This class has the same interface as NGInlineItemsBuilder but does nothing // except tracking if floating or out-of-flow objects are added. // // |MarkLineBoxesDirty| uses this class to traverse tree without buildling // |NGInlineItem|. class ItemsBuilderForMarkLineBoxesDirty { + STACK_ALLOCATED(); + public: - void AppendText(const String&, LayoutText*) {} - bool AppendTextReusing(const String&, LayoutText*) { return false; } + ItemsBuilderForMarkLineBoxesDirty(NGDirtyLines* dirty_lines) + : dirty_lines_(dirty_lines) {} + void AppendText(LayoutText* layout_text, const String*) { + if (dirty_lines_ && dirty_lines_->HandleText(layout_text)) + dirty_lines_ = nullptr; + } void AppendOpaque(NGInlineItem::NGInlineItemType, LayoutObject*) {} - void AppendBreakOpportunity(LayoutObject*) {} - void AppendAtomicInline(LayoutObject*) {} + void AppendAtomicInline(LayoutObject* layout_object) { + if (dirty_lines_ && + dirty_lines_->HandleAtomicInline(ToLayoutBox(layout_object))) + dirty_lines_ = nullptr; + } void AppendFloating(LayoutObject*) { has_floating_or_out_of_flow_positioned_ = true; } @@ -148,7 +94,10 @@ void SetIsSymbolMarker(bool) {} void EnterBlock(const ComputedStyle*) {} void ExitBlock() {} - void EnterInline(LayoutObject*) {} + void EnterInline(LayoutInline* layout_inline) { + if (dirty_lines_ && dirty_lines_->HandleInlineBox(layout_inline)) + dirty_lines_ = nullptr; + } void ExitInline(LayoutObject*) {} bool ShouldAbort() const { @@ -164,12 +113,12 @@ } void ClearInlineFragment(LayoutObject* object) { - NGInlineNode::ClearInlineFragment(object); + DCHECK(object->IsInLayoutNGInlineFormattingContext()); } void ClearNeedsLayout(LayoutObject* object) { object->ClearNeedsLayout(); - object->ClearNeedsCollectInlines(); + DCHECK(!object->NeedsCollectInlines()); ClearInlineFragment(object); } @@ -178,6 +127,7 @@ } private: + NGDirtyLines* dirty_lines_; bool has_floating_or_out_of_flow_positioned_ = false; }; @@ -194,8 +144,7 @@ template <typename ItemsBuilder> void CollectInlinesInternal(LayoutBlockFlow* block, ItemsBuilder* builder, - String* previous_text, - NGLineBoxMarker* marker) { + const String* previous_text) { builder->EnterBlock(block->Style()); LayoutObject* node = GetLayoutObjectForFirstChildNode(block); @@ -203,28 +152,11 @@ LayoutNGListItem::FindSymbolMarkerLayoutText(block); while (node) { if (LayoutText* layout_text = ToLayoutTextOrNull(node)) { - // If the LayoutText element hasn't changed, reuse the existing items. - - // if the last ended with space and this starts with space, do not allow - // reuse. builder->MightCollapseWithPreceding(*previous_text) - bool item_reused = false; - if (previous_text && layout_text->HasValidInlineItems()) - item_reused = builder->AppendTextReusing(*previous_text, layout_text); - - // If not create a new item as needed. - if (!item_reused) { - if (UNLIKELY(layout_text->IsWordBreak())) - builder->AppendBreakOpportunity(layout_text); - else - builder->AppendText(layout_text->GetText(), layout_text); - } + builder->AppendText(layout_text, previous_text); if (symbol == layout_text) builder->SetIsSymbolMarker(true); - if (marker && marker->HandleText(layout_text)) - marker = nullptr; - builder->ClearNeedsLayout(layout_text); } else if (node->IsFloating()) { @@ -252,9 +184,6 @@ // signal the presence of a non-text object to the unicode bidi // algorithm. builder->AppendAtomicInline(node); - - if (marker && marker->HandleAtomicInline(ToLayoutBox(node))) - marker = nullptr; } builder->ClearInlineFragment(node); @@ -268,9 +197,6 @@ builder->EnterInline(layout_inline); - if (marker && marker->HandleInlineBox(layout_inline)) - marker = nullptr; - // Traverse to children if they exist. if (LayoutObject* child = layout_inline->FirstChild()) { node = child; @@ -363,17 +289,29 @@ block_flow->ResetNGInlineNodeData(); } + if (NGPaintFragment* fragment = block_flow->PaintFragment()) { + NGDirtyLines dirty_lines(fragment); + PrepareLayout(std::move(previous_data), &dirty_lines); + return; + } + PrepareLayout(std::move(previous_data), /* dirty_lines */ nullptr); +} + +void NGInlineNode::PrepareLayout( + std::unique_ptr<NGInlineNodeData> previous_data, + NGDirtyLines* dirty_lines) { // Scan list of siblings collecting all in-flow non-atomic inlines. A single // NGInlineNode represent a collection of adjacent non-atomic inlines. NGInlineNodeData* data = MutableData(); DCHECK(data); - CollectInlines(data, previous_data.get()); + CollectInlines(data, previous_data.get(), dirty_lines); SegmentText(data); ShapeText(data, previous_data.get()); ShapeTextForFirstLineIfNeeded(data); AssociateItemsWithInlines(data); DCHECK_EQ(data, MutableData()); + LayoutBlockFlow* block_flow = GetLayoutBlockFlow(); block_flow->ClearNeedsCollectInlines(); #if DCHECK_IS_ON() @@ -418,7 +356,7 @@ NGInlineItemsBuilderForOffsetMapping builder(&items); builder.GetOffsetMappingBuilder().ReserveCapacity( EstimateOffsetMappingItemsCount(*layout_block_flow)); - CollectInlinesInternal(layout_block_flow, &builder, nullptr, nullptr); + CollectInlinesInternal(layout_block_flow, &builder, nullptr); // For non-NG object, we need the text, and also the inline items to resolve // bidi levels. Otherwise |data| already has the text from the pre-layout @@ -466,23 +404,18 @@ // parent LayoutInline where possible, and joining all text content in a single // string to allow bidi resolution and shaping of the entire block. void NGInlineNode::CollectInlines(NGInlineNodeData* data, - NGInlineNodeData* previous_data) { + NGInlineNodeData* previous_data, + NGDirtyLines* dirty_lines) { DCHECK(data->text_content.IsNull()); DCHECK(data->items.IsEmpty()); LayoutBlockFlow* block = GetLayoutBlockFlow(); block->WillCollectInlines(); - // If we have PaintFragment, mark line boxes dirty from |NeedsLayout| flag. - base::Optional<NGLineBoxMarker> marker; - if (NGPaintFragment* block_fragment = block->PaintFragment()) - marker.emplace(block_fragment); - String* previous_text = previous_data ? &previous_data->text_content : nullptr; data->items.ReserveCapacity(EstimateInlineItemsCount(*block)); - NGInlineItemsBuilder builder(&data->items); - CollectInlinesInternal(block, &builder, previous_text, - marker.has_value() ? &*marker : nullptr); + NGInlineItemsBuilder builder(&data->items, dirty_lines); + CollectInlinesInternal(block, &builder, previous_text); data->text_content = builder.ToString(); // Set |is_bidi_enabled_| for all UTF-16 strings for now, because at this @@ -998,15 +931,13 @@ if (constraint_space.HasBlockFragmentation()) return nullptr; - const NGPaintFragment* paint_fragment = block_flow->PaintFragment(); + NGPaintFragment* paint_fragment = block_flow->PaintFragment(); if (!paint_fragment) return nullptr; - if (!MarkLineBoxesDirty(block_flow)) + if (!MarkLineBoxesDirty(block_flow, paint_fragment)) return nullptr; - PrepareLayoutIfNeeded(); - if (Data().changes_may_affect_earlier_lines_) return nullptr; @@ -1018,10 +949,18 @@ // Removals of LayoutObject already marks relevant line boxes dirty by calling // |DirtyLinesFromChangedChild()|, but insertions and style changes are not // marked yet. -bool NGInlineNode::MarkLineBoxesDirty(LayoutBlockFlow* block_flow) { - NGLineBoxMarker marker(block_flow->PaintFragment()); - ItemsBuilderForMarkLineBoxesDirty builder; - CollectInlinesInternal(block_flow, &builder, nullptr, &marker); +bool NGInlineNode::MarkLineBoxesDirty(LayoutBlockFlow* block_flow, + NGPaintFragment* paint_fragment) { + NGDirtyLines dirty_lines(paint_fragment); + if (block_flow->NeedsCollectInlines()) { + std::unique_ptr<NGInlineNodeData> previous_data; + previous_data.reset(block_flow->TakeNGInlineNodeData()); + block_flow->ResetNGInlineNodeData(); + PrepareLayout(std::move(previous_data), &dirty_lines); + return true; + } + ItemsBuilderForMarkLineBoxesDirty builder(&dirty_lines); + CollectInlinesInternal(block_flow, &builder, nullptr); return !builder.ShouldAbort(); }
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h index 94052b21..25ab690b 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h
@@ -9,6 +9,7 @@ #include "third_party/blink/renderer/core/layout/layout_block_flow.h" #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h" #include "third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h" +#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h" #include "third_party/blink/renderer/platform/wtf/casting.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" @@ -16,10 +17,11 @@ class NGBlockBreakToken; class NGConstraintSpace; +class NGDirtyLines; class NGInlineChildLayoutContext; +class NGInlineNodeLegacy; class NGLayoutResult; class NGOffsetMapping; -class NGInlineNodeLegacy; struct MinMaxSize; struct NGInlineItemsData; @@ -59,8 +61,11 @@ // Instruct to re-compute |PrepareLayout| on the next layout. void InvalidatePrepareLayoutForTest() { - GetLayoutBlockFlow()->ResetNGInlineNodeData(); + LayoutBlockFlow* block_flow = GetLayoutBlockFlow(); + block_flow->ResetNGInlineNodeData(); DCHECK(!IsPrepareLayoutFinished()); + // There shouldn't be paint fragment if NGInlineNodeData does not exist. + block_flow->SetPaintFragment(nullptr, nullptr); } const NGInlineItemsData& ItemsData(bool is_first_line) const { @@ -100,21 +105,18 @@ String ToString() const; - // A helper function for NGInlineItemsBuilder. - static void ClearInlineFragment(LayoutObject* object) { - object->SetIsInLayoutNGInlineFormattingContext(true); - object->SetFirstInlineFragment(nullptr); - } - protected: bool IsPrepareLayoutFinished() const; // Prepare inline and text content for layout. Must be called before // calling the Layout method. void PrepareLayoutIfNeeded(); + void PrepareLayout(std::unique_ptr<NGInlineNodeData> previous_data, + NGDirtyLines* dirty_lines); void CollectInlines(NGInlineNodeData*, - NGInlineNodeData* previous_data = nullptr); + NGInlineNodeData* previous_data = nullptr, + NGDirtyLines* dirty_lines = nullptr); void SegmentText(NGInlineNodeData*); void SegmentScriptRuns(NGInlineNodeData*); void SegmentFontOrientation(NGInlineNodeData*); @@ -124,7 +126,7 @@ void ShapeTextForFirstLineIfNeeded(NGInlineNodeData*); void AssociateItemsWithInlines(NGInlineNodeData*); - bool MarkLineBoxesDirty(LayoutBlockFlow*); + bool MarkLineBoxesDirty(LayoutBlockFlow*, NGPaintFragment*); NGInlineNodeData* MutableData() { return To<LayoutBlockFlow>(box_)->GetNGInlineNodeData();
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc index 442409ea..ad30531 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc
@@ -77,7 +77,9 @@ void ShapeText() { NGInlineNode::ShapeText(MutableData()); } bool MarkLineBoxesDirty() { - return NGInlineNode::MarkLineBoxesDirty(GetLayoutBlockFlow()); + LayoutBlockFlow* block_flow = GetLayoutBlockFlow(); + return NGInlineNode::MarkLineBoxesDirty(block_flow, + block_flow->PaintFragment()); } }; @@ -1081,6 +1083,38 @@ ForceLayout(); // Ensure running layout does not crash. } +TEST_F(NGInlineNodeTest, MarkLineBoxesDirtyOnEndSpaceCollapsed) { + SetupHtml("container", R"HTML( + <style> + div { + font-size: 10px; + width: 8ch; + } + #empty { + background: yellow; /* ensure fragment is created */ + } + #target { + display: inline-block; + } + </style> + <div id=container> + 1234567890 + 1234567890 + <span id=empty> </span> + <span id=target></span></div> + )HTML"); + + // Removing #target makes the spaces before it to be collapsed. + Element* target = GetElementById("target"); + target->remove(); + + auto lines = MarkLineBoxesDirty(); + EXPECT_FALSE(lines[0]->IsDirty()); + EXPECT_TRUE(lines[1]->IsDirty()); + + ForceLayout(); // Ensure running layout does not crash. +} + // Test marking line boxes when the first span has NeedsLayout. The span is // culled. TEST_F(NGInlineNodeTest, MarkLineBoxesDirtyOnNeedsLayoutFirst) {
diff --git a/third_party/blink/renderer/core/loader/text_track_loader.cc b/third_party/blink/renderer/core/loader/text_track_loader.cc index 4998ea7..fc613bd1 100644 --- a/third_party/blink/renderer/core/loader/text_track_loader.cc +++ b/third_party/blink/renderer/core/loader/text_track_loader.cc
@@ -29,6 +29,7 @@ #include "third_party/blink/public/platform/task_type.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/inspector/console_message.h" +#include "third_party/blink/renderer/platform/heap/heap.h" #include "third_party/blink/renderer/platform/loader/fetch/fetch_initiator_type_names.h" #include "third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h" #include "third_party/blink/renderer/platform/loader/fetch/raw_resource.h" @@ -75,8 +76,10 @@ if (state_ == kFailed) return; - if (!cue_parser_) - cue_parser_ = VTTParser::Create(this, GetDocument()); + if (!cue_parser_) { + cue_parser_ = MakeGarbageCollected<VTTParser, VTTParserClient*, Document&>( + this, GetDocument()); + } cue_parser_->ParseBytes(data, length); }
diff --git a/third_party/blink/renderer/core/loader/text_track_loader.h b/third_party/blink/renderer/core/loader/text_track_loader.h index b3dac32..eda65bf5 100644 --- a/third_party/blink/renderer/core/loader/text_track_loader.h +++ b/third_party/blink/renderer/core/loader/text_track_loader.h
@@ -50,11 +50,6 @@ USING_GARBAGE_COLLECTED_MIXIN(TextTrackLoader); public: - static TextTrackLoader* Create(TextTrackLoaderClient& client, - Document& document) { - return MakeGarbageCollected<TextTrackLoader>(client, document); - } - TextTrackLoader(TextTrackLoaderClient&, Document&); ~TextTrackLoader() override;
diff --git a/third_party/blink/renderer/core/timing/window_performance.cc b/third_party/blink/renderer/core/timing/window_performance.cc index 2267206..8c71bc0 100644 --- a/third_party/blink/renderer/core/timing/window_performance.cc +++ b/third_party/blink/renderer/core/timing/window_performance.cc
@@ -365,7 +365,7 @@ DOMHighResTimeStamp end_time = MonotonicTimeToDOMHighResTimeStamp(timestamp); for (const auto& entry : event_timings_) { - int duration_in_ms = std::ceil((end_time - entry->startTime()) / 8) * 8; + int duration_in_ms = std::round((end_time - entry->startTime()) / 8) * 8; entry->SetDuration(duration_in_ms); if (!first_input_timing_) { if (entry->name() == "pointerdown") {
diff --git a/third_party/blink/renderer/core/timing/window_performance_test.cc b/third_party/blink/renderer/core/timing/window_performance_test.cc index 41b564b4..c446e1b 100644 --- a/third_party/blink/renderer/core/timing/window_performance_test.cc +++ b/third_party/blink/renderer/core/timing/window_performance_test.cc
@@ -252,6 +252,28 @@ performance_->clearEventTimings(); } +TEST_F(WindowPerformanceTest, Expose100MsEvents) { + ScopedEventTimingForTest event_timing(true); + TimeTicks start_time = GetTimeOrigin() + TimeDelta::FromSeconds(1); + TimeTicks processing_start = start_time + TimeDelta::FromMilliseconds(10); + TimeTicks processing_end = processing_start + TimeDelta::FromMilliseconds(10); + performance_->RegisterEventTiming("mousedown", start_time, processing_start, + processing_end, false); + + TimeTicks start_time2 = start_time + TimeDelta::FromMicroseconds(200); + performance_->RegisterEventTiming("click", start_time2, processing_start, + processing_end, false); + + // The swap time is 100.1 ms after |start_time| but only 99.9 ms after + // |start_time2|. + TimeTicks swap_time = start_time + TimeDelta::FromMicroseconds(100100); + SimulateSwapPromise(swap_time); + // Only the longer event should have been reported. + EXPECT_EQ(1u, performance_->getEntriesByType("event").size()); + EXPECT_EQ(1u, performance_->getEntriesByName("mousedown", "event").size()); + EXPECT_EQ(0u, performance_->getEntriesByName("click", "event").size()); +} + TEST_F(WindowPerformanceTest, EventTimingDuration) { ScopedEventTimingForTest event_timing(true); @@ -270,7 +292,7 @@ performance_->RegisterEventTiming("click", start_time, processing_start, processing_end, true); TimeTicks long_swap_time = - GetTimeOrigin() + TimeDelta::FromMilliseconds(1100); + GetTimeOrigin() + TimeDelta::FromMilliseconds(2000); SimulateSwapPromise(long_swap_time); EXPECT_EQ(1u, performance_->getEntriesByName("click", "event").size());
diff --git a/third_party/blink/renderer/modules/BUILD.gn b/third_party/blink/renderer/modules/BUILD.gn index abc394d..1ac21e4 100644 --- a/third_party/blink/renderer/modules/BUILD.gn +++ b/third_party/blink/renderer/modules/BUILD.gn
@@ -307,6 +307,7 @@ "indexeddb/web_idb_cursor_impl_unittest.cc", "indexeddb/web_idb_transaction_impl_unittest.cc", "manifest/image_resource_type_converters_test.cc", + "manifest/manifest_manager_unittest.cc", "manifest/manifest_parser_unittest.cc", "media_controls/elements/media_control_animated_arrow_container_element_test.cc", "media_controls/elements/media_control_display_cutout_fullscreen_button_element_test.cc",
diff --git a/third_party/blink/renderer/modules/manifest/BUILD.gn b/third_party/blink/renderer/modules/manifest/BUILD.gn index 9024c30..c437685 100644 --- a/third_party/blink/renderer/modules/manifest/BUILD.gn +++ b/third_party/blink/renderer/modules/manifest/BUILD.gn
@@ -8,6 +8,8 @@ sources = [ "image_resource_type_converters.cc", "image_resource_type_converters.h", + "manifest_change_notifier.cc", + "manifest_change_notifier.h", "manifest_fetcher.cc", "manifest_fetcher.h", "manifest_manager.cc",
diff --git a/third_party/blink/renderer/modules/manifest/manifest_change_notifier.cc b/third_party/blink/renderer/modules/manifest/manifest_change_notifier.cc new file mode 100644 index 0000000..2fda9bf2 --- /dev/null +++ b/third_party/blink/renderer/modules/manifest/manifest_change_notifier.cc
@@ -0,0 +1,83 @@ +// 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 "third_party/blink/renderer/modules/manifest/manifest_change_notifier.h" + +#include <utility> + +#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h" +#include "third_party/blink/renderer/core/dom/document.h" +#include "third_party/blink/renderer/core/frame/local_frame.h" +#include "third_party/blink/renderer/modules/manifest/manifest_manager.h" + +namespace blink { + +ManifestChangeNotifier::ManifestChangeNotifier(LocalFrame& frame) + : frame_(&frame) {} + +ManifestChangeNotifier::~ManifestChangeNotifier() = default; + +void ManifestChangeNotifier::Trace(Visitor* visitor) { + visitor->Trace(frame_); +} + +void ManifestChangeNotifier::DidChangeManifest() { + // Manifests are not considered when the current page has a unique origin. + if (!ManifestManager::From(*frame_)->CanFetchManifest()) + return; + + if (report_task_scheduled_) + return; + + // Changing the manifest URL can trigger multiple notifications; the manifest + // URL update may involve removing the old manifest link before adding the new + // one, triggering multiple calls to DidChangeManifest(). Coalesce changes + // during a single event loop task to avoid sending spurious notifications to + // the browser. + // + // During document load, coalescing is disabled to maintain relative ordering + // of this notification and the favicon URL reporting. + if (!frame_->IsLoading()) { + report_task_scheduled_ = true; + frame_->GetTaskRunner(TaskType::kInternalLoading) + ->PostTask(FROM_HERE, + WTF::Bind(&ManifestChangeNotifier::ReportManifestChange, + WrapWeakPersistent(this))); + return; + } + ReportManifestChange(); +} + +void ManifestChangeNotifier::ReportManifestChange() { + report_task_scheduled_ = false; + if (!frame_ || !frame_->GetDocument() || !frame_->IsAttached()) + return; + + auto manifest_url = ManifestManager::From(*frame_)->ManifestURL(); + + EnsureManifestChangeObserver(); + + // |manifest_change_observer_| may be null for tests. + if (!manifest_change_observer_) + return; + + if (manifest_url.IsNull()) + manifest_change_observer_->ManifestUrlChanged(base::nullopt); + else + manifest_change_observer_->ManifestUrlChanged(manifest_url); +} + +void ManifestChangeNotifier::EnsureManifestChangeObserver() { + if (manifest_change_observer_) + return; + + AssociatedInterfaceProvider* provider = + frame_->GetRemoteNavigationAssociatedInterfaces(); + if (!provider) + return; + + provider->GetInterface(&manifest_change_observer_); +} + +} // namespace blink
diff --git a/third_party/blink/renderer/modules/manifest/manifest_change_notifier.h b/third_party/blink/renderer/modules/manifest/manifest_change_notifier.h new file mode 100644 index 0000000..759b4f0d --- /dev/null +++ b/third_party/blink/renderer/modules/manifest/manifest_change_notifier.h
@@ -0,0 +1,42 @@ +// 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 THIRD_PARTY_BLINK_RENDERER_MODULES_MANIFEST_MANIFEST_CHANGE_NOTIFIER_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_MANIFEST_MANIFEST_CHANGE_NOTIFIER_H_ + +#include "base/macros.h" +#include "third_party/blink/public/mojom/manifest/manifest_observer.mojom-blink.h" +#include "third_party/blink/renderer/modules/modules_export.h" +#include "third_party/blink/renderer/platform/heap/handle.h" +#include "third_party/blink/renderer/platform/heap/member.h" + +namespace blink { + +class LocalFrame; + +class MODULES_EXPORT ManifestChangeNotifier + : public GarbageCollectedFinalized<ManifestChangeNotifier> { + public: + explicit ManifestChangeNotifier(LocalFrame& frame); + virtual ~ManifestChangeNotifier(); + + virtual void Trace(blink::Visitor*); + + virtual void DidChangeManifest(); + + private: + void ReportManifestChange(); + void EnsureManifestChangeObserver(); + + Member<LocalFrame> frame_; + mojom::blink::ManifestUrlChangeObserverAssociatedPtr + manifest_change_observer_; + bool report_task_scheduled_ = false; + + DISALLOW_COPY_AND_ASSIGN(ManifestChangeNotifier); +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_MANIFEST_MANIFEST_CHANGE_NOTIFIER_H_
diff --git a/third_party/blink/renderer/modules/manifest/manifest_manager.cc b/third_party/blink/renderer/modules/manifest/manifest_manager.cc index ed920be..3ad9ff6 100644 --- a/third_party/blink/renderer/modules/manifest/manifest_manager.cc +++ b/third_party/blink/renderer/modules/manifest/manifest_manager.cc
@@ -11,10 +11,11 @@ #include "third_party/blink/public/platform/interface_registry.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/frame/frame_console.h" -#include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/local_frame_client.h" #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h" +#include "third_party/blink/renderer/core/html/html_link_element.h" #include "third_party/blink/renderer/core/inspector/console_message.h" +#include "third_party/blink/renderer/modules/manifest/manifest_change_notifier.h" #include "third_party/blink/renderer/modules/manifest/manifest_fetcher.h" #include "third_party/blink/renderer/modules/manifest/manifest_parser.h" #include "third_party/blink/renderer/modules/manifest/manifest_type_converters.h" @@ -52,6 +53,8 @@ may_have_manifest_(false), manifest_dirty_(true) { if (frame.IsMainFrame()) { + manifest_change_notifier_ = + MakeGarbageCollected<ManifestChangeNotifier>(frame); frame.GetInterfaceRegistry()->AddInterface(WTF::BindRepeating( &ManifestManager::BindToRequest, WrapWeakPersistent(this))); } @@ -132,6 +135,8 @@ manifest_dirty_ = true; manifest_url_ = KURL(); manifest_debug_info_ = nullptr; + if (manifest_change_notifier_) + manifest_change_notifier_->DidChangeManifest(); } void ManifestManager::DidCommitLoad() { @@ -147,17 +152,16 @@ return; } - Document& document = *(GetSupplementable()->GetDocument()); - manifest_url_ = document.ManifestURL(); - + manifest_url_ = ManifestURL(); if (manifest_url_.IsEmpty()) { ManifestUmaUtil::FetchFailed(ManifestUmaUtil::FETCH_EMPTY_URL); ResolveCallbacks(ResolveStateFailure); return; } + Document& document = *GetSupplementable()->GetDocument(); fetcher_ = MakeGarbageCollected<ManifestFetcher>(manifest_url_); - fetcher_->Start(document, document.ManifestUseCredentials(), + fetcher_->Start(document, ManifestUseCredentials(), WTF::Bind(&ManifestManager::OnManifestFetchComplete, WrapWeakPersistent(this), document.Url())); } @@ -185,8 +189,7 @@ for (const auto& error : manifest_debug_info_->errors) { auto location = std::make_unique<SourceLocation>( - GetSupplementable()->GetDocument()->ManifestURL().GetString(), - error->line, error->column, nullptr, 0); + ManifestURL().GetString(), error->line, error->column, nullptr, 0); GetSupplementable()->Console().AddMessage(ConsoleMessage::Create( mojom::ConsoleMessageSource::kOther, @@ -228,6 +231,24 @@ } } +KURL ManifestManager::ManifestURL() const { + HTMLLinkElement* link_element = + GetSupplementable()->GetDocument()->LinkManifest(); + if (!link_element) + return KURL(); + return link_element->Href(); +} + +bool ManifestManager::ManifestUseCredentials() const { + HTMLLinkElement* link_element = + GetSupplementable()->GetDocument()->LinkManifest(); + if (!link_element) + return false; + return EqualIgnoringASCIICase( + link_element->FastGetAttribute(html_names::kCrossoriginAttr), + "use-credentials"); +} + void ManifestManager::BindToRequest( mojom::blink::ManifestManagerRequest request) { bindings_.AddBinding(this, std::move(request)); @@ -249,6 +270,7 @@ void ManifestManager::Trace(blink::Visitor* visitor) { visitor->Trace(fetcher_); + visitor->Trace(manifest_change_notifier_); Supplement<LocalFrame>::Trace(visitor); ContextLifecycleObserver::Trace(visitor); }
diff --git a/third_party/blink/renderer/modules/manifest/manifest_manager.h b/third_party/blink/renderer/modules/manifest/manifest_manager.h index 3876cb0..5a923f1 100644 --- a/third_party/blink/renderer/modules/manifest/manifest_manager.h +++ b/third_party/blink/renderer/modules/manifest/manifest_manager.h
@@ -13,12 +13,15 @@ #include "third_party/blink/public/mojom/manifest/manifest_manager.mojom-blink.h" #include "third_party/blink/public/web/web_manifest_manager.h" #include "third_party/blink/renderer/core/execution_context/context_lifecycle_observer.h" +#include "third_party/blink/renderer/core/frame/local_frame.h" +#include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/platform/heap/member.h" #include "third_party/blink/renderer/platform/supplementable.h" namespace blink { -class LocalFrame; +class ManifestChangeNotifier; +class ManifestManagerTest; class ManifestFetcher; class ResourceResponse; @@ -27,11 +30,12 @@ // the ManifestParser in order to do so. // // Consumers should use the mojo ManifestManager interface to use this class. -class ManifestManager : public GarbageCollectedFinalized<ManifestManager>, - public WebManifestManager, - public Supplement<LocalFrame>, - public mojom::blink::ManifestManager, - public ContextLifecycleObserver { +class MODULES_EXPORT ManifestManager + : public GarbageCollectedFinalized<ManifestManager>, + public WebManifestManager, + public Supplement<LocalFrame>, + public mojom::blink::ManifestManager, + public ContextLifecycleObserver { USING_GARBAGE_COLLECTED_MIXIN(ManifestManager); public: @@ -41,17 +45,18 @@ static void ProvideTo(LocalFrame&); - static bool CanFetchManifest(LocalFrame* frame); - explicit ManifestManager(LocalFrame&); ~ManifestManager() override; void DidChangeManifest(); void DidCommitLoad(); + bool CanFetchManifest(); + + KURL ManifestURL() const; + bool ManifestUseCredentials() const; // WebManifestManager void RequestManifest(WebCallback callback) override; - bool CanFetchManifest() override; void Trace(blink::Visitor*) override; @@ -83,7 +88,10 @@ void Dispose(); + friend class ManifestManagerTest; + Member<ManifestFetcher> fetcher_; + Member<ManifestChangeNotifier> manifest_change_notifier_; // Whether the LocalFrame may have an associated Manifest. If true, the frame // may have a manifest, if false, it can't have one. This boolean is true when
diff --git a/third_party/blink/renderer/modules/manifest/manifest_manager_unittest.cc b/third_party/blink/renderer/modules/manifest/manifest_manager_unittest.cc new file mode 100644 index 0000000..e27601f --- /dev/null +++ b/third_party/blink/renderer/modules/manifest/manifest_manager_unittest.cc
@@ -0,0 +1,145 @@ +// 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/manifest/manifest_manager.h" + +#include <string> + +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/platform/web_url.h" +#include "third_party/blink/renderer/core/dom/document.h" +#include "third_party/blink/renderer/core/frame/frame_test_helpers.h" +#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h" +#include "third_party/blink/renderer/core/html/html_head_element.h" +#include "third_party/blink/renderer/core/html/html_link_element.h" +#include "third_party/blink/renderer/core/testing/page_test_base.h" +#include "third_party/blink/renderer/modules/manifest/manifest_change_notifier.h" +#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h" +#include "third_party/blink/renderer/platform/testing/url_test_helpers.h" +#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" + +namespace blink { + +namespace { + +void RegisterMockedURL(const std::string& base_url, + const std::string& file_name) { + url_test_helpers::RegisterMockedURLLoadFromBase( + WebString::FromUTF8(base_url), test::CoreTestDataPath(), + WebString::FromUTF8(file_name)); +} + +} // namespace + +class MockManifestChangeNotifier : public ManifestChangeNotifier { + public: + MockManifestChangeNotifier(LocalFrame& frame) + : ManifestChangeNotifier(frame), manifest_change_count_(0) {} + ~MockManifestChangeNotifier() override = default; + + // ManifestChangeNotifier: + void DidChangeManifest() override { ++manifest_change_count_; } + + int ManifestChangeCount() { return manifest_change_count_; } + + private: + int manifest_change_count_; +}; + +class ManifestManagerTest : public PageTestBase { + protected: + ManifestManagerTest() : base_url_("http://internal.test/") {} + void SetUp() override { + PageTestBase::SetUp(IntSize()); + ManifestManager::ProvideTo(GetFrame()); + } + + void TearDown() override { + ThreadState::Current()->CollectAllGarbageForTesting(); + } + + ManifestManager* GetManifestManager(LocalFrame* frame = nullptr) { + return ManifestManager::From(frame ? *frame : GetFrame()); + } + + void SetMockManifestChangeNotifier(LocalFrame* frame) { + GetManifestManager(frame)->manifest_change_notifier_ = + MakeGarbageCollected<MockManifestChangeNotifier>(*frame); + } + + int ManifestChangeCount(LocalFrame* frame) { + return static_cast<MockManifestChangeNotifier*>( + GetManifestManager(frame)->manifest_change_notifier_.Get()) + ->ManifestChangeCount(); + } + + std::string base_url_; +}; + +TEST_F(ManifestManagerTest, ManifestURL) { + // Test the default result. + EXPECT_EQ(nullptr, GetDocument().LinkManifest()); + + // Check that we use the first manifest with <link rel=manifest> + auto* link_manifest = MakeGarbageCollected<HTMLLinkElement>( + GetDocument(), CreateElementFlags()); + link_manifest->setAttribute(blink::html_names::kRelAttr, "manifest"); + GetDocument().head()->AppendChild(link_manifest); + EXPECT_EQ(link_manifest, GetDocument().LinkManifest()); + + // No href attribute was set. + EXPECT_EQ(KURL(), GetManifestManager()->ManifestURL()); + + // Set to some absolute url. + link_manifest->setAttribute(html_names::kHrefAttr, + "http://example.com/manifest.json"); + ASSERT_EQ(link_manifest->Href(), GetManifestManager()->ManifestURL()); + + // Set to some relative url. + link_manifest->setAttribute(html_names::kHrefAttr, "static/manifest.json"); + ASSERT_EQ(link_manifest->Href(), GetManifestManager()->ManifestURL()); +} + +TEST_F(ManifestManagerTest, ManifestUseCredentials) { + // Test the default result. + EXPECT_EQ(nullptr, GetDocument().LinkManifest()); + + // Check that we use the first manifest with <link rel=manifest> + auto* link_manifest = MakeGarbageCollected<HTMLLinkElement>( + GetDocument(), CreateElementFlags()); + link_manifest->setAttribute(blink::html_names::kRelAttr, "manifest"); + GetDocument().head()->AppendChild(link_manifest); + + // No crossorigin attribute was set so credentials shouldn't be used. + ASSERT_FALSE(link_manifest->FastHasAttribute(html_names::kCrossoriginAttr)); + ASSERT_FALSE(GetManifestManager()->ManifestUseCredentials()); + + // Crossorigin set to a random string shouldn't trigger using credentials. + link_manifest->setAttribute(html_names::kCrossoriginAttr, "foobar"); + ASSERT_FALSE(GetManifestManager()->ManifestUseCredentials()); + + // Crossorigin set to 'anonymous' shouldn't trigger using credentials. + link_manifest->setAttribute(html_names::kCrossoriginAttr, "anonymous"); + ASSERT_FALSE(GetManifestManager()->ManifestUseCredentials()); + + // Crossorigin set to 'use-credentials' should trigger using credentials. + link_manifest->setAttribute(html_names::kCrossoriginAttr, "use-credentials"); + ASSERT_TRUE(GetManifestManager()->ManifestUseCredentials()); +} + +TEST_F(ManifestManagerTest, NotifyManifestChange) { + RegisterMockedURL(base_url_, "link-manifest-change.html"); + + frame_test_helpers::WebViewHelper web_view_helper; + web_view_helper.Initialize(); + + auto* frame = web_view_helper.GetWebView()->MainFrameImpl(); + SetMockManifestChangeNotifier(frame->GetFrame()); + frame_test_helpers::LoadFrame(frame, base_url_ + "link-manifest-change.html"); + + EXPECT_EQ(14, ManifestChangeCount(frame->GetFrame())); +} + +} // namespace blink
diff --git a/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate_test.cc b/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate_test.cc index 9b48647..af928e1 100644 --- a/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate_test.cc +++ b/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate_test.cc
@@ -30,6 +30,7 @@ #include "third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller_impl.h" #include "third_party/blink/renderer/modules/screen_orientation/web_lock_orientation_callback.h" #include "third_party/blink/renderer/platform/geometry/int_rect.h" +#include "third_party/blink/renderer/platform/heap/heap.h" #include "third_party/blink/renderer/platform/testing/empty_web_media_player.h" #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h" #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h" @@ -439,7 +440,7 @@ } TEST_F(MediaControlsOrientationLockDelegateTest, DelegateRequiresVideo) { - HTMLAudioElement* audio = HTMLAudioElement::Create(GetDocument()); + auto* audio = MakeGarbageCollected<HTMLAudioElement>(GetDocument()); GetDocument().body()->AppendChild(audio); EXPECT_FALSE(HasDelegate(*audio->GetMediaControls())); }
diff --git a/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate_test.cc b/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate_test.cc index 5ff1999..677d266 100644 --- a/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate_test.cc +++ b/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate_test.cc
@@ -28,6 +28,7 @@ #include "third_party/blink/renderer/modules/device_orientation/device_orientation_data.h" #include "third_party/blink/renderer/modules/media_controls/media_controls_impl.h" #include "third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller_impl.h" +#include "third_party/blink/renderer/platform/heap/heap.h" #include "third_party/blink/renderer/platform/testing/empty_web_media_player.h" #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h" #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h" @@ -250,7 +251,7 @@ } TEST_F(MediaControlsRotateToFullscreenDelegateTest, DelegateRequiresVideo) { - HTMLAudioElement* audio = HTMLAudioElement::Create(GetDocument()); + auto* audio = MakeGarbageCollected<HTMLAudioElement>(GetDocument()); GetDocument().body()->AppendChild(audio); EXPECT_FALSE(HasDelegate(*audio->GetMediaControls())); }
diff --git a/third_party/blink/renderer/modules/mediastream/video_track_adapter.cc b/third_party/blink/renderer/modules/mediastream/video_track_adapter.cc index f151df43..302cac0 100644 --- a/third_party/blink/renderer/modules/mediastream/video_track_adapter.cc +++ b/third_party/blink/renderer/modules/mediastream/video_track_adapter.cc
@@ -25,9 +25,7 @@ #include "media/base/video_util.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/public/web/modules/mediastream/video_track_adapter_settings.h" -#include "third_party/blink/renderer/platform/cross_thread_functional.h" #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h" -#include "third_party/blink/renderer/platform/wtf/functional.h" #include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h" namespace blink { @@ -136,9 +134,9 @@ : public WTF::ThreadSafeRefCounted<VideoFrameResolutionAdapter> { public: struct VideoTrackCallbacks { - VideoCaptureDeliverFrameCB frame_callback; - VideoTrackSettingsCallback settings_callback; - VideoTrackFormatCallback format_callback; + VideoCaptureDeliverFrameInternalCallback frame_callback; + VideoTrackSettingsInternalCallback settings_callback; + VideoTrackFormatInternalCallback format_callback; }; // Setting |max_frame_rate| to 0.0, means that no frame rate limitation // will be done. @@ -152,9 +150,9 @@ // |settings_callback| to set track settings on the main thread. // |frame_callback| will however be released on the main render thread. void AddCallbacks(const MediaStreamVideoTrack* track, - VideoCaptureDeliverFrameCB frame_callback, - VideoTrackSettingsCallback settings_callback, - VideoTrackFormatCallback format_callback); + VideoCaptureDeliverFrameInternalCallback frame_callback, + VideoTrackSettingsInternalCallback settings_callback, + VideoTrackFormatInternalCallback format_callback); // Removes the callbacks associated with |track| if |track| has been added. It // is ok to call RemoveCallbacks() even if |track| has not been added. @@ -195,7 +193,7 @@ // Updates track settings if either frame width, height or frame rate have // changed since last update. void MaybeUpdateTrackSettings( - const VideoTrackSettingsCallback& settings_callback, + const VideoTrackSettingsInternalCallback& settings_callback, const scoped_refptr<media::VideoFrame>& frame); // Updates computed source format for all tracks if either frame width, height @@ -259,13 +257,15 @@ void VideoTrackAdapter::VideoFrameResolutionAdapter::AddCallbacks( const MediaStreamVideoTrack* track, - VideoCaptureDeliverFrameCB frame_callback, - VideoTrackSettingsCallback settings_callback, - VideoTrackFormatCallback format_callback) { + VideoCaptureDeliverFrameInternalCallback frame_callback, + VideoTrackSettingsInternalCallback settings_callback, + VideoTrackFormatInternalCallback format_callback) { DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_); - callbacks_.insert({track, - {std::move(frame_callback), std::move(settings_callback), - std::move(format_callback)}}); + + VideoTrackCallbacks track_callbacks = {std::move(frame_callback), + std::move(settings_callback), + std::move(format_callback)}; + callbacks_.insert({track, std::move(track_callbacks)}); } void VideoTrackAdapter::VideoFrameResolutionAdapter::RemoveCallbacks( @@ -283,7 +283,7 @@ if (it == callbacks_.end()) return track_callbacks; - track_callbacks = it->second; + track_callbacks = std::move(it->second); callbacks_.erase(it); return track_callbacks; } @@ -446,7 +446,7 @@ } void VideoTrackAdapter::VideoFrameResolutionAdapter::MaybeUpdateTrackSettings( - const VideoTrackSettingsCallback& settings_callback, + const VideoTrackSettingsInternalCallback& settings_callback, const scoped_refptr<media::VideoFrame>& frame) { DCHECK_CALLED_ON_VALID_THREAD(io_thread_checker_); ComputeFrameRate(frame->timestamp(), &track_settings_.frame_rate, @@ -511,18 +511,21 @@ const VideoTrackAdapterSettings& settings) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - io_task_runner_->PostTask( - FROM_HERE, - base::BindOnce(&VideoTrackAdapter::AddTrackOnIO, this, track, - std::move(frame_callback), std::move(settings_callback), - std::move(format_callback), settings)); + PostCrossThreadTask( + *io_task_runner_, FROM_HERE, + CrossThreadBind( + &VideoTrackAdapter::AddTrackOnIO, CrossThreadUnretained(this), + CrossThreadUnretained(track), + WTF::Passed(CrossThreadBind(std::move(frame_callback))), + WTF::Passed(CrossThreadBind(std::move(settings_callback))), + WTF::Passed(CrossThreadBind(std::move(format_callback))), settings)); } void VideoTrackAdapter::AddTrackOnIO( const MediaStreamVideoTrack* track, - VideoCaptureDeliverFrameCB frame_callback, - VideoTrackSettingsCallback settings_callback, - VideoTrackFormatCallback format_callback, + VideoCaptureDeliverFrameInternalCallback frame_callback, + VideoTrackSettingsInternalCallback settings_callback, + VideoTrackFormatInternalCallback format_callback, const VideoTrackAdapterSettings& settings) { DCHECK(io_task_runner_->BelongsToCurrentThread()); scoped_refptr<VideoFrameResolutionAdapter> adapter; @@ -570,10 +573,12 @@ VideoTrackAdapter::OnMutedCallback bound_on_muted_callback = media::BindToCurrentLoop(on_muted_callback); - io_task_runner_->PostTask( - FROM_HERE, - base::BindOnce(&VideoTrackAdapter::StartFrameMonitoringOnIO, this, - std::move(bound_on_muted_callback), source_frame_rate)); + PostCrossThreadTask( + *io_task_runner_, FROM_HERE, + CrossThreadBind( + &VideoTrackAdapter::StartFrameMonitoringOnIO, WrapRefCounted(this), + WTF::Passed(CrossThreadBind(std::move(bound_on_muted_callback))), + source_frame_rate)); } void VideoTrackAdapter::StopFrameMonitoring() { @@ -654,7 +659,7 @@ } void VideoTrackAdapter::StartFrameMonitoringOnIO( - const OnMutedCallback& on_muted_callback, + OnMutedInternalCallback on_muted_callback, double source_frame_rate) { DCHECK(io_task_runner_->BelongsToCurrentThread()); DCHECK(!monitoring_frame_rate_); @@ -667,10 +672,11 @@ source_frame_rate_ = source_frame_rate; DVLOG(1) << "Monitoring frame creation, first (large) delay: " << (kFirstFrameTimeoutInFrameIntervals / source_frame_rate_) << "s"; - io_task_runner_->PostDelayedTask( - FROM_HERE, - base::BindOnce(&VideoTrackAdapter::CheckFramesReceivedOnIO, this, - on_muted_callback, frame_counter_), + PostDelayedCrossThreadTask( + *io_task_runner_, FROM_HERE, + CrossThreadBind( + &VideoTrackAdapter::CheckFramesReceivedOnIO, WrapRefCounted(this), + WTF::Passed(std::move(on_muted_callback)), frame_counter_), base::TimeDelta::FromSecondsD(kFirstFrameTimeoutInFrameIntervals / source_frame_rate_)); } @@ -706,17 +712,17 @@ // Remove the track. for (auto* it = adapters_.begin(); it != adapters_.end(); ++it) { track_callbacks = (*it)->RemoveAndGetCallbacks(track); - if (track_callbacks.frame_callback.is_null()) + if (!track_callbacks.frame_callback) continue; if ((*it)->IsEmpty()) { - DCHECK(!track_callbacks.frame_callback.is_null()); + DCHECK(track_callbacks.frame_callback); adapters_.erase(it); } break; } // If the track was found, re-add it with new settings. - if (!track_callbacks.frame_callback.is_null()) { + if (track_callbacks.frame_callback) { AddTrackOnIO(track, std::move(track_callbacks.frame_callback), std::move(track_callbacks.settings_callback), std::move(track_callbacks.format_callback), settings); @@ -739,18 +745,18 @@ is_device_rotated = true; } if (adapters_.IsEmpty()) { - renderer_task_runner_->PostTask( - FROM_HERE, - base::BindOnce(frame_dropped_cb_, - media::VideoCaptureFrameDropReason:: - kVideoTrackAdapterHasNoResolutionAdapters)); + PostCrossThreadTask( + *renderer_task_runner_, FROM_HERE, + CrossThreadBind(frame_dropped_cb_, + media::VideoCaptureFrameDropReason:: + kVideoTrackAdapterHasNoResolutionAdapters)); } for (const auto& adapter : adapters_) adapter->DeliverFrame(frame, estimated_capture_time, is_device_rotated); } void VideoTrackAdapter::CheckFramesReceivedOnIO( - const OnMutedCallback& set_muted_state_callback, + OnMutedInternalCallback set_muted_state_callback, uint64_t old_frame_counter_snapshot) { DCHECK(io_task_runner_->BelongsToCurrentThread()); @@ -770,10 +776,11 @@ } } - io_task_runner_->PostDelayedTask( - FROM_HERE, - base::BindOnce(&VideoTrackAdapter::CheckFramesReceivedOnIO, this, - set_muted_state_callback, frame_counter_), + PostDelayedCrossThreadTask( + *io_task_runner_, FROM_HERE, + CrossThreadBind( + &VideoTrackAdapter::CheckFramesReceivedOnIO, WrapRefCounted(this), + WTF::Passed(std::move(set_muted_state_callback)), frame_counter_), base::TimeDelta::FromSecondsD(kNormalFrameTimeoutInFrameIntervals / source_frame_rate_)); }
diff --git a/third_party/blink/renderer/modules/mediastream/video_track_adapter.h b/third_party/blink/renderer/modules/mediastream/video_track_adapter.h index 84afd5c..41f56ec20 100644 --- a/third_party/blink/renderer/modules/mediastream/video_track_adapter.h +++ b/third_party/blink/renderer/modules/mediastream/video_track_adapter.h
@@ -16,6 +16,7 @@ #include "third_party/blink/public/platform/modules/mediastream/media_stream_types.h" #include "third_party/blink/public/platform/web_common.h" #include "third_party/blink/public/web/modules/mediastream/media_stream_video_track.h" +#include "third_party/blink/renderer/platform/cross_thread_functional.h" #include "third_party/blink/renderer/platform/geometry/int_size.h" #include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h" #include "third_party/blink/renderer/platform/wtf/vector.h" @@ -92,23 +93,36 @@ virtual ~VideoTrackAdapter(); friend class WTF::ThreadSafeRefCounted<VideoTrackAdapter>; + // These aliases mimic the definition of VideoCaptureDeliverFrameCB, + // VideoTrackSettingsCallback and VideoTrackFormatCallback respectively. + using VideoCaptureDeliverFrameInternalCallback = + WTF::CrossThreadFunction<void( + const scoped_refptr<media::VideoFrame>& video_frame, + base::TimeTicks estimated_capture_time)>; + using VideoTrackSettingsInternalCallback = + WTF::CrossThreadFunction<void(gfx::Size frame_size, double frame_rate)>; + using VideoTrackFormatInternalCallback = + WTF::CrossThreadFunction<void(const media::VideoCaptureFormat&)>; void AddTrackOnIO(const MediaStreamVideoTrack* track, - VideoCaptureDeliverFrameCB frame_callback, - VideoTrackSettingsCallback settings_callback, - VideoTrackFormatCallback track_callback, + VideoCaptureDeliverFrameInternalCallback frame_callback, + VideoTrackSettingsInternalCallback settings_callback, + VideoTrackFormatInternalCallback track_callback, const VideoTrackAdapterSettings& settings); + void RemoveTrackOnIO(const MediaStreamVideoTrack* track); void ReconfigureTrackOnIO(const MediaStreamVideoTrack* track, const VideoTrackAdapterSettings& settings); - void StartFrameMonitoringOnIO(const OnMutedCallback& on_muted_state_callback, + using OnMutedInternalCallback = + WTF::CrossThreadFunction<void(bool mute_state)>; + void StartFrameMonitoringOnIO(OnMutedInternalCallback on_muted_state_callback, double source_frame_rate); void StopFrameMonitoringOnIO(); void SetSourceFrameSizeOnIO(const IntSize& frame_size); // Compare |frame_counter_snapshot| with the current |frame_counter_|, and // inform of the situation (muted, not muted) via |set_muted_state_callback|. - void CheckFramesReceivedOnIO(const OnMutedCallback& set_muted_state_callback, + void CheckFramesReceivedOnIO(OnMutedInternalCallback set_muted_state_callback, uint64_t old_frame_counter_snapshot); // |thread_checker_| is bound to the main render thread.
diff --git a/third_party/blink/renderer/modules/modules_idl_files.gni b/third_party/blink/renderer/modules/modules_idl_files.gni index 1519caa..0846826 100644 --- a/third_party/blink/renderer/modules/modules_idl_files.gni +++ b/third_party/blink/renderer/modules/modules_idl_files.gni
@@ -680,6 +680,7 @@ "payments/payment_instrument.idl", "payments/payment_item.idl", "payments/payment_method_change_event_init.idl", + "payments/payment_method_change_response.idl", "payments/payment_method_data.idl", "payments/payment_options.idl", "payments/payment_request_event_init.idl",
diff --git a/third_party/blink/renderer/modules/payments/payment_details_update.idl b/third_party/blink/renderer/modules/payments/payment_details_update.idl index 7d798eb..52fb7d9 100644 --- a/third_party/blink/renderer/modules/payments/payment_details_update.idl +++ b/third_party/blink/renderer/modules/payments/payment_details_update.idl
@@ -2,10 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// https://w3c.github.io/browser-payment-api/#paymentdetailsupdate-dictionary +// https://w3c.github.io/payment-request/#dom-paymentdetailsupdate dictionary PaymentDetailsUpdate : PaymentDetailsBase { DOMString error; PaymentItem total; AddressErrors shippingAddressErrors; + object paymentMethodErrors; };
diff --git a/third_party/blink/renderer/modules/payments/payment_method_change_response.idl b/third_party/blink/renderer/modules/payments/payment_method_change_response.idl new file mode 100644 index 0000000..17f7d2a --- /dev/null +++ b/third_party/blink/renderer/modules/payments/payment_method_change_response.idl
@@ -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. + +// https://w3c.github.io/payment-handler/#dom-paymentmethodchangeresponse + +dictionary PaymentMethodChangeResponse { + DOMString error; + PaymentCurrencyAmount total; + FrozenArray<PaymentDetailsModifier> modifiers; + object paymentMethodErrors; +};
diff --git a/third_party/blink/renderer/modules/payments/payment_request.cc b/third_party/blink/renderer/modules/payments/payment_request.cc index 44c1521..de78a9a3 100644 --- a/third_party/blink/renderer/modules/payments/payment_request.cc +++ b/third_party/blink/renderer/modules/payments/payment_request.cc
@@ -399,25 +399,10 @@ const ScriptValue& input, PaymentMethodDataPtr& output, ExceptionState& exception_state) { - DCHECK(!input.IsEmpty()); - v8::Local<v8::String> value; - if (!input.V8Value()->IsObject() || - !v8::JSON::Stringify(input.GetContext(), input.V8Value().As<v8::Object>()) - .ToLocal(&value)) { - exception_state.ThrowTypeError( - "Payment method data should be a JSON-serializable object"); + PaymentsValidators::ValidateAndStringifyObject( + "Payment method data", input, output->stringified_data, exception_state); + if (exception_state.HadException()) return; - } - - output->stringified_data = ToBlinkString<String>(value, kDoNotExternalize); - - if (output->stringified_data.length() > - PaymentRequest::kMaxJSONStringLength) { - exception_state.ThrowTypeError( - "JSON serialization of payment method data should be no longer than " - "1048576 characters"); - return; - } // Serialize payment method specific data to be sent to the payment apps. The // payment apps are responsible for validating and processing their method @@ -594,6 +579,12 @@ payments::mojom::blink::AddressErrors::From( input->shippingAddressErrors()); } + + if (input->hasPaymentMethodErrors()) { + PaymentsValidators::ValidateAndStringifyObject( + "Payment method errors", input->paymentMethodErrors(), + output->stringified_payment_method_errors, exception_state); + } } void ValidateAndConvertPaymentMethodData(
diff --git a/third_party/blink/renderer/modules/payments/payment_request.h b/third_party/blink/renderer/modules/payments/payment_request.h index 49a5dde27..6c940b6 100644 --- a/third_party/blink/renderer/modules/payments/payment_request.h +++ b/third_party/blink/renderer/modules/payments/payment_request.h
@@ -106,10 +106,8 @@ enum { // Implementation defined constants controlling the allowed list length kMaxListSize = 1024, - // ... and string length + // ... and string length. kMaxStringLength = 1024, - // ... and JSON length. - kMaxJSONStringLength = 1048576 }; private:
diff --git a/third_party/blink/renderer/modules/payments/payment_request_event.cc b/third_party/blink/renderer/modules/payments/payment_request_event.cc index a180bedc..8eaf020 100644 --- a/third_party/blink/renderer/modules/payments/payment_request_event.cc +++ b/third_party/blink/renderer/modules/payments/payment_request_event.cc
@@ -7,10 +7,14 @@ #include <memory> #include <utility> +#include "third_party/blink/public/platform/interface_provider.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h" #include "third_party/blink/renderer/core/dom/dom_exception.h" #include "third_party/blink/renderer/core/workers/worker_global_scope.h" #include "third_party/blink/renderer/core/workers/worker_location.h" +#include "third_party/blink/renderer/modules/payments/payment_method_change_response.h" +#include "third_party/blink/renderer/modules/payments/payments_validators.h" #include "third_party/blink/renderer/modules/service_worker/respond_with_observer.h" #include "third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.h" #include "third_party/blink/renderer/platform/bindings/script_state.h" @@ -21,17 +25,48 @@ PaymentRequestEvent* PaymentRequestEvent::Create( const AtomicString& type, const PaymentRequestEventInit* initializer) { - return MakeGarbageCollected<PaymentRequestEvent>(type, initializer, nullptr, - nullptr); + return MakeGarbageCollected<PaymentRequestEvent>( + type, initializer, payments::mojom::blink::PaymentHandlerHostPtrInfo(), + nullptr, nullptr); } PaymentRequestEvent* PaymentRequestEvent::Create( const AtomicString& type, const PaymentRequestEventInit* initializer, + payments::mojom::blink::PaymentHandlerHostPtrInfo host_info, RespondWithObserver* respond_with_observer, WaitUntilObserver* wait_until_observer) { return MakeGarbageCollected<PaymentRequestEvent>( - type, initializer, respond_with_observer, wait_until_observer); + type, initializer, std::move(host_info), respond_with_observer, + wait_until_observer); +} + +PaymentRequestEvent::PaymentRequestEvent( + const AtomicString& type, + const PaymentRequestEventInit* initializer, + payments::mojom::blink::PaymentHandlerHostPtrInfo host_info, + RespondWithObserver* respond_with_observer, + WaitUntilObserver* wait_until_observer) + : ExtendableEvent(type, initializer, wait_until_observer), + top_origin_(initializer->topOrigin()), + payment_request_origin_(initializer->paymentRequestOrigin()), + payment_request_id_(initializer->paymentRequestId()), + method_data_(initializer->hasMethodData() + ? initializer->methodData() + : HeapVector<Member<PaymentMethodData>>()), + total_(initializer->hasTotal() ? initializer->total() + : PaymentCurrencyAmount::Create()), + modifiers_(initializer->hasModifiers() + ? initializer->modifiers() + : HeapVector<Member<PaymentDetailsModifier>>()), + instrument_key_(initializer->instrumentKey()), + observer_(respond_with_observer) { + if (!host_info.is_valid()) + return; + + payment_handler_host_.Bind(std::move(host_info)); + payment_handler_host_.set_connection_error_handler(WTF::Bind( + &PaymentRequestEvent::OnHostConnectionError, WrapWeakPersistent(this))); } PaymentRequestEvent::~PaymentRequestEvent() = default; @@ -109,6 +144,53 @@ return promise; } +ScriptPromise PaymentRequestEvent::changePaymentMethod( + ScriptState* script_state, + const String& method_name, + ExceptionState& exception_state) { + return changePaymentMethod(script_state, method_name, ScriptValue(), + exception_state); +} + +ScriptPromise PaymentRequestEvent::changePaymentMethod( + ScriptState* script_state, + const String& method_name, + const ScriptValue& method_details, + ExceptionState& exception_state) { + if (change_payment_method_resolver_) { + return ScriptPromise::RejectWithDOMException( + script_state, + DOMException::Create( + DOMExceptionCode::kInvalidStateError, + "Waiting for response to the previous payment method change")); + } + + if (!payment_handler_host_.is_bound()) { + return ScriptPromise::RejectWithDOMException( + script_state, + DOMException::Create(DOMExceptionCode::kInvalidStateError, + "No corresponding PaymentRequest object found")); + } + + auto method_data = payments::mojom::blink::PaymentHandlerMethodData::New(); + if (!method_details.IsEmpty()) { + PaymentsValidators::ValidateAndStringifyObject( + "Method details", method_details, method_data->stringified_data, + exception_state); + if (exception_state.HadException()) + return ScriptPromise(); + } + + method_data->method_name = method_name; + payment_handler_host_->ChangePaymentMethod( + std::move(method_data), + WTF::Bind(&PaymentRequestEvent::OnChangePaymentMethodResponse, + WrapWeakPersistent(this))); + change_payment_method_resolver_ = + MakeGarbageCollected<ScriptPromiseResolver>(script_state); + return change_payment_method_resolver_->Promise(); +} + void PaymentRequestEvent::respondWith(ScriptState* script_state, ScriptPromise script_promise, ExceptionState& exception_state) { @@ -129,28 +211,100 @@ visitor->Trace(method_data_); visitor->Trace(total_); visitor->Trace(modifiers_); + visitor->Trace(change_payment_method_resolver_); visitor->Trace(observer_); ExtendableEvent::Trace(visitor); } -PaymentRequestEvent::PaymentRequestEvent( - const AtomicString& type, - const PaymentRequestEventInit* initializer, - RespondWithObserver* respond_with_observer, - WaitUntilObserver* wait_until_observer) - : ExtendableEvent(type, initializer, wait_until_observer), - top_origin_(initializer->topOrigin()), - payment_request_origin_(initializer->paymentRequestOrigin()), - payment_request_id_(initializer->paymentRequestId()), - method_data_(initializer->hasMethodData() - ? initializer->methodData() - : HeapVector<Member<PaymentMethodData>>()), - total_(initializer->hasTotal() ? initializer->total() - : PaymentCurrencyAmount::Create()), - modifiers_(initializer->hasModifiers() - ? initializer->modifiers() - : HeapVector<Member<PaymentDetailsModifier>>()), - instrument_key_(initializer->instrumentKey()), - observer_(respond_with_observer) {} +void PaymentRequestEvent::OnChangePaymentMethodResponse( + payments::mojom::blink::PaymentMethodChangeResponsePtr response) { + if (!change_payment_method_resolver_) + return; + + auto* dictionary = MakeGarbageCollected<PaymentMethodChangeResponse>(); + if (!response->error.IsNull() && !response->error.IsEmpty()) { + dictionary->setError(response->error); + } + + if (response->total) { + auto* total = MakeGarbageCollected<PaymentCurrencyAmount>(); + total->setCurrency(response->total->currency); + total->setValue(response->total->value); + dictionary->setTotal(total); + } + + ScriptState* script_state = change_payment_method_resolver_->GetScriptState(); + ScriptState::Scope scope(script_state); + ExceptionState exception_state(script_state->GetIsolate(), + ExceptionState::kConstructionContext, + "PaymentDetailsModifier"); + + if (response->modifiers) { + auto* modifiers = + MakeGarbageCollected<HeapVector<Member<PaymentDetailsModifier>>>(); + for (const auto& response_modifier : *response->modifiers) { + if (!response_modifier) + continue; + + auto* mod = MakeGarbageCollected<PaymentDetailsModifier>(); + mod->setSupportedMethod(response_modifier->method_data->method_name); + + if (response_modifier->total) { + auto* amount = MakeGarbageCollected<PaymentCurrencyAmount>(); + amount->setCurrency(response_modifier->total->currency); + amount->setValue(response_modifier->total->value); + auto* total = MakeGarbageCollected<PaymentItem>(); + total->setAmount(amount); + total->setLabel(""); + mod->setTotal(total); + } + + if (!response_modifier->method_data->stringified_data.IsEmpty()) { + v8::Local<v8::Value> parsed_value = FromJSONString( + script_state->GetIsolate(), script_state->GetContext(), + response_modifier->method_data->stringified_data, exception_state); + if (exception_state.HadException()) { + change_payment_method_resolver_->Reject(DOMException::Create( + DOMExceptionCode::kSyntaxError, exception_state.Message())); + change_payment_method_resolver_.Clear(); + return; + } + mod->setData(ScriptValue(script_state, parsed_value)); + modifiers->emplace_back(mod); + } + } + dictionary->setModifiers(*modifiers); + } + + if (response->stringified_payment_method_errors && + !response->stringified_payment_method_errors.IsEmpty()) { + v8::Local<v8::Value> parsed_value = FromJSONString( + script_state->GetIsolate(), script_state->GetContext(), + response->stringified_payment_method_errors, exception_state); + if (exception_state.HadException()) { + change_payment_method_resolver_->Reject(DOMException::Create( + DOMExceptionCode::kSyntaxError, exception_state.Message())); + change_payment_method_resolver_.Clear(); + return; + } + dictionary->setPaymentMethodErrors(ScriptValue(script_state, parsed_value)); + } + + change_payment_method_resolver_->Resolve( + dictionary->hasError() || dictionary->hasTotal() || + dictionary->hasModifiers() || dictionary->hasPaymentMethodErrors() + ? dictionary + : nullptr); + change_payment_method_resolver_.Clear(); +} + +void PaymentRequestEvent::OnHostConnectionError() { + if (change_payment_method_resolver_) { + change_payment_method_resolver_->Reject(DOMException::Create( + DOMExceptionCode::kAbortError, "Browser process disconnected")); + } + change_payment_method_resolver_.Clear(); + payment_handler_host_.reset(); +} } // namespace blink
diff --git a/third_party/blink/renderer/modules/payments/payment_request_event.h b/third_party/blink/renderer/modules/payments/payment_request_event.h index b9b3318f..b82cf71 100644 --- a/third_party/blink/renderer/modules/payments/payment_request_event.h +++ b/third_party/blink/renderer/modules/payments/payment_request_event.h
@@ -6,6 +6,7 @@ #define THIRD_PARTY_BLINK_RENDERER_MODULES_PAYMENTS_PAYMENT_REQUEST_EVENT_H_ #include "base/macros.h" +#include "third_party/blink/public/mojom/payments/payment_handler_host.mojom-blink.h" #include "third_party/blink/renderer/bindings/core/v8/script_value.h" #include "third_party/blink/renderer/modules/event_modules.h" #include "third_party/blink/renderer/modules/payments/payment_request_event_init.h" @@ -19,7 +20,9 @@ namespace blink { class RespondWithObserver; +class ScriptPromiseResolver; class ScriptState; +class ScriptValue; class MODULES_EXPORT PaymentRequestEvent final : public ExtendableEvent { DEFINE_WRAPPERTYPEINFO(); @@ -27,15 +30,19 @@ public: static PaymentRequestEvent* Create(const AtomicString& type, const PaymentRequestEventInit*); - static PaymentRequestEvent* Create(const AtomicString& type, - const PaymentRequestEventInit*, - RespondWithObserver*, - WaitUntilObserver*); + static PaymentRequestEvent* Create( + const AtomicString& type, + const PaymentRequestEventInit*, + payments::mojom::blink::PaymentHandlerHostPtrInfo host_info, + RespondWithObserver*, + WaitUntilObserver*); - PaymentRequestEvent(const AtomicString& type, - const PaymentRequestEventInit*, - RespondWithObserver*, - WaitUntilObserver*); + PaymentRequestEvent( + const AtomicString& type, + const PaymentRequestEventInit*, + payments::mojom::blink::PaymentHandlerHostPtrInfo host_info, + RespondWithObserver*, + WaitUntilObserver*); ~PaymentRequestEvent() override; const AtomicString& InterfaceName() const override; @@ -49,11 +56,22 @@ const String& instrumentKey() const; ScriptPromise openWindow(ScriptState*, const String& url); + ScriptPromise changePaymentMethod(ScriptState*, + const String& method_name, + ExceptionState& exception_state); + ScriptPromise changePaymentMethod(ScriptState*, + const String& method_name, + const ScriptValue& method_details, + ExceptionState& exception_state); void respondWith(ScriptState*, ScriptPromise, ExceptionState&); void Trace(blink::Visitor*) override; private: + void OnChangePaymentMethodResponse( + payments::mojom::blink::PaymentMethodChangeResponsePtr); + void OnHostConnectionError(); + String top_origin_; String payment_request_origin_; String payment_request_id_; @@ -62,7 +80,9 @@ HeapVector<Member<PaymentDetailsModifier>> modifiers_; String instrument_key_; + Member<ScriptPromiseResolver> change_payment_method_resolver_; Member<RespondWithObserver> observer_; + payments::mojom::blink::PaymentHandlerHostPtr payment_handler_host_; DISALLOW_COPY_AND_ASSIGN(PaymentRequestEvent); };
diff --git a/third_party/blink/renderer/modules/payments/payment_request_event.idl b/third_party/blink/renderer/modules/payments/payment_request_event.idl index 127ab29..51d8824 100644 --- a/third_party/blink/renderer/modules/payments/payment_request_event.idl +++ b/third_party/blink/renderer/modules/payments/payment_request_event.idl
@@ -18,5 +18,6 @@ readonly attribute DOMString instrumentKey; [CallWith=ScriptState] Promise<WindowClient?> openWindow(USVString url); + [CallWith=ScriptState, RaisesException, RuntimeEnabled=PaymentHandlerChangePaymentMethod] Promise<PaymentMethodChangeResponse?> changePaymentMethod(DOMString methodName, optional object? methodDetails = null); [CallWith=ScriptState, RaisesException] void respondWith(Promise<PaymentResponse> response); };
diff --git a/third_party/blink/renderer/modules/payments/payments_validators.cc b/third_party/blink/renderer/modules/payments/payments_validators.cc index 4a2b44a..434cdb1 100644 --- a/third_party/blink/renderer/modules/payments/payments_validators.cc +++ b/third_party/blink/renderer/modules/payments/payments_validators.cc
@@ -5,17 +5,22 @@ #include "third_party/blink/renderer/modules/payments/payments_validators.h" #include "third_party/blink/renderer/bindings/core/v8/script_regexp.h" +#include "third_party/blink/renderer/bindings/core/v8/script_value.h" #include "third_party/blink/renderer/modules/payments/address_errors.h" #include "third_party/blink/renderer/modules/payments/payer_errors.h" #include "third_party/blink/renderer/modules/payments/payment_validation_errors.h" +#include "third_party/blink/renderer/platform/bindings/exception_state.h" +#include "third_party/blink/renderer/platform/bindings/string_resource.h" #include "third_party/blink/renderer/platform/weborigin/kurl.h" #include "third_party/blink/renderer/platform/weborigin/security_origin.h" #include "third_party/blink/renderer/platform/wtf/text/string_impl.h" +#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" namespace blink { -// We limit the maximum length of string to 2048 bytes for security reasons. -static const int kMaxiumStringLength = 2048; +// Passing a giant string through IPC to the browser can cause a crash due to +// failure in memory allocation. This number here is chosen conservatively. +static constexpr size_t kMaximumStringLength = 2 * 1024; bool PaymentsValidators::IsValidCurrencyCodeFormat( const String& code, @@ -69,12 +74,14 @@ bool PaymentsValidators::IsValidErrorMsgFormat(const String& error, String* optional_error_message) { - if (error.length() <= kMaxiumStringLength) + if (error.length() <= kMaximumStringLength) return true; - if (optional_error_message) + if (optional_error_message) { *optional_error_message = - "Error message should be at most 2048 characters long"; + String::Format("Error message should be at most %zu characters long", + kMaximumStringLength); + } return false; } @@ -154,4 +161,30 @@ } } +void PaymentsValidators::ValidateAndStringifyObject( + const String& input_name, + const ScriptValue& input, + String& output, + ExceptionState& exception_state) { + v8::Local<v8::String> value; + if (input.IsEmpty() || !input.V8Value()->IsObject() || + !v8::JSON::Stringify(input.GetContext(), input.V8Value().As<v8::Object>()) + .ToLocal(&value)) { + exception_state.ThrowTypeError(input_name + + " should be a JSON-serializable object"); + return; + } + + output = ToBlinkString<String>(value, kDoNotExternalize); + + // Implementation defined constant controlling the allowed JSON length. + static constexpr size_t kMaxJSONStringLength = 1024 * 1024; + + if (output.length() > kMaxJSONStringLength) { + exception_state.ThrowTypeError(String::Format( + "JSON serialization of %s should be no longer than %zu characters", + input_name.Characters8(), kMaxJSONStringLength)); + } +} + } // namespace blink
diff --git a/third_party/blink/renderer/modules/payments/payments_validators.h b/third_party/blink/renderer/modules/payments/payments_validators.h index bc935751..a47ae15 100644 --- a/third_party/blink/renderer/modules/payments/payments_validators.h +++ b/third_party/blink/renderer/modules/payments/payments_validators.h
@@ -13,8 +13,10 @@ namespace blink { class AddressErrors; +class ExceptionState; class PayerErrors; class PaymentValidationErrors; +class ScriptValue; class MODULES_EXPORT PaymentsValidators final { STATIC_ONLY(PaymentsValidators); @@ -25,8 +27,8 @@ static bool IsValidCurrencyCodeFormat(const String& code, String* optional_error_message); - // Returns true if |amount| is a valid currency code as defined in ISO 20022 - // CurrencyAnd30Amount. + // Returns true if |amount| is a valid currency code as defined in + // PaymentRequest standard. static bool IsValidAmountFormat(const String& amount, const String& item_name, String* optional_error_message); @@ -41,19 +43,19 @@ const payments::mojom::blink::PaymentAddressPtr&, String* optional_error_message); - // Returns false if |error| is too long (greater than 2048). + // Returns false if |error| is too long. static bool IsValidErrorMsgFormat(const String& code, String* optional_error_message); - // Returns false if |errors| has too long string (greater than 2048). + // Returns false if |errors| has too long string. static bool IsValidAddressErrorsFormat(const AddressErrors* errors, String* optional_error_message); - // Returns false if |errors| has too long string (greater than 2048). + // Returns false if |errors| has too long string. static bool IsValidPayerErrorsFormat(const PayerErrors* errors, String* optional_error_message); - // Returns false if |errors| has too long string (greater than 2048). + // Returns false if |errors| has too long string. static bool IsValidPaymentValidationErrorsFormat( const PaymentValidationErrors* errors, String* optional_error_message); @@ -61,6 +63,18 @@ // Implements the PMI validation algorithm from: // https://www.w3.org/TR/payment-method-id/#dfn-validate-a-payment-method-identifier static bool IsValidMethodFormat(const String& identifier); + + // Validates that |input| is a JavaScript object that can be serialized into + // JSON string of a reasonable size. + // + // If the |input| is valid, the JSON serialization is saved in |output|. + // + // If the |input| is invalid, throws a TypeError through the |exception_state| + // and uses the |input_name| to better describe what was being validated. + static void ValidateAndStringifyObject(const String& input_name, + const ScriptValue& input, + String& output, + ExceptionState& exception_state); }; } // namespace blink
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_dtls_transport.cc b/third_party/blink/renderer/modules/peerconnection/rtc_dtls_transport.cc index 5c76192b..48a704c 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_dtls_transport.cc +++ b/third_party/blink/renderer/modules/peerconnection/rtc_dtls_transport.cc
@@ -80,6 +80,11 @@ return TransportStateToString(current_state_.state()); } +const HeapVector<Member<DOMArrayBuffer>>& +RTCDtlsTransport::getRemoteCertificates() const { + return remote_certificates_; +} + RTCIceTransport* RTCDtlsTransport::iceTransport() const { return ice_transport_; } @@ -110,6 +115,40 @@ // We depend on closed only happening once for safe garbage collection. DCHECK(current_state_.state() != webrtc::DtlsTransportState::kClosed); current_state_ = info; + // If the certificates have changed, copy them as DOMArrayBuffers. + // This makes sure that getRemoteCertificates() == getRemoteCertificates() + if (current_state_.remote_ssl_certificates()) { + const rtc::SSLCertChain* certs = current_state_.remote_ssl_certificates(); + if (certs->GetSize() != remote_certificates_.size()) { + remote_certificates_.clear(); + for (size_t i = 0; i < certs->GetSize(); i++) { + auto& cert = certs->Get(i); + rtc::Buffer der_cert; + cert.ToDER(&der_cert); + DOMArrayBuffer* dab_cert = DOMArrayBuffer::Create( + der_cert.data(), static_cast<unsigned int>(der_cert.size())); + remote_certificates_.push_back(dab_cert); + } + } else { + // Replace certificates that have changed, if any + for (WTF::wtf_size_t i = 0; i < certs->GetSize(); i++) { + auto& cert = certs->Get(i); + rtc::Buffer der_cert; + cert.ToDER(&der_cert); + DOMArrayBuffer* dab_cert = DOMArrayBuffer::Create( + der_cert.data(), static_cast<unsigned int>(der_cert.size())); + // Don't replace the certificate if it's unchanged. + // Should have been "if (*dab_cert != *remote_certificates_[i])" + if (dab_cert->ByteLength() != remote_certificates_[i]->ByteLength() || + memcmp(dab_cert->Data(), remote_certificates_[i]->Data(), + dab_cert->ByteLength()) != 0) { + remote_certificates_[i] = dab_cert; + } + } + } + } else { + remote_certificates_.clear(); + } if (!closed_from_owner_) { DispatchEvent(*Event::Create(event_type_names::kStatechange)); } @@ -124,6 +163,7 @@ } void RTCDtlsTransport::Trace(Visitor* visitor) { + visitor->Trace(remote_certificates_); visitor->Trace(ice_transport_); DtlsTransportProxy::Delegate::Trace(visitor); EventTargetWithInlineData::Trace(visitor);
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_dtls_transport.h b/third_party/blink/renderer/modules/peerconnection/rtc_dtls_transport.h index 20d85e7..04424f83 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_dtls_transport.h +++ b/third_party/blink/renderer/modules/peerconnection/rtc_dtls_transport.h
@@ -15,6 +15,7 @@ namespace blink { class DtlsTransportProxy; +class DOMArrayBuffer; class RTCIceTransport; enum class RTCDtlsTransportState { @@ -46,6 +47,7 @@ // rtc_dtls_transport.idl RTCIceTransport* iceTransport() const; String state() const; + const HeapVector<Member<DOMArrayBuffer>>& getRemoteCertificates() const; DEFINE_ATTRIBUTE_EVENT_LISTENER(statechange, kStatechange) DEFINE_ATTRIBUTE_EVENT_LISTENER(error, kError) @@ -66,6 +68,7 @@ private: webrtc::DtlsTransportInformation current_state_; + HeapVector<Member<DOMArrayBuffer>> remote_certificates_; rtc::scoped_refptr<webrtc::DtlsTransportInterface> native_transport_; std::unique_ptr<DtlsTransportProxy> proxy_; Member<RTCIceTransport> ice_transport_;
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_dtls_transport.idl b/third_party/blink/renderer/modules/peerconnection/rtc_dtls_transport.idl index b7b9e42..c514ca9 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_dtls_transport.idl +++ b/third_party/blink/renderer/modules/peerconnection/rtc_dtls_transport.idl
@@ -18,8 +18,7 @@ ] interface RTCDtlsTransport : EventTarget { readonly attribute RTCIceTransport iceTransport; readonly attribute RTCDtlsTransportState state; - // TODO(https://crbug.com/943972): Implement getRemoteCertificates(). - // sequence<ArrayBuffer> getRemoteCertificates(); + sequence<ArrayBuffer> getRemoteCertificates(); attribute EventHandler onstatechange; attribute EventHandler onerror; };
diff --git a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_test.cc b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_test.cc index 629874a27..1ea4de8 100644 --- a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_test.cc +++ b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_test.cc
@@ -14,6 +14,7 @@ #include "third_party/blink/renderer/core/html/media/html_video_element.h" #include "third_party/blink/renderer/core/testing/page_test_base.h" #include "third_party/blink/renderer/core/testing/wait_for_event.h" +#include "third_party/blink/renderer/platform/heap/heap.h" #include "third_party/blink/renderer/platform/testing/empty_web_media_player.h" #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h" @@ -128,7 +129,7 @@ WTF::BindRepeating(&MockPictureInPictureService::Bind, WTF::Unretained(&mock_service_))); - video_ = HTMLVideoElement::Create(GetDocument()); + video_ = MakeGarbageCollected<HTMLVideoElement>(GetDocument()); video_->SetReadyState(HTMLMediaElement::ReadyState::kHaveMetadata); layer_ = cc::Layer::Create(); video_->SetCcLayerForTesting(layer_.get());
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc index 19ca042..e6a6b107 100644 --- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc +++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc
@@ -36,9 +36,11 @@ #include "base/memory/ptr_util.h" #include "base/trace_event/trace_event.h" #include "third_party/blink/public/mojom/notifications/notification.mojom-blink.h" +#include "third_party/blink/public/mojom/payments/payment_handler_host.mojom-blink.h" #include "third_party/blink/public/mojom/service_worker/service_worker_client.mojom-blink.h" #include "third_party/blink/public/mojom/service_worker/service_worker_event_status.mojom-blink.h" #include "third_party/blink/public/platform/modules/notifications/web_notification_data.h" +#include "third_party/blink/public/platform/modules/payments/web_payment_request_event_data.h" #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_error.h" #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_request.h" #include "third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h" @@ -566,19 +568,21 @@ void ServiceWorkerGlobalScopeProxy::DispatchPaymentRequestEvent( int event_id, - const WebPaymentRequestEventData& web_app_request) { + std::unique_ptr<WebPaymentRequestEventData> web_app_request) { DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_); WaitUntilObserver* wait_until_observer = WaitUntilObserver::Create( WorkerGlobalScope(), WaitUntilObserver::kPaymentRequest, event_id); PaymentRequestRespondWithObserver* respond_with_observer = PaymentRequestRespondWithObserver::Create(WorkerGlobalScope(), event_id, wait_until_observer); - Event* event = PaymentRequestEvent::Create( event_type_names::kPaymentrequest, PaymentEventDataConversion::ToPaymentRequestEventInit( WorkerGlobalScope()->ScriptController()->GetScriptState(), - web_app_request), + *web_app_request), + payments::mojom::blink::PaymentHandlerHostPtrInfo( + std::move(web_app_request->payment_handler_host_handle), + payments::mojom::blink::PaymentHandlerHost::Version_), respond_with_observer, wait_until_observer); WorkerGlobalScope()->DispatchExtendableEventWithRespondWith(
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h index 6eab31f..ae29495 100644 --- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h +++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h
@@ -129,8 +129,9 @@ void DispatchAbortPaymentEvent(int) override; void DispatchCanMakePaymentEvent(int, const WebCanMakePaymentEventData&) override; - void DispatchPaymentRequestEvent(int, - const WebPaymentRequestEventData&) override; + void DispatchPaymentRequestEvent( + int, + std::unique_ptr<WebPaymentRequestEventData>) override; bool HasFetchEventHandler() override; void OnNavigationPreloadResponse( int fetch_event_id,
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index 8b2388a..5742a1f9 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -660,7 +660,7 @@ }, { name: "IDBTransactionCommit", - status: "experimental", + status: "stable", }, { name: "IdleDetection", @@ -1058,6 +1058,10 @@ status: "experimental", }, { + name: "PaymentHandlerChangePaymentMethod", + status: "experimental", + }, + { name: "PaymentMethodChangeEvent", status: "experimental", },
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index f530ed60..956147e5 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -253,6 +253,7 @@ crbug.com/907601 virtual/fractional_scrolling/fast/scrolling/events/scrollend-event-fired-after-snap.html [ Skip ] crbug.com/907601 virtual/fractional_scrolling_threaded/fast/scrolling/events/scrollend-event-fired-after-snap.html [ Skip ] crbug.com/907601 virtual/scroll_customization/fast/scrolling/events/scrollend-event-fired-after-snap.html [ Skip ] +crbug.com/907601 external/wpt/dom/events/scrolling/scrollend-event-fired-after-snap.html [ Skip ] # Tests not yet passing with Blink FractionalScrollOffsets enabled. crbug.com/414283 virtual/fractional_scrolling/fast/scrolling/fractional-scroll-offset-fixed-position-non-composited.html [ Failure ] @@ -6170,7 +6171,7 @@ crbug.com/953591 [ Win ] css3/masking/mask-repeat-space-padding.html [ Pass Failure ] crbug.com/953591 [ Win ] fast/forms/datalist/input-appearance-range-with-transform.html [ Pass Failure ] crbug.com/953591 [ Win ] transforms/matrix-02.html [ Pass Failure ] -crbug.com/938884 [ Win7 ] http/tests/devtools/elements/styles-3/styles-add-blank-property.js [ Timeout Pass ] +crbug.com/938884 http/tests/devtools/elements/styles-3/styles-add-blank-property.js [ Timeout Pass ] # Sheriff 2019-04-18 crbug.com/954297 [ Linux Win ] http/tests/devtools/oopif/oopif-presentation-console-messages.js [ Pass Crash Timeout ] @@ -6201,3 +6202,12 @@ crbug.com/959168 external/wpt/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch.html [ Timeout Pass ] crbug.com/959168 external/wpt/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch.html [ Timeout Pass ] crbug.com/959168 external/wpt/pointerevents/pointerevent_touch-action-inherit_parent-none_touch.html [ Timeout Pass ] + +# Sheriff 2019-05-06 +crbug.com/959002 crbug.com/959042 http/tests/devtools/elements/styles-1/color-aware-property-value-edit.js [ Pass Timeout ] +crbug.com/959002 crbug.com/959042 http/tests/devtools/elements/styles-1/edit-resource-referred-by-multiple-styletags.js [ Pass Timeout ] +crbug.com/959002 crbug.com/959042 http/tests/devtools/elements/styles-3/style-autocomplete.js [ Pass Timeout ] +crbug.com/959002 crbug.com/959042 http/tests/devtools/elements/styles-3/styles-variables.js [ Pass Timeout ] +crbug.com/959002 crbug.com/959042 http/tests/devtools/elements/styles-4/styles-keyframes.js [ Pass Timeout ] +crbug.com/959002 crbug.com/959042 http/tests/devtools/elements/styles-4/undo-add-new-rule.js [ Pass Timeout ] +
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json index 77f8217..6ace4f8 100644 --- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json +++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
@@ -6391,12 +6391,6 @@ {} ] ], - "pointerevents/extension/pointerevent_getCoalescedEvents_when_pointerlocked-manual.html": [ - [ - "pointerevents/extension/pointerevent_getCoalescedEvents_when_pointerlocked-manual.html", - {} - ] - ], "pointerevents/extension/pointerevent_getPredictedEvents_when_pointerlocked-manual.html": [ [ "pointerevents/extension/pointerevent_getPredictedEvents_when_pointerlocked-manual.html", @@ -6457,12 +6451,6 @@ {} ] ], - "pointerevents/pointerevent_boundary_events_in_capturing-manual.html": [ - [ - "pointerevents/pointerevent_boundary_events_in_capturing-manual.html", - {} - ] - ], "pointerevents/pointerevent_capture_suppressing_mouse-manual.html": [ [ "pointerevents/pointerevent_capture_suppressing_mouse-manual.html", @@ -6493,24 +6481,12 @@ {} ] ], - "pointerevents/pointerevent_releasepointercapture_events_to_original_target-manual.html": [ - [ - "pointerevents/pointerevent_releasepointercapture_events_to_original_target-manual.html", - {} - ] - ], "pointerevents/pointerevent_sequence_at_implicit_release_on_click-manual.html": [ [ "pointerevents/pointerevent_sequence_at_implicit_release_on_click-manual.html", {} ] ], - "pointerevents/pointerevent_sequence_at_implicit_release_on_drag-manual.html": [ - [ - "pointerevents/pointerevent_sequence_at_implicit_release_on_drag-manual.html", - {} - ] - ], "pointerevents/pointerevent_touch-action-button-test_touch-manual.html": [ [ "pointerevents/pointerevent_touch-action-button-test_touch-manual.html", @@ -6559,12 +6535,6 @@ {} ] ], - "pointerevents/pointerlock/pointerevent_movementxy_when_locked-manual.html": [ - [ - "pointerevents/pointerlock/pointerevent_movementxy_when_locked-manual.html", - {} - ] - ], "pointerevents/pointerlock/pointerevent_pointerlock_after_pointercapture-manual.html": [ [ "pointerevents/pointerlock/pointerevent_pointerlock_after_pointercapture-manual.html", @@ -131038,6 +131008,11 @@ {} ] ], + "css/css-backgrounds/inheritance-expected.txt": [ + [ + {} + ] + ], "css/css-backgrounds/justfortest.html": [ [ {} @@ -131813,11 +131788,6 @@ {} ] ], - "css/css-break/page-break-legacy-shorthands-expected.txt": [ - [ - {} - ] - ], "css/css-break/parsing/box-decoration-break-valid-expected.txt": [ [ {} @@ -146748,6 +146718,36 @@ {} ] ], + "css/css-sizing/parsing/height-valid-expected.txt": [ + [ + {} + ] + ], + "css/css-sizing/parsing/max-height-valid-expected.txt": [ + [ + {} + ] + ], + "css/css-sizing/parsing/max-width-valid-expected.txt": [ + [ + {} + ] + ], + "css/css-sizing/parsing/min-height-valid-expected.txt": [ + [ + {} + ] + ], + "css/css-sizing/parsing/min-width-valid-expected.txt": [ + [ + {} + ] + ], + "css/css-sizing/parsing/width-valid-expected.txt": [ + [ + {} + ] + ], "css/css-sizing/range-percent-intrinsic-size-1-ref.html": [ [ {} @@ -200108,6 +200108,11 @@ {} ] ], + "wake-lock/wakelock-disabled-by-feature-policy.https.sub-expected.txt": [ + [ + {} + ] + ], "wake-lock/wakelock-disabled-by-feature-policy.https.sub.html.headers": [ [ {} @@ -200118,11 +200123,26 @@ {} ] ], + "wake-lock/wakelock-enabled-by-feature-policy-attribute-redirect-on-load.https.sub-expected.txt": [ + [ + {} + ] + ], + "wake-lock/wakelock-enabled-by-feature-policy.https.sub-expected.txt": [ + [ + {} + ] + ], "wake-lock/wakelock-enabled-by-feature-policy.https.sub.html.headers": [ [ {} ] ], + "wake-lock/wakelock-enabled-on-self-origin-by-feature-policy.https.sub-expected.txt": [ + [ + {} + ] + ], "wake-lock/wakelock-enabled-on-self-origin-by-feature-policy.https.sub.html.headers": [ [ {} @@ -201813,11 +201833,6 @@ {} ] ], - "webrtc/RTCDtlsTransport-getRemoteCertificates-expected.txt": [ - [ - {} - ] - ], "webrtc/RTCIceTransport-expected.txt": [ [ {} @@ -228059,6 +228074,12 @@ {} ] ], + "css/css-backgrounds/inheritance.html": [ + [ + "css/css-backgrounds/inheritance.html", + {} + ] + ], "css/css-backgrounds/parsing/background-attachment-invalid.html": [ [ "css/css-backgrounds/parsing/background-attachment-invalid.html", @@ -232919,6 +232940,12 @@ {} ] ], + "css/css-rhythm/inheritance.html": [ + [ + "css/css-rhythm/inheritance.html", + {} + ] + ], "css/css-rhythm/line-height-step-dynamic-001.html": [ [ "css/css-rhythm/line-height-step-dynamic-001.html", @@ -233405,6 +233432,12 @@ {} ] ], + "css/css-scrollbars/inheritance.html": [ + [ + "css/css-scrollbars/inheritance.html", + {} + ] + ], "css/css-scrollbars/scrollbar-width-keywords.html": [ [ "css/css-scrollbars/scrollbar-width-keywords.html", @@ -234179,6 +234212,102 @@ {} ] ], + "css/css-sizing/inheritance.html": [ + [ + "css/css-sizing/inheritance.html", + {} + ] + ], + "css/css-sizing/parsing/box-sizing-computed.html": [ + [ + "css/css-sizing/parsing/box-sizing-computed.html", + {} + ] + ], + "css/css-sizing/parsing/box-sizing-invalid.html": [ + [ + "css/css-sizing/parsing/box-sizing-invalid.html", + {} + ] + ], + "css/css-sizing/parsing/box-sizing-valid.html": [ + [ + "css/css-sizing/parsing/box-sizing-valid.html", + {} + ] + ], + "css/css-sizing/parsing/height-invalid.html": [ + [ + "css/css-sizing/parsing/height-invalid.html", + {} + ] + ], + "css/css-sizing/parsing/height-valid.html": [ + [ + "css/css-sizing/parsing/height-valid.html", + {} + ] + ], + "css/css-sizing/parsing/max-height-invalid.html": [ + [ + "css/css-sizing/parsing/max-height-invalid.html", + {} + ] + ], + "css/css-sizing/parsing/max-height-valid.html": [ + [ + "css/css-sizing/parsing/max-height-valid.html", + {} + ] + ], + "css/css-sizing/parsing/max-width-invalid.html": [ + [ + "css/css-sizing/parsing/max-width-invalid.html", + {} + ] + ], + "css/css-sizing/parsing/max-width-valid.html": [ + [ + "css/css-sizing/parsing/max-width-valid.html", + {} + ] + ], + "css/css-sizing/parsing/min-height-invalid.html": [ + [ + "css/css-sizing/parsing/min-height-invalid.html", + {} + ] + ], + "css/css-sizing/parsing/min-height-valid.html": [ + [ + "css/css-sizing/parsing/min-height-valid.html", + {} + ] + ], + "css/css-sizing/parsing/min-width-invalid.html": [ + [ + "css/css-sizing/parsing/min-width-invalid.html", + {} + ] + ], + "css/css-sizing/parsing/min-width-valid.html": [ + [ + "css/css-sizing/parsing/min-width-valid.html", + {} + ] + ], + "css/css-sizing/parsing/width-invalid.html": [ + [ + "css/css-sizing/parsing/width-invalid.html", + {} + ] + ], + "css/css-sizing/parsing/width-valid.html": [ + [ + "css/css-sizing/parsing/width-valid.html", + {} + ] + ], "css/css-sizing/percentage-height-in-flexbox.html": [ [ "css/css-sizing/percentage-height-in-flexbox.html", @@ -245578,6 +245707,12 @@ {} ] ], + "element-timing/invisible-images.html": [ + [ + "element-timing/invisible-images.html", + {} + ] + ], "element-timing/multiple-background-images.html": [ [ "element-timing/multiple-background-images.html", @@ -290246,6 +290381,14 @@ {} ] ], + "pointerevents/extension/pointerevent_getCoalescedEvents_when_pointerlocked.html": [ + [ + "pointerevents/extension/pointerevent_getCoalescedEvents_when_pointerlocked.html", + { + "testdriver": true + } + ] + ], "pointerevents/extension/pointerevent_pointerrawupdate.html": [ [ "pointerevents/extension/pointerevent_pointerrawupdate.html", @@ -290285,6 +290428,14 @@ } ] ], + "pointerevents/pointerevent_boundary_events_in_capturing.html": [ + [ + "pointerevents/pointerevent_boundary_events_in_capturing.html", + { + "testdriver": true + } + ] + ], "pointerevents/pointerevent_capture_mouse.html": [ [ "pointerevents/pointerevent_capture_mouse.html", @@ -290458,6 +290609,14 @@ } ] ], + "pointerevents/pointerevent_releasepointercapture_events_to_original_target.html": [ + [ + "pointerevents/pointerevent_releasepointercapture_events_to_original_target.html", + { + "testdriver": true + } + ] + ], "pointerevents/pointerevent_releasepointercapture_invalid_pointerid.html": [ [ "pointerevents/pointerevent_releasepointercapture_invalid_pointerid.html", @@ -290495,6 +290654,14 @@ {} ] ], + "pointerevents/pointerevent_sequence_at_implicit_release_on_drag.html": [ + [ + "pointerevents/pointerevent_sequence_at_implicit_release_on_drag.html", + { + "testdriver": true + } + ] + ], "pointerevents/pointerevent_setpointercapture_disconnected.html": [ [ "pointerevents/pointerevent_setpointercapture_disconnected.html", @@ -290660,6 +290827,14 @@ } ] ], + "pointerevents/pointerlock/pointerevent_movementxy_when_locked.html": [ + [ + "pointerevents/pointerlock/pointerevent_movementxy_when_locked.html", + { + "testdriver": true + } + ] + ], "pointerlock/constructor.html": [ [ "pointerlock/constructor.html", @@ -368871,6 +369046,14 @@ "842832c01bac0c0643395ed3387d7263ec4dbf0f", "reftest" ], + "css/css-backgrounds/inheritance-expected.txt": [ + "fabdb48c4298030a4fe93f6e5d7597e88a0bcb00", + "support" + ], + "css/css-backgrounds/inheritance.html": [ + "768b18a6284e8857636c37f880a59641c8b9ed99", + "testharness" + ], "css/css-backgrounds/justfortest.html": [ "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", "support" @@ -369855,10 +370038,6 @@ "d3a4018cd809fc09eb68c1b25f4dda4736e64131", "reftest" ], - "css/css-break/page-break-legacy-shorthands-expected.txt": [ - "4cfbd726dbe2b72dd1f5e2a657cedb4f6a6defca", - "support" - ], "css/css-break/page-break-legacy-shorthands.html": [ "7eaa18f5435e87362e85bc0963c512cdf3904c9a", "testharness" @@ -392095,6 +392274,10 @@ "b1e355e6cc0f39c5685bb37753a43bac1477d9c8", "support" ], + "css/css-rhythm/inheritance.html": [ + "d47bfcb1fbdc983acb96b44cda8566165d1b7dd6", + "testharness" + ], "css/css-rhythm/line-height-step-basic-001.html": [ "19727e30ae71afcf2b32d96161f761f662bf6d28", "reftest" @@ -392871,6 +393054,10 @@ "107938ece14d394e42a5b0d8f3d99d63bf61271e", "testharness" ], + "css/css-scrollbars/inheritance.html": [ + "1a630786b490e4f872a36bd66f8dfaa763f968f9", + "testharness" + ], "css/css-scrollbars/scrollbar-width-keywords-expected.txt": [ "e5de544a83462b3172f13279fb6e1e5f18708886", "support" @@ -394411,6 +394598,10 @@ "5b1713975eb21e96a558933f81412a7bb0007d19", "reftest" ], + "css/css-sizing/inheritance.html": [ + "367ad0201daa5a307f8e87432c49f9719fa80191", + "testharness" + ], "css/css-sizing/intrinsic-percent-non-replaced-001-ref.html": [ "0b217dd192c0644ba30ec2ceb290689b99ff9193", "support" @@ -394475,6 +394666,90 @@ "fa95069dbf0083b0dc7095d2bb3acf20a6ccf898", "reftest" ], + "css/css-sizing/parsing/box-sizing-computed.html": [ + "ad5d1a7f1690f2edddc66ec816c4fd018fadc659", + "testharness" + ], + "css/css-sizing/parsing/box-sizing-invalid.html": [ + "02d57797eac70caf1d7c1c5186079cf2ca902de9", + "testharness" + ], + "css/css-sizing/parsing/box-sizing-valid.html": [ + "8f0b8099cf569edc74863dd180c904472b01f8ea", + "testharness" + ], + "css/css-sizing/parsing/height-invalid.html": [ + "14dd0b9b7192fd9fe9141b853d8727fa2f57fff6", + "testharness" + ], + "css/css-sizing/parsing/height-valid-expected.txt": [ + "4c06052738a124d338fd113af465ea13fb263975", + "support" + ], + "css/css-sizing/parsing/height-valid.html": [ + "204cd645ec4ca0d1ae7d0fb29b1ff4e2bf8d1211", + "testharness" + ], + "css/css-sizing/parsing/max-height-invalid.html": [ + "3798bb31c52b64dfc18247e4d89da44a024ab42d", + "testharness" + ], + "css/css-sizing/parsing/max-height-valid-expected.txt": [ + "514956df4fd8fdf9931f103ff4f7636cf56c6a38", + "support" + ], + "css/css-sizing/parsing/max-height-valid.html": [ + "3c4aab833f173fb9d33b704baa0e16c1842bd833", + "testharness" + ], + "css/css-sizing/parsing/max-width-invalid.html": [ + "86e852833819e2c58e84cb15680e37e989e9f626", + "testharness" + ], + "css/css-sizing/parsing/max-width-valid-expected.txt": [ + "bcc2dad38cc8996b9ddea155c7e3f2834f57caf0", + "support" + ], + "css/css-sizing/parsing/max-width-valid.html": [ + "4788ccfe6631105e8745b89317298976b1f54557", + "testharness" + ], + "css/css-sizing/parsing/min-height-invalid.html": [ + "0bb939b12be245758dde7ce93e1edab8a19fa0df", + "testharness" + ], + "css/css-sizing/parsing/min-height-valid-expected.txt": [ + "d7107b7e20ea642023a2913c40a5558df5ac42ac", + "support" + ], + "css/css-sizing/parsing/min-height-valid.html": [ + "debefbe0b82748d3665c0e82566ebea78d0271b0", + "testharness" + ], + "css/css-sizing/parsing/min-width-invalid.html": [ + "b4e600900dbb8c722567570caa3629c7c5811461", + "testharness" + ], + "css/css-sizing/parsing/min-width-valid-expected.txt": [ + "6d49931c294cb851c434b1368b43545a9fe5b833", + "support" + ], + "css/css-sizing/parsing/min-width-valid.html": [ + "cbbd19c97f73101f38501177772ae6e9e8248504", + "testharness" + ], + "css/css-sizing/parsing/width-invalid.html": [ + "6c56d2816008c5d5c4c4071aaf3cfb172fd6ad93", + "testharness" + ], + "css/css-sizing/parsing/width-valid-expected.txt": [ + "f732208241178e8ba8fc824e8a7ded6a0d99d9ea", + "support" + ], + "css/css-sizing/parsing/width-valid.html": [ + "f6c5c0ac66eb2a86179dfe7fbc80a596dd8fe27b", + "testharness" + ], "css/css-sizing/percentage-height-in-flexbox.html": [ "f5d9d528a15b4ed445808ebd74de2c3814cb5ee1", "testharness" @@ -432743,6 +433018,10 @@ "fbb2d6a12cd39e9bcd96a610e87076d9d3d6f2d4", "testharness" ], + "element-timing/invisible-images.html": [ + "50aa6d13a9a5bfc006305276011050c153fcf8b2", + "testharness" + ], "element-timing/multiple-background-images.html": [ "f3fbe767303f91328a892686a6d0d5761b1b3575", "testharness" @@ -436236,7 +436515,7 @@ "support" ], "feature-policy/resources/feature-policy-wakelock.html": [ - "3acc34767df16b2a2c80e446dbb646c278de6db9", + "292e8a1c036b872cc75fa02cba96009a2f6385a5", "support" ], "feature-policy/resources/feature-policy-webvr.html": [ @@ -473655,9 +473934,9 @@ "6971dcecfdebf3a113ef4ef9c9e8bd7bdf88ea02", "testharness" ], - "pointerevents/extension/pointerevent_getCoalescedEvents_when_pointerlocked-manual.html": [ - "6efded85b4562bd960a4b5e584e68984a1ce6316", - "manual" + "pointerevents/extension/pointerevent_getCoalescedEvents_when_pointerlocked.html": [ + "b8443767524b61d305351afcbe55bb8bab668b5e", + "testharness" ], "pointerevents/extension/pointerevent_getPredictedEvents_when_pointerlocked-manual.html": [ "eaf08d675a403aaf8bbf5a39e965af39a15d9d4e", @@ -473723,9 +474002,9 @@ "e860cd082bede68aa014fe36ceff011e8227e2ad", "testharness" ], - "pointerevents/pointerevent_boundary_events_in_capturing-manual.html": [ - "0de4d55ed13ed67229cc4a6a0f77635fad815d01", - "manual" + "pointerevents/pointerevent_boundary_events_in_capturing.html": [ + "1ed26eb6dcfcd728440a0eae5ddede45fe9a8dcf", + "testharness" ], "pointerevents/pointerevent_capture_mouse.html": [ "d8d54db6ba302eff8e2df5c5fe13c209b3183a55", @@ -473835,9 +474114,9 @@ "07df04fc2046737997b70b50063825d292af90de", "testharness" ], - "pointerevents/pointerevent_releasepointercapture_events_to_original_target-manual.html": [ - "89f3d839f46d9982130d6aec3c9c0ed75862bfa4", - "manual" + "pointerevents/pointerevent_releasepointercapture_events_to_original_target.html": [ + "12e31cdb234d1bbb5cc43b436415e44b12daaef2", + "testharness" ], "pointerevents/pointerevent_releasepointercapture_invalid_pointerid.html": [ "824494551671a8a15a6aa2a73a110a65beff0086", @@ -473863,9 +474142,9 @@ "0b93c847ed216653891d00cf55b5b00e41424b50", "manual" ], - "pointerevents/pointerevent_sequence_at_implicit_release_on_drag-manual.html": [ - "982167dc5014d06c0babd3222696c8ba556d882e", - "manual" + "pointerevents/pointerevent_sequence_at_implicit_release_on_drag.html": [ + "88d5eed3ffe6baf80ba13b1f293fd8f63a13e673", + "testharness" ], "pointerevents/pointerevent_setpointercapture_disconnected.html": [ "a7cc3e00e23f1544cdb81762025929a194df0f75", @@ -473888,7 +474167,7 @@ "support" ], "pointerevents/pointerevent_support.js": [ - "dc35ea24eebc65dd3b0fe52dd54042c78959bd1d", + "44dba450a3a2d558d3314da9413eb18a5ba9a1ff", "support" ], "pointerevents/pointerevent_suppress_compat_events_on_click.html": [ @@ -473991,9 +474270,9 @@ "6d903c405e95bd140cc201b7191434fac57931c8", "manual" ], - "pointerevents/pointerlock/pointerevent_movementxy_when_locked-manual.html": [ - "ccb8c27cb59bb1732dc72c5c26b6ca2a8fdf9f5c", - "manual" + "pointerevents/pointerlock/pointerevent_movementxy_when_locked.html": [ + "bdad97df04b2ca67fc1f92e256c979c137a4c66a", + "testharness" ], "pointerevents/pointerlock/pointerevent_pointerlock_after_pointercapture-manual.html": [ "8ac35f82856a38e887ec84ad67f5c374014905c5", @@ -498979,8 +499258,12 @@ "2bd5c9dba4d7c7cbaab692f8f87f64d2708313d5", "manual" ], + "wake-lock/wakelock-disabled-by-feature-policy.https.sub-expected.txt": [ + "2f5222518fbcb0f0306d609ef4e50bcf33dd459c", + "support" + ], "wake-lock/wakelock-disabled-by-feature-policy.https.sub.html": [ - "ad7eeb075f44430dbe4f9ed7a55c2ce3f155d0c0", + "008424ac3c8720a1b0a0691827a1c6f1ddb34ccd", "testharness" ], "wake-lock/wakelock-disabled-by-feature-policy.https.sub.html.headers": [ @@ -498995,24 +499278,36 @@ "1edafee45fc11ba5ae3ebcc83d1e8a5c22da9f24", "testharness" ], + "wake-lock/wakelock-enabled-by-feature-policy-attribute-redirect-on-load.https.sub-expected.txt": [ + "05b307cbd286ff743fd77648016bdea37c6052fc", + "support" + ], "wake-lock/wakelock-enabled-by-feature-policy-attribute-redirect-on-load.https.sub.html": [ - "74875937f6ec35ecdca2049e27999b3df6bd0c5d", + "d93eaa8bdc58861a922cb8cdb7cb3716d1ed8d97", "testharness" ], "wake-lock/wakelock-enabled-by-feature-policy-attribute.https.sub.html": [ - "185f5ad11b152b0f1ee42364022ef0d9ea0e9d2c", + "c0066e7f1f84d642554a31a4fa592dc08edbfc00", "testharness" ], + "wake-lock/wakelock-enabled-by-feature-policy.https.sub-expected.txt": [ + "a0328ea97004bcb2a7a7ea4ceb454e1fa7222be0", + "support" + ], "wake-lock/wakelock-enabled-by-feature-policy.https.sub.html": [ - "eb49be5d44b0d7ffefb3900e60a5524dbb77ece4", + "39a2af4960fd8011d2b502f0d7986992ac92b7b2", "testharness" ], "wake-lock/wakelock-enabled-by-feature-policy.https.sub.html.headers": [ "34b7437443cd9998c423260d05202be05d7b5d38", "support" ], + "wake-lock/wakelock-enabled-on-self-origin-by-feature-policy.https.sub-expected.txt": [ + "060131b3f498e25e3aa5ac8cc3e9b2d50a8d62bb", + "support" + ], "wake-lock/wakelock-enabled-on-self-origin-by-feature-policy.https.sub.html": [ - "a0c25525e6b61086e81f00a5d7a4226e43637942", + "ab81d4068b11d1aa534be0897f6dca684483158e", "testharness" ], "wake-lock/wakelock-enabled-on-self-origin-by-feature-policy.https.sub.html.headers": [ @@ -500992,7 +501287,7 @@ "testharness" ], "webaudio/the-audio-api/the-biquadfilternode-interface/no-dezippering.html": [ - "d54bc0bd8abe5f65bbfa618c76c286be78b9a6ac", + "63d4be3bb42101253aef2171ae70f977f0a7fb0d", "testharness" ], "webaudio/the-audio-api/the-channelmergernode-interface/audiochannelmerger-basic.html": [ @@ -503067,12 +503362,8 @@ "03211eccb920e136413a0e61a94d24f4d8bbd714", "testharness" ], - "webrtc/RTCDtlsTransport-getRemoteCertificates-expected.txt": [ - "e4e58c4347f1512cc6f854d2e5183b27c267c434", - "support" - ], "webrtc/RTCDtlsTransport-getRemoteCertificates.html": [ - "0614364e9756ec933ca842b97b1dbd31489b35ee", + "4735b7574123d65df93820132afd9fb6c3afa638", "testharness" ], "webrtc/RTCDtlsTransport-state.html": [ @@ -503568,7 +503859,7 @@ "testharness" ], "webrtc/idlharness.https.window-expected.txt": [ - "5e62ee6f092bcf9302253f2d17bf173d313bc705", + "3b456b5366ccad7e9eb445484cdaa009fad2b452", "support" ], "webrtc/idlharness.https.window.js": [
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/inheritance-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/inheritance-expected.txt new file mode 100644 index 0000000..fabdb48 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/inheritance-expected.txt
@@ -0,0 +1,64 @@ +This is a testharness.js-based test. +Found 60 tests; 59 PASS, 1 FAIL, 0 TIMEOUT, 0 NOTRUN. +PASS Property background-attachment has initial value scroll +PASS Property background-attachment does not inherit +PASS Property background-clip has initial value border-box +PASS Property background-clip does not inherit +PASS Property background-color has initial value rgba(0, 0, 0, 0) +PASS Property background-color does not inherit +PASS Property background-image has initial value none +PASS Property background-image does not inherit +PASS Property background-origin has initial value padding-box +PASS Property background-origin does not inherit +PASS Property background-position has initial value 0% 0% +PASS Property background-position does not inherit +PASS Property background-repeat has initial value repeat +PASS Property background-repeat does not inherit +PASS Property background-size has initial value auto +PASS Property background-size does not inherit +PASS Property border-bottom-color has initial value rgb(2, 3, 4) +PASS Property border-bottom-color does not inherit +PASS Property border-bottom-left-radius has initial value 0px +PASS Property border-bottom-left-radius does not inherit +PASS Property border-bottom-right-radius has initial value 0px +PASS Property border-bottom-right-radius does not inherit +PASS Property border-bottom-style has initial value none +PASS Property border-bottom-style does not inherit +PASS Property border-bottom-width has initial value 3px +PASS Property border-bottom-width does not inherit +FAIL Property border-image-outset has initial value 0 assert_equals: expected "0" but got "0px" +PASS Property border-image-outset does not inherit +PASS Property border-image-repeat has initial value stretch +PASS Property border-image-repeat does not inherit +PASS Property border-image-slice has initial value 100% +PASS Property border-image-slice does not inherit +PASS Property border-image-source has initial value none +PASS Property border-image-source does not inherit +PASS Property border-image-width has initial value 1 +PASS Property border-image-width does not inherit +PASS Property border-left-color has initial value rgb(2, 3, 4) +PASS Property border-left-color does not inherit +PASS Property border-left-style has initial value none +PASS Property border-left-style does not inherit +PASS Property border-left-width has initial value 3px +PASS Property border-left-width does not inherit +PASS Property border-right-color has initial value rgb(2, 3, 4) +PASS Property border-right-color does not inherit +PASS Property border-right-style has initial value none +PASS Property border-right-style does not inherit +PASS Property border-right-width has initial value 3px +PASS Property border-right-width does not inherit +PASS Property border-top-color has initial value rgb(2, 3, 4) +PASS Property border-top-color does not inherit +PASS Property border-top-left-radius has initial value 0px +PASS Property border-top-left-radius does not inherit +PASS Property border-top-right-radius has initial value 0px +PASS Property border-top-right-radius does not inherit +PASS Property border-top-style has initial value none +PASS Property border-top-style does not inherit +PASS Property border-top-width has initial value 3px +PASS Property border-top-width does not inherit +PASS Property box-shadow has initial value none +PASS Property box-shadow does not inherit +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/inheritance.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/inheritance.html new file mode 100644 index 0000000..768b18a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/inheritance.html
@@ -0,0 +1,77 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>Inheritance of CSS Backgrounds and Borders properties</title> +<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#property-index"> +<meta name="assert" content="Properties inherit or not according to the spec."> +<meta name="assert" content="Properties have initial values according to the spec."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/inheritance-testcommon.js"></script> +</head> +<body> +<div id="reference"></div> +<!-- container and target are used by the functions in inheritance-testcommon.js --> +<div id="container"> + <div id="target"></div> +</div> +<style> + #reference { + column-rule-style: dotted; /* Avoid column-rule-width computed style 0px */ + column-rule-width: medium; + } + #container { + border-style: solid; /* Avoid border-*-width computed style 0px */ + } + #target { + border-style: solid; /* Avoid border-*-width computed style 0px */ + } +</style> +<script> +const transparentColor = 'rgba(0, 0, 0, 0)'; // https://www.w3.org/TR/css-color-3/#transparent +const mediumWidth = getComputedStyle(document.getElementById('reference')).columnRuleWidth; // e.g. 3px +const currentColor = 'rgb(2, 3, 4)'; +container.style.color = currentColor; + + +// assert_not_inherited accepts: property name, expected initial value, another value the property supports. +assert_not_inherited('background-attachment', 'scroll', 'fixed'); +assert_not_inherited('background-clip', 'border-box', 'padding-box'); +assert_not_inherited('background-color', transparentColor, 'rgb(42, 53, 64)'); +assert_not_inherited('background-image', 'none', 'url("https://example.com/")'); +assert_not_inherited('background-origin', 'padding-box', 'content-box'); +assert_not_inherited('background-position', '0% 0%', '10px 20px'); +assert_not_inherited('background-repeat', 'repeat', 'space round'); +assert_not_inherited('background-size', 'auto', 'contain'); + +assert_not_inherited('border-bottom-color', currentColor, 'rgb(42, 53, 64)'); +assert_not_inherited('border-bottom-left-radius', '0px', '5px 7%'); +assert_not_inherited('border-bottom-right-radius', '0px', '5px 7%'); +assert_not_inherited('border-bottom-style', 'none', 'dashed'); +assert_not_inherited('border-bottom-width', mediumWidth, '10px'); + +assert_not_inherited('border-image-outset', '0', '1px 2px 3px 4px'); +assert_not_inherited('border-image-repeat', 'stretch', 'repeat round'); +assert_not_inherited('border-image-slice', '100%', '1% 2% 3% 4% fill'); +assert_not_inherited('border-image-source', 'none', 'url("https://example.com/")'); +assert_not_inherited('border-image-width', '1', '1px 2px 3px 4px'); + +assert_not_inherited('border-left-color', currentColor, 'rgb(42, 53, 64)'); +assert_not_inherited('border-left-style', 'none', 'dashed'); +assert_not_inherited('border-left-width', mediumWidth, '10px'); + +assert_not_inherited('border-right-color', currentColor, 'rgb(42, 53, 64)'); +assert_not_inherited('border-right-style', 'none', 'dashed'); +assert_not_inherited('border-right-width', mediumWidth, '10px'); + +assert_not_inherited('border-top-color', currentColor, 'rgb(42, 53, 64)'); +assert_not_inherited('border-top-left-radius', '0px', '5px 7%'); +assert_not_inherited('border-top-right-radius', '0px', '5px 7%'); +assert_not_inherited('border-top-style', 'none', 'dashed'); +assert_not_inherited('border-top-width', mediumWidth, '10px'); + +assert_not_inherited('box-shadow', 'none', 'rgb(42, 53, 64) 1px 2px 3px 4px'); +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/page-break-legacy-shorthands-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-break/page-break-legacy-shorthands-expected.txt deleted file mode 100644 index 4cfbd726..0000000 --- a/third_party/blink/web_tests/external/wpt/css/css-break/page-break-legacy-shorthands-expected.txt +++ /dev/null
@@ -1,7 +0,0 @@ -This is a testharness.js-based test. -PASS Legacy values of the shorthands work as expected -FAIL New values work on the new longhands, but serialize to the empty string in the legacy shorthands assert_equals: expected "" but got "auto" -PASS New values of the break longhands don't work on legacy shorthands -PASS Legacy shorthands really never appear on cssText, even when there are variable references -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/css/css-rhythm/inheritance.html b/third_party/blink/web_tests/external/wpt/css/css-rhythm/inheritance.html new file mode 100644 index 0000000..d47bfcb --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-rhythm/inheritance.html
@@ -0,0 +1,24 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>Inheritance of CSS Rhythmic Sizing properties</title> +<link rel="help" href="https://drafts.csswg.org/css-rhythm/#property-index"> +<meta name="assert" content="Properties do not inherit."> +<meta name="assert" content="Properties have initial values according to the spec."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/inheritance-testcommon.js"></script> +</head> +<body> +<div id="container"> + <div id="target"></div> +</div> +<script> +// Omitting block-step-align block-step-insert block-step-round block-step-size +// as they lack implementations. + +assert_inherited('line-height-step', '0px', '10px'); +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scrollbars/inheritance.html b/third_party/blink/web_tests/external/wpt/css/css-scrollbars/inheritance.html new file mode 100644 index 0000000..1a63078 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-scrollbars/inheritance.html
@@ -0,0 +1,22 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>Inheritance of CSS Scrollbars properties</title> +<link rel="help" href="https://drafts.csswg.org/css-scrollbars/#property-index"> +<meta name="assert" content="Properties inherit according to the spec."> +<meta name="assert" content="Properties have initial values according to the spec."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/inheritance-testcommon.js"></script> +</head> +<body> +<div id="container"> + <div id="target"></div> +</div> +<script> +assert_inherited('scrollbar-color', 'auto', 'rgb(1, 2, 3) rgb(4, 5, 6)'); +assert_not_inherited('scrollbar-width', 'auto', 'thin'); +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-outside-computed.html b/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-outside-computed.html index fb86b66..4a2f278e 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-outside-computed.html +++ b/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-outside-computed.html
@@ -17,9 +17,19 @@ </style> <div id="target"></div> <script> +// TODO: Add inset() tests + +test_computed_value("shape-outside", "circle(at 10% 20%)"); test_computed_value("shape-outside", "circle(calc(10px + 0.5em) at -50% 50%) border-box", "circle(30px at -50% 50%) border-box"); test_computed_value("shape-outside", "circle(calc(10px - 0.5em) at 50% -50%) border-box", "circle(0px at 50% -50%) border-box"); + test_computed_value("shape-outside", "ellipse(60% closest-side at 50% 50%)"); +test_computed_value("shape-outside", "ellipse(calc(10px + 0.5em) calc(10px - 0.5em) at -50% 50%) padding-box", "ellipse(30px 0px at -50% 50%) padding-box"); +test_computed_value("shape-outside", "ellipse(calc(10px - 0.5em) calc(10px + 0.5em) at 50% -50%) border-box", "ellipse(0px 30px at 50% -50%) border-box"); + +test_computed_value("polygon(evenodd, -10px, -20px, -30px, -40px, -50px, -60px) margin-box"); +test_computed_value("polygon(10%, 20%, 30%, 40%, 50%, 60%) content-box"); +test_computed_value("polygon(calc(10px - 0.5em), 20%, 30%, 40%, 50%, calc(10px - 0.5em))", "polygon(-10px, 20%, 30%, 40%, 50%, -10px)"); </script> </body> </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-outside-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-outside-invalid.html index 366fa92..5fe89a6 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-outside-invalid.html +++ b/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-outside-invalid.html
@@ -44,6 +44,8 @@ test_invalid_value("shape-outside", "polygon(1%)"); +test_invalid_value("shape-outside", "border-box circle(7% at 8% 9%) border-box"); + // <geometry-box> other than <shape-box> test_invalid_value("shape-outside", "fill-box"); test_invalid_value("shape-outside", "stroke-box");
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-outside-valid-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-outside-valid-expected.txt index ff80dc81..69e88ee 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-outside-valid-expected.txt +++ b/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-outside-valid-expected.txt
@@ -30,7 +30,10 @@ PASS e.style['shape-outside'] = "content-box" should set the property value PASS e.style['shape-outside'] = "margin-box" should set the property value PASS e.style['shape-outside'] = "circle(7% at 8% 9%) border-box" should set the property value +PASS e.style['shape-outside'] = "padding-box inset(10em)" should set the property value PASS e.style['shape-outside'] = "border-box circle(7% at 8% 9%)" should set the property value +PASS e.style['shape-outside'] = "margin-box ellipse(at 1em 2em)" should set the property value +PASS e.style['shape-outside'] = "content-box polygon(1% 2%)" should set the property value PASS e.style['shape-outside'] = "url(https://example.com/)" should set the property value PASS e.style['shape-outside'] = "url(\"https://example.com/\")" should set the property value FAIL e.style['shape-outside'] = "cross-fade(url(\"https://example.com/\"), green)" should set the property value assert_not_equals: property should be set got disallowed value ""
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-outside-valid.html b/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-outside-valid.html index 43e715d..99b565db 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-outside-valid.html +++ b/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-outside-valid.html
@@ -53,8 +53,11 @@ // basic-shape> <shape-box> test_valid_value("shape-outside", "circle(7% at 8% 9%) border-box"); -// <shape-box> basic-shape> -test_valid_value("shape-outside", "border-box circle(7% at 8% 9%)"); +// <shape-box> <basic-shape> +test_valid_value("shape-outside", "padding-box inset(10em)", "inset(10em) padding-box"); +test_valid_value("shape-outside", "border-box circle(7% at 8% 9%)", "circle(7% at 8% 9%) border-box"); +test_valid_value("shape-outside", "margin-box ellipse(at 1em 2em)", "ellipse(at 1em 2em) margin-box"); +test_valid_value("shape-outside", "content-box polygon(1% 2%)", "polygon(1% 2%) content-box"); // <image> // Spec is silent about url serialization.
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-shape-box-pair-000.html b/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-shape-box-pair-000.html index 72de9010..f6d0a5d 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-shape-box-pair-000.html +++ b/third_party/blink/web_tests/external/wpt/css/css-shapes/shape-outside/values/shape-outside-shape-box-pair-000.html
@@ -39,22 +39,22 @@ }, { "actual": " content-box polygon(nonzero, 1px 1px)", - "expected_inline": "content-box polygon(1px 1px)", + "expected_inline": "polygon(1px 1px) content-box", "expected_computed": "polygon(1px 1px) content-box" }, { "actual": "padding-box polygon(nonzero, 1px 1px)", - "expected_inline": "padding-box polygon(1px 1px)", + "expected_inline": "polygon(1px 1px) padding-box", "expected_computed": "polygon(1px 1px) padding-box" }, { "actual": "border-box polygon(nonzero, 1px 1px)", - "expected_inline": "border-box polygon(1px 1px)", + "expected_inline": "polygon(1px 1px) border-box", "expected_computed": "polygon(1px 1px) border-box" }, { "actual": "margin-box polygon(nonzero, 1px 1px)", - "expected_inline": "margin-box polygon(1px 1px)", + "expected_inline": "polygon(1px 1px) margin-box", "expected_computed": "polygon(1px 1px) margin-box" } ];
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/inheritance.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/inheritance.html new file mode 100644 index 0000000..367ad02 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/inheritance.html
@@ -0,0 +1,32 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>Inheritance of CSS Intrinsic & Extrinsic Sizing properties</title> +<link rel="help" href="https://drafts.csswg.org/css-sizing-3/#property-index"> +<meta name="assert" content="Properties do not inherit."> +<meta name="assert" content="Properties have initial values according to the spec."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/inheritance-testcommon.js"></script> +</head> +<body> +<div id="container"> +<div id="target"></div> +</div> +<style> + #container { + display: grid; + } +</style> +<script> +assert_not_inherited('box-sizing', 'content-box', 'border-box'); +assert_not_inherited('max-height', 'none', '10px'); +assert_not_inherited('max-width', 'none', '10px'); +assert_not_inherited('min-height', 'auto', '10px'); +assert_not_inherited('min-width', 'auto', '10px'); + +// height, width not yet tested. +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/box-sizing-computed.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/box-sizing-computed.html new file mode 100644 index 0000000..ad5d1a7 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/box-sizing-computed.html
@@ -0,0 +1,19 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Intrinsic & Extrinsic Sizing: getComputedValue().boxSizing</title> +<link rel="help" href="https://drafts.csswg.org/css-sizing-3/#propdef-box-sizing"> +<meta name="assert" content="box-sizing computed value is as specified."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/computed-testcommon.js"></script> +</head> +<body> +<div id="target"></div> +<script> +test_computed_value("box-sizing", "content-box"); +test_computed_value("box-sizing", "border-box"); +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/box-sizing-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/box-sizing-invalid.html new file mode 100644 index 0000000..02d5779 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/box-sizing-invalid.html
@@ -0,0 +1,24 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Intrinsic & Extrinsic Sizing Test: parsing box-sizing with invalid values</title> +<link rel="help" href="https://drafts.csswg.org/css-sizing-3/#propdef-box-sizing"> +<meta name="assert" content="box-sizing supports only the grammar 'content-box | border-box'."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +</head> +<body> +<script> +test_invalid_value("box-sizing", "margin-box"); +test_invalid_value("box-sizing", "padding-box"); +test_invalid_value("box-sizing", "fill-box"); +test_invalid_value("box-sizing", "stroke-box"); +test_invalid_value("box-sizing", "view-box"); + +test_invalid_value("box-sizing", "content-box border-box"); +test_invalid_value("box-sizing", "content-box, border-box"); +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/box-sizing-valid.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/box-sizing-valid.html new file mode 100644 index 0000000..8f0b809 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/box-sizing-valid.html
@@ -0,0 +1,18 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Intrinsic & Extrinsic Sizing Test: parsing box-sizing with valid values</title> +<link rel="help" href="https://drafts.csswg.org/css-sizing-3/#propdef-box-sizing"> +<meta name="assert" content="box-sizing supports the full grammar 'content-box | border-box'."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +</head> +<body> +<script> +test_valid_value("box-sizing", "content-box"); +test_valid_value("box-sizing", "border-box"); +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/height-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/height-invalid.html new file mode 100644 index 0000000..14dd0b9 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/height-invalid.html
@@ -0,0 +1,21 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Intrinsic & Extrinsic Sizing Test: parsing height with invalid values</title> +<link rel="help" href="https://drafts.csswg.org/css-sizing-3/#propdef-height"> +<meta name="assert" content="height supports only the grammar 'auto | <length-percentage> | min-content | max-content | fit-content(<length-percentage>)'."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +</head> +<body> +<script> +test_invalid_value("height", "none"); +test_invalid_value("height", "min-content max-content"); + +test_invalid_value("height", "-10%"); +test_invalid_value("height", "-0.5em"); +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/height-valid-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/height-valid-expected.txt new file mode 100644 index 0000000..4c06052 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/height-valid-expected.txt
@@ -0,0 +1,13 @@ +This is a testharness.js-based test. +PASS e.style['height'] = "auto" should set the property value +PASS e.style['height'] = "min-content" should set the property value +PASS e.style['height'] = "max-content" should set the property value +PASS e.style['height'] = "0" should set the property value +PASS e.style['height'] = "10%" should set the property value +PASS e.style['height'] = "0.5em" should set the property value +PASS e.style['height'] = "calc(10% - 0.5em)" should set the property value +FAIL e.style['height'] = "fit-content(10%)" should set the property value assert_not_equals: property should be set got disallowed value "" +FAIL e.style['height'] = "fit-content(0.5em)" should set the property value assert_not_equals: property should be set got disallowed value "" +FAIL e.style['height'] = "fit-content(10% - 0.5em)" should set the property value assert_not_equals: property should be set got disallowed value "" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/height-valid.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/height-valid.html new file mode 100644 index 0000000..204cd645 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/height-valid.html
@@ -0,0 +1,28 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Intrinsic & Extrinsic Sizing Test: parsing height with valid values</title> +<link rel="help" href="https://drafts.csswg.org/css-sizing-3/#propdef-height"> +<meta name="assert" content="height supports the full grammar 'auto | <length-percentage> | min-content | max-content | fit-content(<length-percentage>)'."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +</head> +<body> +<script> +test_valid_value("height", "auto"); +test_valid_value("height", "min-content"); +test_valid_value("height", "max-content"); + +test_valid_value("height", "0", "0px"); +test_valid_value("height", "10%"); +test_valid_value("height", "0.5em"); +test_valid_value("height", "calc(10% - 0.5em)"); + +test_valid_value("height", "fit-content(10%)"); +test_valid_value("height", "fit-content(0.5em)"); +test_valid_value("height", "fit-content(10% - 0.5em)"); +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/max-height-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/max-height-invalid.html new file mode 100644 index 0000000..3798bb31c --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/max-height-invalid.html
@@ -0,0 +1,21 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Intrinsic & Extrinsic Sizing Test: parsing max-height with invalid values</title> +<link rel="help" href="https://drafts.csswg.org/css-sizing-3/#propdef-max-height"> +<meta name="assert" content="max-height supports only the grammar 'none | <length-percentage> | min-content | max-content | fit-content(<length-percentage>)'."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +</head> +<body> +<script> +test_invalid_value("max-height", "auto"); +test_invalid_value("max-height", "min-content max-content"); + +test_invalid_value("max-height", "-10%"); +test_invalid_value("max-height", "-0.5em"); +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/max-height-valid-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/max-height-valid-expected.txt new file mode 100644 index 0000000..514956d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/max-height-valid-expected.txt
@@ -0,0 +1,13 @@ +This is a testharness.js-based test. +PASS e.style['max-height'] = "none" should set the property value +PASS e.style['max-height'] = "min-content" should set the property value +PASS e.style['max-height'] = "max-content" should set the property value +PASS e.style['max-height'] = "0" should set the property value +PASS e.style['max-height'] = "10%" should set the property value +PASS e.style['max-height'] = "0.5em" should set the property value +PASS e.style['max-height'] = "calc(10% - 0.5em)" should set the property value +FAIL e.style['max-height'] = "fit-content(10%)" should set the property value assert_not_equals: property should be set got disallowed value "" +FAIL e.style['max-height'] = "fit-content(0.5em)" should set the property value assert_not_equals: property should be set got disallowed value "" +FAIL e.style['max-height'] = "fit-content(10% - 0.5em)" should set the property value assert_not_equals: property should be set got disallowed value "" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/max-height-valid.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/max-height-valid.html new file mode 100644 index 0000000..3c4aab83 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/max-height-valid.html
@@ -0,0 +1,28 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Intrinsic & Extrinsic Sizing Test: parsing max-height with valid values</title> +<link rel="help" href="https://drafts.csswg.org/css-sizing-3/#propdef-max-height"> +<meta name="assert" content="max-height supports the full grammar 'none | <length-percentage> | min-content | max-content | fit-content(<length-percentage>)'."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +</head> +<body> +<script> +test_valid_value("max-height", "none"); +test_valid_value("max-height", "min-content"); +test_valid_value("max-height", "max-content"); + +test_valid_value("max-height", "0", "0px"); +test_valid_value("max-height", "10%"); +test_valid_value("max-height", "0.5em"); +test_valid_value("max-height", "calc(10% - 0.5em)"); + +test_valid_value("max-height", "fit-content(10%)"); +test_valid_value("max-height", "fit-content(0.5em)"); +test_valid_value("max-height", "fit-content(10% - 0.5em)"); +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/max-width-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/max-width-invalid.html new file mode 100644 index 0000000..86e8528 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/max-width-invalid.html
@@ -0,0 +1,21 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Intrinsic & Extrinsic Sizing Test: parsing max-width with invalid values</title> +<link rel="help" href="https://drafts.csswg.org/css-sizing-3/#propdef-max-width"> +<meta name="assert" content="max-width supports only the grammar 'none | <length-percentage> | min-content | max-content | fit-content(<length-percentage>)'."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +</head> +<body> +<script> +test_invalid_value("max-width", "auto"); +test_invalid_value("max-width", "min-content max-content"); + +test_invalid_value("max-width", "-10%"); +test_invalid_value("max-width", "-0.5em"); +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/max-width-valid-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/max-width-valid-expected.txt new file mode 100644 index 0000000..bcc2dad3 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/max-width-valid-expected.txt
@@ -0,0 +1,13 @@ +This is a testharness.js-based test. +PASS e.style['max-width'] = "none" should set the property value +PASS e.style['max-width'] = "min-content" should set the property value +PASS e.style['max-width'] = "max-content" should set the property value +PASS e.style['max-width'] = "0" should set the property value +PASS e.style['max-width'] = "10%" should set the property value +PASS e.style['max-width'] = "0.5em" should set the property value +PASS e.style['max-width'] = "calc(10% - 0.5em)" should set the property value +FAIL e.style['max-width'] = "fit-content(10%)" should set the property value assert_not_equals: property should be set got disallowed value "" +FAIL e.style['max-width'] = "fit-content(0.5em)" should set the property value assert_not_equals: property should be set got disallowed value "" +FAIL e.style['max-width'] = "fit-content(10% - 0.5em)" should set the property value assert_not_equals: property should be set got disallowed value "" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/max-width-valid.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/max-width-valid.html new file mode 100644 index 0000000..4788ccf --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/max-width-valid.html
@@ -0,0 +1,28 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Intrinsic & Extrinsic Sizing Test: parsing max-width with valid values</title> +<link rel="help" href="https://drafts.csswg.org/css-sizing-3/#propdef-max-width"> +<meta name="assert" content="max-width supports the full grammar 'none | <length-percentage> | min-content | max-content | fit-content(<length-percentage>)'."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +</head> +<body> +<script> +test_valid_value("max-width", "none"); +test_valid_value("max-width", "min-content"); +test_valid_value("max-width", "max-content"); + +test_valid_value("max-width", "0", "0px"); +test_valid_value("max-width", "10%"); +test_valid_value("max-width", "0.5em"); +test_valid_value("max-width", "calc(10% - 0.5em)"); + +test_valid_value("max-width", "fit-content(10%)"); +test_valid_value("max-width", "fit-content(0.5em)"); +test_valid_value("max-width", "fit-content(10% - 0.5em)"); +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/min-height-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/min-height-invalid.html new file mode 100644 index 0000000..0bb939b --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/min-height-invalid.html
@@ -0,0 +1,21 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Intrinsic & Extrinsic Sizing Test: parsing min-height with invalid values</title> +<link rel="help" href="https://drafts.csswg.org/css-sizing-3/#propdef-min-height"> +<meta name="assert" content="min-height supports only the grammar 'auto | <length-percentage> | min-content | max-content | fit-content(<length-percentage>)'."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +</head> +<body> +<script> +test_invalid_value("min-height", "none"); +test_invalid_value("min-height", "min-content max-content"); + +test_invalid_value("min-height", "-10%"); +test_invalid_value("min-height", "-0.5em"); +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/min-height-valid-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/min-height-valid-expected.txt new file mode 100644 index 0000000..d7107b7e --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/min-height-valid-expected.txt
@@ -0,0 +1,13 @@ +This is a testharness.js-based test. +PASS e.style['min-height'] = "auto" should set the property value +PASS e.style['min-height'] = "min-content" should set the property value +PASS e.style['min-height'] = "max-content" should set the property value +PASS e.style['min-height'] = "0" should set the property value +PASS e.style['min-height'] = "10%" should set the property value +PASS e.style['min-height'] = "0.5em" should set the property value +PASS e.style['min-height'] = "calc(10% - 0.5em)" should set the property value +FAIL e.style['min-height'] = "fit-content(10%)" should set the property value assert_not_equals: property should be set got disallowed value "" +FAIL e.style['min-height'] = "fit-content(0.5em)" should set the property value assert_not_equals: property should be set got disallowed value "" +FAIL e.style['min-height'] = "fit-content(10% - 0.5em)" should set the property value assert_not_equals: property should be set got disallowed value "" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/min-height-valid.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/min-height-valid.html new file mode 100644 index 0000000..debefbe --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/min-height-valid.html
@@ -0,0 +1,28 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Intrinsic & Extrinsic Sizing Test: parsing min-height with valid values</title> +<link rel="help" href="https://drafts.csswg.org/css-sizing-3/#propdef-min-height"> +<meta name="assert" content="min-height supports the full grammar 'auto | <length-percentage> | min-content | max-content | fit-content(<length-percentage>)'."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +</head> +<body> +<script> +test_valid_value("min-height", "auto"); +test_valid_value("min-height", "min-content"); +test_valid_value("min-height", "max-content"); + +test_valid_value("min-height", "0", "0px"); +test_valid_value("min-height", "10%"); +test_valid_value("min-height", "0.5em"); +test_valid_value("min-height", "calc(10% - 0.5em)"); + +test_valid_value("min-height", "fit-content(10%)"); +test_valid_value("min-height", "fit-content(0.5em)"); +test_valid_value("min-height", "fit-content(10% - 0.5em)"); +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/min-width-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/min-width-invalid.html new file mode 100644 index 0000000..b4e60090 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/min-width-invalid.html
@@ -0,0 +1,21 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Intrinsic & Extrinsic Sizing Test: parsing min-width with invalid values</title> +<link rel="help" href="https://drafts.csswg.org/css-sizing-3/#propdef-min-width"> +<meta name="assert" content="min-width supports only the grammar 'auto | <length-percentage> | min-content | max-content | fit-content(<length-percentage>)'."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +</head> +<body> +<script> +test_invalid_value("min-width", "none"); +test_invalid_value("min-width", "min-content max-content"); + +test_invalid_value("min-width", "-10%"); +test_invalid_value("min-width", "-0.5em"); +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/min-width-valid-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/min-width-valid-expected.txt new file mode 100644 index 0000000..6d49931c --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/min-width-valid-expected.txt
@@ -0,0 +1,13 @@ +This is a testharness.js-based test. +PASS e.style['min-width'] = "auto" should set the property value +PASS e.style['min-width'] = "min-content" should set the property value +PASS e.style['min-width'] = "max-content" should set the property value +PASS e.style['min-width'] = "0" should set the property value +PASS e.style['min-width'] = "10%" should set the property value +PASS e.style['min-width'] = "0.5em" should set the property value +PASS e.style['min-width'] = "calc(10% - 0.5em)" should set the property value +FAIL e.style['min-width'] = "fit-content(10%)" should set the property value assert_not_equals: property should be set got disallowed value "" +FAIL e.style['min-width'] = "fit-content(0.5em)" should set the property value assert_not_equals: property should be set got disallowed value "" +FAIL e.style['min-width'] = "fit-content(10% - 0.5em)" should set the property value assert_not_equals: property should be set got disallowed value "" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/min-width-valid.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/min-width-valid.html new file mode 100644 index 0000000..cbbd19c --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/min-width-valid.html
@@ -0,0 +1,28 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Intrinsic & Extrinsic Sizing Test: parsing min-width with valid values</title> +<link rel="help" href="https://drafts.csswg.org/css-sizing-3/#propdef-min-width"> +<meta name="assert" content="min-width supports the full grammar 'auto | <length-percentage> | min-content | max-content | fit-content(<length-percentage>)'."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +</head> +<body> +<script> +test_valid_value("min-width", "auto"); +test_valid_value("min-width", "min-content"); +test_valid_value("min-width", "max-content"); + +test_valid_value("min-width", "0", "0px"); +test_valid_value("min-width", "10%"); +test_valid_value("min-width", "0.5em"); +test_valid_value("min-width", "calc(10% - 0.5em)"); + +test_valid_value("min-width", "fit-content(10%)"); +test_valid_value("min-width", "fit-content(0.5em)"); +test_valid_value("min-width", "fit-content(10% - 0.5em)"); +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/width-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/width-invalid.html new file mode 100644 index 0000000..6c56d28 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/width-invalid.html
@@ -0,0 +1,21 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Intrinsic & Extrinsic Sizing Test: parsing width with invalid values</title> +<link rel="help" href="https://drafts.csswg.org/css-sizing-3/#propdef-width"> +<meta name="assert" content="width supports only the grammar 'auto | <length-percentage> | min-content | max-content | fit-content(<length-percentage>)'."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +</head> +<body> +<script> +test_invalid_value("width", "none"); +test_invalid_value("width", "min-content max-content"); + +test_invalid_value("width", "-10%"); +test_invalid_value("width", "-0.5em"); +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/width-valid-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/width-valid-expected.txt new file mode 100644 index 0000000..f732208 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/width-valid-expected.txt
@@ -0,0 +1,13 @@ +This is a testharness.js-based test. +PASS e.style['width'] = "auto" should set the property value +PASS e.style['width'] = "min-content" should set the property value +PASS e.style['width'] = "max-content" should set the property value +PASS e.style['width'] = "0" should set the property value +PASS e.style['width'] = "10%" should set the property value +PASS e.style['width'] = "0.5em" should set the property value +PASS e.style['width'] = "calc(10% - 0.5em)" should set the property value +FAIL e.style['width'] = "fit-content(10%)" should set the property value assert_not_equals: property should be set got disallowed value "" +FAIL e.style['width'] = "fit-content(0.5em)" should set the property value assert_not_equals: property should be set got disallowed value "" +FAIL e.style['width'] = "fit-content(10% - 0.5em)" should set the property value assert_not_equals: property should be set got disallowed value "" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/width-valid.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/width-valid.html new file mode 100644 index 0000000..f6c5c0a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/parsing/width-valid.html
@@ -0,0 +1,28 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Intrinsic & Extrinsic Sizing Test: parsing width with valid values</title> +<link rel="help" href="https://drafts.csswg.org/css-sizing-3/#propdef-width"> +<meta name="assert" content="width supports the full grammar 'auto | <length-percentage> | min-content | max-content | fit-content(<length-percentage>)'."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +</head> +<body> +<script> +test_valid_value("width", "auto"); +test_valid_value("width", "min-content"); +test_valid_value("width", "max-content"); + +test_valid_value("width", "0", "0px"); +test_valid_value("width", "10%"); +test_valid_value("width", "0.5em"); +test_valid_value("width", "calc(10% - 0.5em)"); + +test_valid_value("width", "fit-content(10%)"); +test_valid_value("width", "fit-content(0.5em)"); +test_valid_value("width", "fit-content(10% - 0.5em)"); +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-will-change/inheritance.html b/third_party/blink/web_tests/external/wpt/css/css-will-change/inheritance.html new file mode 100644 index 0000000..6b4ed2a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-will-change/inheritance.html
@@ -0,0 +1,21 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>Inheritance of CSS will-change property</title> +<link rel="help" href="https://drafts.csswg.org/css-will-change/#property-index"> +<meta name="assert" content="will-change does not inherit."> +<meta name="assert" content="will-change has initial value auto."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/inheritance-testcommon.js"></script> +</head> +<body> +<div id="container"> +<div id="target"></div> +</div> +<script> +assert_not_inherited('will-change', 'auto', 'transform'); +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-will-change/parsing/will-change-computed-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-will-change/parsing/will-change-computed-expected.txt new file mode 100644 index 0000000..c0c9e1a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-will-change/parsing/will-change-computed-expected.txt
@@ -0,0 +1,12 @@ +This is a testharness.js-based test. +PASS Property will-change value 'auto' computes to 'auto' +PASS Property will-change value 'scroll-position' computes to 'scroll-position' +PASS Property will-change value 'contents' computes to 'contents' +PASS Property will-change value 'transform' computes to 'transform' +PASS Property will-change value 'background-color' computes to 'background-color' +FAIL Property will-change value 'scroll-position, contents' computes to 'scroll-position, contents' assert_equals: expected "scroll-position, contents" but got "contents, scroll-position" +PASS Property will-change value 'scroll-position, transform' computes to 'scroll-position, transform' +PASS Property will-change value 'contents, transform' computes to 'contents, transform' +PASS Property will-change value 'transform, background-color' computes to 'transform, background-color' +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/css/css-will-change/parsing/will-change-computed.html b/third_party/blink/web_tests/external/wpt/css/css-will-change/parsing/will-change-computed.html new file mode 100644 index 0000000..d58aade4e --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-will-change/parsing/will-change-computed.html
@@ -0,0 +1,29 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Will Change Test: getComputedValue().willChange</title> +<link rel="help" href="https://drafts.csswg.org/css-will-change/#propdef-will-change"> +<meta name="assert" content="will-change computed value is as specified."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/computed-testcommon.js"></script> +</head> +<body> +<div id="target"></div> +<script> +test_computed_value("will-change", "auto"); + +// <animateable-feature> = scroll-position | contents | <custom-ident> +test_computed_value("will-change", "scroll-position"); +test_computed_value("will-change", "contents"); +test_computed_value("will-change", "transform"); +test_computed_value("will-change", "background-color"); + +test_computed_value("will-change", "scroll-position, contents"); +test_computed_value("will-change", "scroll-position, transform"); +test_computed_value("will-change", "contents, transform"); +test_computed_value("will-change", "transform, background-color"); +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-will-change/parsing/will-change-invalid-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-will-change/parsing/will-change-invalid-expected.txt new file mode 100644 index 0000000..321eebf --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-will-change/parsing/will-change-invalid-expected.txt
@@ -0,0 +1,14 @@ +This is a testharness.js-based test. +PASS e.style['will-change'] = "auto transform" should not set the property value +PASS e.style['will-change'] = "auto, transform" should not set the property value +PASS e.style['will-change'] = "contents auto" should not set the property value +PASS e.style['will-change'] = "contents, auto" should not set the property value +PASS e.style['will-change'] = "transform, initial" should not set the property value +PASS e.style['will-change'] = "transform, inherit" should not set the property value +FAIL e.style['will-change'] = "transform, unset" should not set the property value assert_equals: expected "" but got "transform" +PASS e.style['will-change'] = "transform, default" should not set the property value +PASS e.style['will-change'] = "will-change" should not set the property value +PASS e.style['will-change'] = "none" should not set the property value +PASS e.style['will-change'] = "all" should not set the property value +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/css/css-will-change/parsing/will-change-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-will-change/parsing/will-change-invalid.html new file mode 100644 index 0000000..83710ddbc --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-will-change/parsing/will-change-invalid.html
@@ -0,0 +1,33 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Will Change Test: parsing will-change with invalid values</title> +<link rel="author" title="Eric Willigers" href="mailto:ericwilligers@chromium.org"> +<link rel="help" href="https://drafts.csswg.org/css-will-change/#propdef-will-change"> +<meta name="assert" content="will-change only supports the grammar 'auto | <animateable-feature>#'."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +</head> +<body> +<script> +test_invalid_value("will-change", "auto transform"); +test_invalid_value("will-change", "auto, transform"); +test_invalid_value("will-change", "contents auto"); +test_invalid_value("will-change", "contents, auto"); + +// CSS-wide keywords are excluded from <custom-ident> +// https://drafts.csswg.org/css-values-4/#identifier-value +test_invalid_value("will-change", "transform, initial"); +test_invalid_value("will-change", "transform, inherit"); +test_invalid_value("will-change", "transform, unset"); +test_invalid_value("will-change", "transform, default"); + +// will-change additionally excludes the following from <custom-ident> +test_invalid_value("will-change", "will-change"); +test_invalid_value("will-change", "none"); +test_invalid_value("will-change", "all"); +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-will-change/parsing/will-change-valid.html b/third_party/blink/web_tests/external/wpt/css/css-will-change/parsing/will-change-valid.html new file mode 100644 index 0000000..b8a086b3 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-will-change/parsing/will-change-valid.html
@@ -0,0 +1,29 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Will Change Test: parsing will-change with valid values</title> +<link rel="author" title="Eric Willigers" href="mailto:ericwilligers@chromium.org"> +<link rel="help" href="https://drafts.csswg.org/css-will-change/#propdef-will-change"> +<meta name="assert" content="will-change supports the full grammar 'auto | <animateable-feature>#'."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +</head> +<body> +<script> +test_valid_value("will-change", "auto"); + +// <animateable-feature> = scroll-position | contents | <custom-ident> +test_valid_value("will-change", "scroll-position"); +test_valid_value("will-change", "contents"); +test_valid_value("will-change", "transform"); +test_valid_value("will-change", "background-color"); + +test_valid_value("will-change", "scroll-position, contents"); +test_valid_value("will-change", "scroll-position, transform"); +test_valid_value("will-change", "contents, transform"); +test_valid_value("will-change", "transform, background-color"); +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-event-fired-to-document.html b/third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-event-fired-to-document.html new file mode 100644 index 0000000..c054ffca --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-event-fired-to-document.html
@@ -0,0 +1,62 @@ +<!DOCTYPE HTML> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="scroll_support.js"></script> +<style> +#targetDiv { + width: 200px; + height: 200px; + overflow: scroll; +} + +#innerDiv { + width: 400px; + height: 400px; +} +</style> + +<body style="margin:0" onload=runTest()> +<div id="targetDiv"> + <div id="innerDiv"> + </div> +</div> +</body> + +<script> +var target_div = document.getElementById('targetDiv'); +var overscrolled_x_delta = 0; +var overscrolled_y_delta = 0; +function onOverscroll(event) { + assert_false(event.cancelable); + // overscroll events are bubbled when the target node is document. + assert_true(event.bubbles); + overscrolled_x_delta = event.deltaX; + overscrolled_y_delta = event.deltaY; +} +document.addEventListener("overscroll", onOverscroll); + +function runTest() { + promise_test (async (t) => { + // Make sure that no overscroll event is sent to target_div. + target_div.addEventListener("overscroll", + t.unreached_func("target_div got unexpected overscroll event.")); + await waitForCompositorCommit(); + + // Scroll up on target div and wait for the doc to get overscroll event. + await touchScrollInTarget(300, target_div, 'up'); + await waitFor(() => { return overscrolled_y_delta < 0; }, + 'Document did not receive overscroll event after scroll up on target.'); + assert_equals(target_div.scrollTop, 0); + + // Scroll left on target div and wait for the doc to get overscroll event. + await touchScrollInTarget(300, target_div, 'left'); + await waitFor(() => { return overscrolled_x_delta < 0; }, + 'Document did not receive overscroll event after scroll left on target.'); + assert_equals(target_div.scrollLeft, 0); + }, 'Tests that the document gets overscroll event when no element scrolls ' + + 'after touch scrolling.'); +} +</script>
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-event-fired-to-element-with-overscroll-behavior.html b/third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-event-fired-to-element-with-overscroll-behavior.html new file mode 100644 index 0000000..750080e --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-event-fired-to-element-with-overscroll-behavior.html
@@ -0,0 +1,92 @@ +<!DOCTYPE HTML> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="scroll_support.js"></script> +<style> +#overscrollXDiv { + width: 600px; + height: 600px; + overflow: scroll; + overscroll-behavior-x: contain; +} +#overscrollYDiv { + width: 500px; + height: 500px; + overflow: scroll; + overscroll-behavior-y: none; +} +#targetDiv { + width: 400px; + height: 400px; + overflow: scroll; +} +.content { + width:800px; + height:800px; +} +</style> + +<body style="margin:0" onload=runTest()> +<div id="overscrollXDiv"> + <div class=content> + <div id="overscrollYDiv"> + <div class=content> + <div id="targetDiv"> + <div class="content"> + </div> + </div> + </div> + </div> + </div> +</div> +</body> + +<script> +var target_div = document.getElementById('targetDiv'); +var overscrolled_x_delta = 0; +var overscrolled_y_delta = 0; +function onOverscrollX(event) { + assert_false(event.cancelable); + assert_false(event.bubbles); + overscrolled_x_delta = event.deltaX; +} +function onOverscrollY(event) { + assert_false(event.cancelable); + assert_false(event.bubbles); + overscrolled_y_delta = event.deltaY; +} +// Test that both "onoverscroll" and addEventListener("overscroll"... work. +document.getElementById('overscrollXDiv').onoverscroll = onOverscrollX; +document.getElementById('overscrollYDiv'). + addEventListener("overscroll", onOverscrollY); + +function runTest() { + promise_test (async (t) => { + // Make sure that no overscroll event is sent to document or target_div. + document.addEventListener("overscroll", + t.unreached_func("Document got unexpected overscroll event.")); + target_div.addEventListener("overscroll", + t.unreached_func("target_div got unexpected overscroll event.")); + await waitForCompositorCommit(); + // Scroll up on target div and wait for the element with overscroll-y to get + // overscroll event. + await touchScrollInTarget(300, target_div, 'up'); + await waitFor(() => { return overscrolled_y_delta < 0; }, + 'Expected element did not receive overscroll event after scroll up on ' + + 'target.'); + assert_equals(target_div.scrollTop, 0); + + // Scroll left on target div and wait for the element with overscroll-x to + // get overscroll event. + await touchScrollInTarget(300, target_div, 'left'); + await waitFor(() => { return overscrolled_x_delta < 0; }, + 'Expected element did not receive overscroll event after scroll left ' + + 'on target.'); + assert_equals(target_div.scrollLeft, 0); + }, 'Tests that the last element in the cut scroll chain gets overscroll ' + + 'event when no element scrolls by touch.'); +} +</script>
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-event-fired-to-scrolled-element.html b/third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-event-fired-to-scrolled-element.html new file mode 100644 index 0000000..cfc782a8 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-event-fired-to-scrolled-element.html
@@ -0,0 +1,65 @@ +<!DOCTYPE HTML> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="scroll_support.js"></script> +<style> +#scrollableDiv { + width: 200px; + height: 200px; + overflow: scroll; +} + +#innerDiv { + width: 400px; + height: 400px; +} +</style> + +<body style="margin:0" onload=runTest()> +<div id="scrollableDiv"> + <div id="innerDiv"> + </div> +</div> +</body> + +<script> +var scrolling_div = document.getElementById('scrollableDiv'); +var overscrolled_x_delta = 0; +var overscrolled_y_delta = 0; +function onOverscroll(event) { + assert_false(event.cancelable); + assert_false(event.bubbles); + overscrolled_x_delta = event.deltaX; + overscrolled_y_delta = event.deltaY; +} +scrolling_div.addEventListener("overscroll", onOverscroll); + +function runTest() { + promise_test (async (t) => { + // Make sure that no overscroll event is sent to document. + document.addEventListener("overscroll", + t.unreached_func("Document got unexpected overscroll event.")); + await waitForCompositorCommit(); + + // Do a horizontal scroll and wait for overscroll event. + await touchScrollInTarget(300, scrolling_div , 'right'); + await waitFor(() => { return overscrolled_x_delta > 0; }, + 'Scroller did not receive overscroll event after horizontal scroll.'); + assert_equals(scrolling_div.scrollWidth - scrolling_div.scrollLeft, + scrolling_div.clientWidth); + + overscrolled_x_delta = 0; + overscrolled_y_delta = 0; + + // Do a vertical scroll and wait for overscroll event. + await touchScrollInTarget(300, scrolling_div, 'down'); + await waitFor(() => { return overscrolled_y_delta > 0; }, + 'Scroller did not receive overscroll event after vertical scroll.'); + assert_equals(scrolling_div.scrollHeight - scrolling_div.scrollTop, + scrolling_div.clientHeight); + }, 'Tests that the scrolled element gets overscroll event after fully scrolling by touch.'); +} +</script>
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-event-fired-to-window.html b/third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-event-fired-to-window.html new file mode 100644 index 0000000..ef5ae3d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/dom/events/scrolling/overscroll-event-fired-to-window.html
@@ -0,0 +1,52 @@ +<!DOCTYPE HTML> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="scroll_support.js"></script> +<style> +#targetDiv { + width: 200px; + height: 200px; + overflow: scroll; +} + +#innerDiv { + width: 400px; + height: 400px; +} +</style> + +<body style="margin:0" onload=runTest()> +<div id="targetDiv"> + <div id="innerDiv"> + </div> +</div> +</body> + +<script> +var target_div = document.getElementById('targetDiv'); +var window_received_overscroll = false; + +function onOverscroll(event) { + assert_false(event.cancelable); + // overscroll events targetting document are bubbled to the window. + assert_true(event.bubbles); + window_received_overscroll = true; +} +window.addEventListener("overscroll", onOverscroll); + +function runTest() { + promise_test (async (t) => { + // Make sure that no overscroll event is sent to target_div. + target_div.addEventListener("overscroll", + t.unreached_func("target_div got unexpected overscroll event.")); + // Scroll up on target div and wait for the window to get overscroll event. + await touchScrollInTarget(300, target_div, 'up'); + await waitFor(() => { return window_received_overscroll; }, + 'Window did not receive overscroll event after scroll up on target.'); + }, 'Tests that the window gets overscroll event when no element scrolls' + + 'after touch scrolling.'); +} +</script>
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/scrolling/scroll_support.js b/third_party/blink/web_tests/external/wpt/dom/events/scrolling/scroll_support.js new file mode 100644 index 0000000..6fd1b322 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/dom/events/scrolling/scroll_support.js
@@ -0,0 +1,85 @@ +const MAX_FRAME = 700; +const MAX_UNCHANGED_FRAMES = 20; + +// Returns a promise that resolves when the given condition is met or rejects +// after MAX_FRAME animation frames. +function waitFor(condition, error_message = 'Reaches the maximum frames.') { + return new Promise((resolve, reject) => { + function tick(frames) { + // We requestAnimationFrame either for MAX_FRAM frames or until condition + // is met. + if (frames >= MAX_FRAME) + reject(error_message); + else if (condition()) + resolve(); + else + requestAnimationFrame(tick.bind(this, frames + 1)); + } + tick(0); + }); +} + +function waitForCompositorCommit() { + return new Promise((resolve) => { + // rAF twice. + window.requestAnimationFrame(() => { + window.requestAnimationFrame(resolve); + }); + }); +} + +function waitForAnimationEnd(getValue) { + var last_changed_frame = 0; + var last_position = getValue(); + return new Promise((resolve, reject) => { + function tick(frames) { + // We requestAnimationFrame either for MAX_FRAME or until + // MAX_UNCHANGED_FRAMES with no change have been observed. + if (frames >= MAX_FRAME || frames - last_changed_frame > MAX_UNCHANGED_FRAMES) { + resolve(); + } else { + current_value = getValue(); + if (last_position != current_value) { + last_changed_frame = frames; + last_position = current_value; + } + requestAnimationFrame(tick.bind(this, frames + 1)); + } + } + tick(0); + }) +} + +function touchScrollInTarget(pixels_to_scroll, target, direction, pause_time_in_ms = 100) { + var x_delta = 0; + var y_delta = 0; + const num_movs = 5; + if (direction == "down") { + y_delta = -1 * pixels_to_scroll / num_movs; + } else if (direction == "up") { + y_delta = pixels_to_scroll / num_movs; + } else if (direction == "right") { + x_delta = -1 * pixels_to_scroll / num_movs; + } else if (direction == "left") { + x_delta = pixels_to_scroll / num_movs;; + } else { + throw("scroll direction '" + direction + "' is not expected, direction should be 'down', 'up', 'left' or 'right'"); + } + return new test_driver.Actions() + .addPointer("pointer1", "touch") + .pointerMove(0, 0, {origin: target}) + .pointerDown() + .pointerMove(x_delta, y_delta, {origin: target}) + .pointerMove(2 * x_delta, 2 * y_delta, {origin: target}) + .pointerMove(3 * x_delta, 3 * y_delta, {origin: target}) + .pointerMove(4 * x_delta, 4 * y_delta, {origin: target}) + .pointerMove(5 * x_delta, 5 * y_delta, {origin: target}) + .pause(pause_time_in_ms) + .pointerUp() + .send(); +} + +// Trigger fling by doing pointerUp right after pointerMoves. +function touchFlingInTarget(pixels_to_scroll, target, direction) { + touchScrollInTarget(pixels_to_scroll, target, direction, 0 /* pause_time */); +}
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/scrolling/scrollend-event-fired-after-snap.html b/third_party/blink/web_tests/external/wpt/dom/events/scrolling/scrollend-event-fired-after-snap.html new file mode 100644 index 0000000..ef1b495 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/dom/events/scrolling/scrollend-event-fired-after-snap.html
@@ -0,0 +1,86 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="scroll_support.js"></script> +<style> +div { + position: absolute; +} +#scroller { + width: 500px; + height: 500px; + overflow: scroll; + scroll-snap-type: both mandatory; + border: solid black 5px; +} +#space { + width: 2000px; + height: 2000px; +} +.target { + width: 200px; + height: 200px; + scroll-snap-align: start; + background-color: blue; +} +</style> + +<body style="margin:0" onload=runTests()> + <div id="scroller"> + <div id="space"></div> + <div class="target" style="left: 0px; top: 0px;"></div> + <div class="target" style="left: 80px; top: 80px;"></div> + <div class="target" style="left: 200px; top: 200px;"></div> + </div> +</body> + +<script> +var scroller = document.getElementById("scroller"); +var space = document.getElementById("space"); +const MAX_FRAME_COUNT = 700; +const MAX_UNCHANGED_FRAME = 20; + +function scrollTop() { + return scroller.scrollTop; +} + +var scroll_arrived_after_scroll_end = false; +var scroll_end_arrived = false; +scroller.addEventListener("scroll", () => { + if (scroll_end_arrived) + scroll_arrived_after_scroll_end = true; +}); +scroller.addEventListener("scrollend", () => { + scroll_end_arrived = true; +}); + +function runTests() { + promise_test (async () => { + await waitForCompositorCommit(); + await touchScrollInTarget(100, scroller, 'down'); + // Wait for the scroll snap animation to finish. + await waitForAnimationEnd(scrollTop); + await waitFor(() => { return scroll_end_arrived; }); + // Verify that scroll snap animation has finished before firing scrollend event. + assert_false(scroll_arrived_after_scroll_end); + }, "Tests that scrollend is fired after scroll snap animation completion."); + + promise_test (async () => { + // Reset scroll state. + scroller.scrollTo(0, 0); + await waitForCompositorCommit(); + scroll_end_arrived = false; + scroll_arrived_after_scroll_end = false; + + await touchFlingInTarget(50, scroller, 'down'); + // Wait for the scroll snap animation to finish. + await waitForAnimationEnd(scrollTop); + await waitFor(() => { return scroll_end_arrived; }); + // Verify that scroll snap animation has finished before firing scrollend event. + assert_false(scroll_arrived_after_scroll_end); + }, "Tests that scrollend is fired after fling snap animation completion."); +} +</script>
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/scrolling/scrollend-event-fired-to-document.html b/third_party/blink/web_tests/external/wpt/dom/events/scrolling/scrollend-event-fired-to-document.html new file mode 100644 index 0000000..a35508e2 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/dom/events/scrolling/scrollend-event-fired-to-document.html
@@ -0,0 +1,67 @@ +<!DOCTYPE HTML> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="scroll_support.js"></script> +<style> +#targetDiv { + width: 200px; + height: 200px; + overflow: scroll; +} + +#innerDiv { + width: 400px; + height: 400px; +} +</style> + +<body style="margin:0" onload=runTest()> +<div id="targetDiv"> + <div id="innerDiv"> + </div> +</div> +</body> + +<script> +var target_div = document.getElementById('targetDiv'); +var horizontal_scrollend_arrived = false; +var vertical_scrollend_arrived = false; +function onHorizontalScrollEnd(event) { + assert_false(event.cancelable); + // scrollend events are bubbled when the target node is document. + assert_true(event.bubbles); + horizontal_scrollend_arrived = true; +} +function onVerticalScrollEnd(event) { + assert_false(event.cancelable); + // scrollend events are bubbled when the target node is document. + assert_true(event.bubbles); + vertical_scrollend_arrived = true; +} +document.addEventListener("scrollend", onHorizontalScrollEnd); +document.addEventListener("scrollend", onVerticalScrollEnd); + +function runTest() { + promise_test (async (t) => { + // Make sure that no scrollend event is sent to target_div. + target_div.addEventListener("scrollend", + t.unreached_func("target_div got unexpected scrollend event.")); + await waitForCompositorCommit(); + // Scroll left on target div and wait for the doc to get scrollend event. + await touchScrollInTarget(300, target_div, 'left'); + await waitFor(() => { return horizontal_scrollend_arrived; }, + 'Document did not receive scrollend event after scroll left on target.'); + assert_equals(target_div.scrollLeft, 0); + + // Scroll up on target div and wait for the doc to get scrollend event. + await touchScrollInTarget(300, target_div, 'up'); + await waitFor(() => { return vertical_scrollend_arrived; }, + 'Document did not receive scrollend event after scroll up on target.'); + assert_equals(target_div.scrollTop, 0); + }, 'Tests that the document gets scrollend event when no element scrolls by ' + + 'touch.'); +} +</script>
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/scrolling/scrollend-event-fired-to-element-with-overscroll-behavior.html b/third_party/blink/web_tests/external/wpt/dom/events/scrolling/scrollend-event-fired-to-element-with-overscroll-behavior.html new file mode 100644 index 0000000..0269c66 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/dom/events/scrolling/scrollend-event-fired-to-element-with-overscroll-behavior.html
@@ -0,0 +1,93 @@ +<!DOCTYPE HTML> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="scroll_support.js"></script> +<style> +#overscrollXDiv { + width: 600px; + height: 600px; + overflow: scroll; + overscroll-behavior-x: contain; +} +#overscrollYDiv { + width: 500px; + height: 500px; + overflow: scroll; + overscroll-behavior-y: none; +} +#targetDiv { + width: 400px; + height: 400px; + overflow: scroll; +} +.content { + width:800px; + height:800px; +} +</style> + +<body style="margin:0" onload=runTest()> +<div id="overscrollXDiv"> + <div class=content> + <div id="overscrollYDiv"> + <div class=content> + <div id="targetDiv"> + <div class="content"> + </div> + </div> + </div> + </div> + </div> +</div> +</body> + +<script> +var target_div = document.getElementById('targetDiv'); +var horizontal_scrollend_arrived = false; +var vertical_scrollend_arrived = false; +function onHorizontalScrollEnd(event) { + assert_false(event.cancelable); + assert_false(event.bubbles); + horizontal_scrollend_arrived = true; +} +function onVerticalScrollEnd(event) { + assert_false(event.cancelable); + assert_false(event.bubbles); + vertical_scrollend_arrived = true; +} +// Test that both "onscrollend" and addEventListener("scrollend"... work. +document.getElementById('overscrollXDiv').onscrollend = onHorizontalScrollEnd; +document.getElementById('overscrollYDiv'). + addEventListener("scrollend", onVerticalScrollEnd); + +function runTest() { + promise_test (async (t) => { + // Make sure that no scrollend event is sent to document or target_div. + document.addEventListener("scrollend", + t.unreached_func("Document got unexpected scrollend event.")); + target_div.addEventListener("scrollend", + t.unreached_func("target_div got unexpected scrollend event.")); + await waitForCompositorCommit(); + + // Scroll left on target div and wait for the element with overscroll-x to + // get scrollend event. + await touchScrollInTarget(300, target_div, 'left'); + await waitFor(() => { return horizontal_scrollend_arrived; }, + 'Expected element did not receive scrollend event after scroll left ' + + 'on target.'); + assert_equals(target_div.scrollLeft, 0); + + // Scroll up on target div and wait for the element with overscroll-y to get + // scrollend event. + await touchScrollInTarget(300, target_div, 'up'); + await waitFor(() => { return vertical_scrollend_arrived; }, + 'Expected element did not receive scrollend event after scroll up on ' + + 'target.'); + assert_equals(target_div.scrollTop, 0); + }, 'Tests that the last element in the cut scroll chain gets scrollend ' + + 'event when no element scrolls by touch.'); +} +</script>
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/scrolling/scrollend-event-fired-to-scrolled-element.html b/third_party/blink/web_tests/external/wpt/dom/events/scrolling/scrollend-event-fired-to-scrolled-element.html new file mode 100644 index 0000000..87cad79 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/dom/events/scrolling/scrollend-event-fired-to-scrolled-element.html
@@ -0,0 +1,67 @@ +<!DOCTYPE HTML> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="scroll_support.js"></script> +<style> +#scrollableDiv { + width: 200px; + height: 200px; + overflow: scroll; +} + +#innerDiv { + width: 400px; + height: 400px; +} +</style> + +<body style="margin:0" onload=runTest()> +<div id="scrollableDiv"> + <div id="innerDiv"> + </div> +</div> +</body> + +<script> +var scrolling_div = document.getElementById('scrollableDiv'); +var horizontal_scrollend_arrived = false; +var vertical_scrollend_arrived = false; +function onHorizontalScrollEnd(event) { + assert_false(event.cancelable); + assert_false(event.bubbles); + horizontal_scrollend_arrived = true; +} +function onVerticalScrollEnd(event) { + assert_false(event.cancelable); + assert_false(event.bubbles); + vertical_scrollend_arrived = true; +} +scrolling_div.addEventListener("scrollend", onHorizontalScrollEnd); +scrolling_div.addEventListener("scrollend", onVerticalScrollEnd); + +function runTest() { + promise_test (async (t) => { + // Make sure that no scrollend event is sent to document. + document.addEventListener("scrollend", + t.unreached_func("Document got unexpected scrollend event.")); + await waitForCompositorCommit(); + + // Do a horizontal scroll and wait for scrollend event. + await touchScrollInTarget(300, scrolling_div, 'right'); + await waitFor(() => { return horizontal_scrollend_arrived; }, + 'Scroller did not receive scrollend event after horizontal scroll.'); + assert_equals(scrolling_div.scrollWidth - scrolling_div.scrollLeft, + scrolling_div.clientWidth); + + // Do a vertical scroll and wait for scrollend event. + await touchScrollInTarget(300, scrolling_div, 'down'); + await waitFor(() => { return vertical_scrollend_arrived; }, + 'Scroller did not receive scrollend event after vertical scroll.'); + assert_equals(scrolling_div.scrollHeight - scrolling_div.scrollTop, + scrolling_div.clientHeight); + }, 'Tests that the scrolled element gets scrollend event at the end of touch scrolling.'); +} +</script>
diff --git a/third_party/blink/web_tests/external/wpt/dom/events/scrolling/scrollend-event-fired-to-window.html b/third_party/blink/web_tests/external/wpt/dom/events/scrolling/scrollend-event-fired-to-window.html new file mode 100644 index 0000000..f9510e6e --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/dom/events/scrolling/scrollend-event-fired-to-window.html
@@ -0,0 +1,54 @@ +<!DOCTYPE HTML> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="scroll_support.js"></script> +<style> +#targetDiv { + width: 200px; + height: 200px; + overflow: scroll; +} + +#innerDiv { + width: 400px; + height: 400px; +} +</style> + +<body style="margin:0" onload=runTest()> +<div id="targetDiv"> + <div id="innerDiv"> + </div> +</div> +</body> + +<script> +var target_div = document.getElementById('targetDiv'); +var scrollend_arrived = false; +function onScrollEnd(event) { + assert_false(event.cancelable); + // scrollend events targetting document are bubbled to the window. + assert_true(event.bubbles); + scrollend_arrived = true; +} +window.addEventListener("scrollend", onScrollEnd); + +function runTest() { + promise_test (async (t) => { + // Make sure that no scrollend event is sent to target_div. + target_div.addEventListener("scrollend", + t.unreached_func("target_div got unexpected scrollend event.")); + await waitForCompositorCommit(); + + // Scroll up on target div and wait for the doc to get scrollend event. + await touchScrollInTarget(300, target_div, 'up'); + await waitFor(() => { return scrollend_arrived; }, + 'Window did not receive scrollend event after scroll up on target.'); + assert_equals(target_div.scrollTop, 0); + }, 'Tests that the window gets scrollend event when no element scrolls ' + + 'after touch scrolling.'); +} +</script>
diff --git a/third_party/blink/web_tests/external/wpt/feature-policy/resources/feature-policy-wakelock.html b/third_party/blink/web_tests/external/wpt/feature-policy/resources/feature-policy-wakelock.html index 3acc3476..292e8a1c 100644 --- a/third_party/blink/web_tests/external/wpt/feature-policy/resources/feature-policy-wakelock.html +++ b/third_party/blink/web_tests/external/wpt/feature-policy/resources/feature-policy-wakelock.html
@@ -1,9 +1,9 @@ <script> "use strict"; -Promise.resolve().then(async () => { +Promise.resolve().then(() => { try { - const wakeLock = await navigator.getWakeLock("screen"); + const wakeLock = new WakeLock("screen"); window.parent.postMessage({ enabled: true }, "*"); } catch (e) { window.parent.postMessage({ enabled: false }, "*");
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-input-element/type-change-file-to-text-crash.html b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-input-element/type-change-file-to-text-crash.html new file mode 100644 index 0000000..5fb5000 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-input-element/type-change-file-to-text-crash.html
@@ -0,0 +1,11 @@ +<!DOCTYPE html> +<link rel="help" href="https://html.spec.whatwg.org/multipage/input.html#input-type-change"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<input id="myInput" type="file"> +<script> + test(() => { + myInput.offsetTop; + myInput.type = "text"; + }, "Changing type from file to text should not crash."); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/payment-handler/idlharness.https.any.serviceworker-expected.txt b/third_party/blink/web_tests/external/wpt/payment-handler/idlharness.https.any.serviceworker-expected.txt index e4fbb7e8..d568ca4c 100644 --- a/third_party/blink/web_tests/external/wpt/payment-handler/idlharness.https.any.serviceworker-expected.txt +++ b/third_party/blink/web_tests/external/wpt/payment-handler/idlharness.https.any.serviceworker-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 96 tests; 62 PASS, 34 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 96 tests; 63 PASS, 33 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS idl_test setup PASS Partial interface ServiceWorkerRegistration: original interface defined PASS Partial interface ServiceWorkerGlobalScope: original interface defined @@ -72,7 +72,7 @@ PASS PaymentRequestEvent interface: attribute instrumentKey FAIL PaymentRequestEvent interface: attribute requestBillingAddress assert_true: The prototype object must have a property "requestBillingAddress" expected true got false PASS PaymentRequestEvent interface: operation openWindow(USVString) -FAIL PaymentRequestEvent interface: operation changePaymentMethod(DOMString, object) assert_own_property: interface prototype object missing non-static operation expected property "changePaymentMethod" missing +PASS PaymentRequestEvent interface: operation changePaymentMethod(DOMString, object) PASS PaymentRequestEvent interface: operation respondWith([object Object]) FAIL PaymentRequestEvent must be primary interface of new PaymentRequestEvent("type") assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present." FAIL Stringification of new PaymentRequestEvent("type") assert_equals: Unexpected exception when evaluating object expected null but got object "TypeError: Failed to construct 'PaymentRequestEvent': 2 arguments required, but only 1 present."
diff --git a/third_party/blink/web_tests/external/wpt/portals/portal-activate-event.html b/third_party/blink/web_tests/external/wpt/portals/portal-activate-event.html index 33d91e37..780e8b58 100644 --- a/third_party/blink/web_tests/external/wpt/portals/portal-activate-event.html +++ b/third_party/blink/web_tests/external/wpt/portals/portal-activate-event.html
@@ -11,7 +11,7 @@ bc.close(); }); const portalUrl = encodeURIComponent(`portal-activate-event-portal.html?test=${test}`); - window.open(`resources/portal-embed-and-activate.html?url=${portalUrl}&channelName=portal-${test}`); + window.open(`resources/portal-embed-and-activate.html?url=${portalUrl}`); }, "Tests that the PortalActivateEvent is dispatched when a portal is activated."); async_test(function(t) { @@ -22,7 +22,7 @@ bc.close(); }); const portalUrl = encodeURIComponent(`portal-activate-event-portal.html?test=${test}`); - window.open(`resources/portal-embed-and-activate.html?url=${portalUrl}&channelName=portal-${test}`); + window.open(`resources/portal-embed-and-activate.html?url=${portalUrl}`); }, "Tests that the portalactivate event handler is dispatched when a portal is activated."); async_test(function(t) { @@ -33,6 +33,6 @@ bc.close(); }); const portalUrl = encodeURIComponent(`portal-activate-event-portal.html?test=${test}`); - window.open(`resources/portal-embed-and-activate.html?url=${portalUrl}&channelName=portal-${test}`); + window.open(`resources/portal-embed-and-activate.html?url=${portalUrl}`); }, "Tests that the HTMLBodyElement has the portalactivate event handler."); </script>
diff --git a/third_party/blink/web_tests/external/wpt/portals/portals-post-message.sub.html b/third_party/blink/web_tests/external/wpt/portals/portals-post-message.sub.html index fe58e25..2d16a42 100644 --- a/third_party/blink/web_tests/external/wpt/portals/portals-post-message.sub.html +++ b/third_party/blink/web_tests/external/wpt/portals/portals-post-message.sub.html
@@ -9,7 +9,7 @@ <input id="input"/> <script> const sameOriginUrl = "resources/portal-post-message-portal.html" - const crossOriginUrl = "http://{{hosts[alt][www]}}:{{ports[http][0]}}/portals/resources/portal-post-message-cross-origin-portal.sub.html" + const crossOriginUrl = "http://{{hosts[alt][www]}}:{{ports[http][0]}}/portals/resources/portal-post-message-portal.html" async function createAndInsertPortal(portalSrc) { var portal = document.createElement("portal"); @@ -17,11 +17,7 @@ document.body.append(portal); var loadPromise = new Promise((resolve, reject) => { - var bc = new BroadcastChannel("portals-post-message"); - bc.onmessage = e => { - bc.close(); - resolve(); - }; + portal.onmessage = resolve; }); await loadPromise; return portal; @@ -30,11 +26,7 @@ function postMessage(portal, ...postMessageArgs) { return new Promise((resolve, reject) => { portal.postMessage(...postMessageArgs); - var bc = new BroadcastChannel("portals-post-message"); - bc.onmessage = e => { - bc.close(); - resolve(e.data); - }; + portal.onmessage = e => { resolve(e.data); }; }); }
diff --git a/third_party/blink/web_tests/external/wpt/portals/resources/portal-activate-event-portal.html b/third_party/blink/web_tests/external/wpt/portals/resources/portal-activate-event-portal.html index b2759c3..63c2e6e 100644 --- a/third_party/blink/web_tests/external/wpt/portals/resources/portal-activate-event-portal.html +++ b/third_party/blink/web_tests/external/wpt/portals/resources/portal-activate-event-portal.html
@@ -17,7 +17,5 @@ window.addEventListener("portalactivate", portalActivate); } - var bc = new BroadcastChannel("portal-" + test); - bc.postMessage("loaded"); - bc.close(); + window.portalHost.postMessage("loaded", "*"); </script>
diff --git a/third_party/blink/web_tests/external/wpt/portals/resources/portal-embed-and-activate.html b/third_party/blink/web_tests/external/wpt/portals/resources/portal-embed-and-activate.html index 6b77a2bf..04f15b7 100644 --- a/third_party/blink/web_tests/external/wpt/portals/resources/portal-embed-and-activate.html +++ b/third_party/blink/web_tests/external/wpt/portals/resources/portal-embed-and-activate.html
@@ -1,26 +1,15 @@ <!DOCTYPE html> <!-- Embeds a portal (src specified by query parameter "url") and activates it after - receiving a message from the portal. Use query parameter "channelName" to - specify the name of the channel used by the portal src send a message - indicating that it is ready for activation (default name used is "portal"). + receiving a message from the portal. --> </title> <body> <script> var searchParams = new URL(location).searchParams; - - // TODO(adithyas): Replace this with postmessage once it's implemented for - // portals. - var channelName = searchParams.get("channelName") || "portal"; - var bc = new BroadcastChannel(channelName); - bc.onmessage = function(e) { - document.querySelector("portal").activate(); - bc.close(); - } - let portal = document.createElement("portal"); portal.src = searchParams.get("url"); + portal.onmessage = () => { portal.activate(); } document.body.appendChild(portal); </script> </body>
diff --git a/third_party/blink/web_tests/external/wpt/portals/resources/portal-forward-with-broadcast.html b/third_party/blink/web_tests/external/wpt/portals/resources/portal-forward-with-broadcast.html deleted file mode 100644 index 39bda69..0000000 --- a/third_party/blink/web_tests/external/wpt/portals/resources/portal-forward-with-broadcast.html +++ /dev/null
@@ -1,14 +0,0 @@ -<!DOCTYPE html> -<body> - <script> - function forwardMessage(e) { - let broadcastChannel = new BroadcastChannel(new URL(location).searchParams.get('broadcastchannel')); - try { - broadcastChannel.postMessage(e.data); - } finally { - broadcastChannel.close(); - } - } - window.addEventListener("message", forwardMessage); - </script> -</body>
diff --git a/third_party/blink/web_tests/external/wpt/portals/resources/portal-host-hidden-after-activation-portal.html b/third_party/blink/web_tests/external/wpt/portals/resources/portal-host-hidden-after-activation-portal.html index 586929e..75c8b73 100644 --- a/third_party/blink/web_tests/external/wpt/portals/resources/portal-host-hidden-after-activation-portal.html +++ b/third_party/blink/web_tests/external/wpt/portals/resources/portal-host-hidden-after-activation-portal.html
@@ -10,8 +10,5 @@ bc.postMessage({hasHost: !!window.portalHost }); bc.close(); - bc = new BroadcastChannel("portal"); - bc.postMessage("loaded"); - bc.close(); - + window.portalHost.postMessage("loaded", "*"); </script>
diff --git a/third_party/blink/web_tests/external/wpt/portals/resources/portal-host-post-message-after-activate.html b/third_party/blink/web_tests/external/wpt/portals/resources/portal-host-post-message-after-activate.html index 07db1a0..996380f 100644 --- a/third_party/blink/web_tests/external/wpt/portals/resources/portal-host-post-message-after-activate.html +++ b/third_party/blink/web_tests/external/wpt/portals/resources/portal-host-post-message-after-activate.html
@@ -1,8 +1,6 @@ <!DOCTYPE html> <script> - var bc = new BroadcastChannel("portal"); - bc.postMessage("loaded"); - bc.close(); + window.portalHost.postMessage("loaded", "*"); var ph = window.portalHost;
diff --git a/third_party/blink/web_tests/external/wpt/portals/resources/portal-post-message-after-activate-window.html b/third_party/blink/web_tests/external/wpt/portals/resources/portal-post-message-after-activate-window.html index d160fb2a..007f0f9 100644 --- a/third_party/blink/web_tests/external/wpt/portals/resources/portal-post-message-after-activate-window.html +++ b/third_party/blink/web_tests/external/wpt/portals/resources/portal-post-message-after-activate-window.html
@@ -5,9 +5,7 @@ portal.src = "portal-post-message-portal.html"; document.body.appendChild(portal); - var bc = new BroadcastChannel("portals-post-message"); - bc.onmessage = () => { - bc.close(); + portal.onmessage = () => { portal.activate().then(() => { error = ""; try {
diff --git a/third_party/blink/web_tests/external/wpt/portals/resources/portal-post-message-cross-origin-portal.sub.html b/third_party/blink/web_tests/external/wpt/portals/resources/portal-post-message-cross-origin-portal.sub.html deleted file mode 100644 index 577c10ac..0000000 --- a/third_party/blink/web_tests/external/wpt/portals/resources/portal-post-message-cross-origin-portal.sub.html +++ /dev/null
@@ -1,27 +0,0 @@ -<!DOCTYPE html> -<body> - <script> - let forwardingIframe = document.createElement('iframe'); - let channelName = new URL(location).searchParams.get('broadcastchannel'); - forwardingIframe.src = - `http://{{host}}:{{ports[http][0]}}/portals/resources/portal-forward-with-broadcast.html?broadcastchannel=portals-post-message`; - forwardingIframe.onload = () => { - forwardingIframe.contentWindow.postMessage("loaded", "*"); - } - document.body.appendChild(forwardingIframe); - - window.portalHost.addEventListener("message", e => { - var message = { - origin: e.origin, - data: e.data, - sourceIsPortalHost: e.source === window.portalHost - }; - if (e.ports.length > 0) { - e.ports[0].postMessage(message); - e.ports[0].close(); - return; - } - forwardingIframe.contentWindow.postMessage(message, "*"); - }); - </script> -</body>
diff --git a/third_party/blink/web_tests/external/wpt/portals/resources/portal-post-message-during-activate-window.html b/third_party/blink/web_tests/external/wpt/portals/resources/portal-post-message-during-activate-window.html index 6c77419..f588bda 100644 --- a/third_party/blink/web_tests/external/wpt/portals/resources/portal-post-message-during-activate-window.html +++ b/third_party/blink/web_tests/external/wpt/portals/resources/portal-post-message-during-activate-window.html
@@ -2,12 +2,10 @@ <body> <script> var portal = document.createElement("portal"); - portal.src = "portal-post-message-portal.html"; + portal.src = "simple-portal.html"; document.body.appendChild(portal); - var bc = new BroadcastChannel("portals-post-message"); - bc.onmessage = () => { - bc.close(); + portal.onmessage = () => { portal.activate(); error = ""; try {
diff --git a/third_party/blink/web_tests/external/wpt/portals/resources/portal-post-message-portal.html b/third_party/blink/web_tests/external/wpt/portals/resources/portal-post-message-portal.html index 1dae5d1..ccb87aaa 100644 --- a/third_party/blink/web_tests/external/wpt/portals/resources/portal-post-message-portal.html +++ b/third_party/blink/web_tests/external/wpt/portals/resources/portal-post-message-portal.html
@@ -1,8 +1,7 @@ <!DOCTYPE html> <script> - var bc = new BroadcastChannel("portals-post-message"); - bc.postMessage("loaded"); - bc.close(); + window.portalHost.postMessage("loaded", "*"); + window.portalHost.onmessage = e => { var message = { origin: e.origin, @@ -27,8 +26,6 @@ return; } - bc = new BroadcastChannel("portals-post-message"); - bc.postMessage(message); - bc.close(); + window.portalHost.postMessage(message, "*"); }; </script>
diff --git a/third_party/blink/web_tests/external/wpt/wake-lock/wakelock-disabled-by-feature-policy.https.sub-expected.txt b/third_party/blink/web_tests/external/wpt/wake-lock/wakelock-disabled-by-feature-policy.https.sub-expected.txt new file mode 100644 index 0000000..2f52225 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/wake-lock/wakelock-disabled-by-feature-policy.https.sub-expected.txt
@@ -0,0 +1,6 @@ +This is a testharness.js-based test. +FAIL Feature-Policy header {"wake-lock" : []} disallows the top-level document. assert_throws: function "() => new WakeLock("screen")" threw object "TypeError: Illegal constructor" that is not a DOMException NotAllowedError: property "code" is equal to undefined, expected 0 +PASS Feature-Policy header {"wake-lock" : []} disallows same-origin iframes. +PASS Feature-Policy header {"wake-lock" : []} disallows cross-origin iframes. +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/wake-lock/wakelock-disabled-by-feature-policy.https.sub.html b/third_party/blink/web_tests/external/wpt/wake-lock/wakelock-disabled-by-feature-policy.https.sub.html index ad7eeb0..008424a 100644 --- a/third_party/blink/web_tests/external/wpt/wake-lock/wakelock-disabled-by-feature-policy.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/wake-lock/wakelock-disabled-by-feature-policy.https.sub.html
@@ -11,13 +11,13 @@ const cross_origin_src = "https://{{domains[www]}}:{{ports[https][0]}}" + same_origin_src; - promise_test(t => { - return promise_rejects(t, "NotAllowedError", navigator.getWakeLock("screen")); + test(() => { + assert_throws("NotAllowedError", () => new WakeLock("screen")); }, 'Feature-Policy header {"wake-lock" : []} disallows the top-level document.'); async_test(t => { test_feature_availability( - 'navigator.getWakeLock("screen")', + 'new WakeLock("screen")', t, same_origin_src, expect_feature_unavailable_default @@ -26,7 +26,7 @@ async_test(t => { test_feature_availability( - 'navigator.getWakeLock("screen")', + 'new WakeLock("screen")', t, cross_origin_src, expect_feature_unavailable_default
diff --git a/third_party/blink/web_tests/external/wpt/wake-lock/wakelock-enabled-by-feature-policy-attribute-redirect-on-load.https.sub-expected.txt b/third_party/blink/web_tests/external/wpt/wake-lock/wakelock-enabled-by-feature-policy-attribute-redirect-on-load.https.sub-expected.txt new file mode 100644 index 0000000..05b307c --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/wake-lock/wakelock-enabled-by-feature-policy-attribute-redirect-on-load.https.sub-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +FAIL Feature-Policy allow="wake-lock" allows same-origin relocation assert_true: new WakeLock("screen") expected true got false +PASS Feature-Policy allow="wake-lock" disallows cross-origin relocation +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/wake-lock/wakelock-enabled-by-feature-policy-attribute-redirect-on-load.https.sub.html b/third_party/blink/web_tests/external/wpt/wake-lock/wakelock-enabled-by-feature-policy-attribute-redirect-on-load.https.sub.html index 74875937..d93eaa8 100644 --- a/third_party/blink/web_tests/external/wpt/wake-lock/wakelock-enabled-by-feature-policy-attribute-redirect-on-load.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/wake-lock/wakelock-enabled-by-feature-policy-attribute-redirect-on-load.https.sub.html
@@ -14,7 +14,7 @@ async_test(t => { test_feature_availability( - 'navigator.getWakeLock("screen")', + 'new WakeLock("screen")', t, same_origin_src, expect_feature_available_default, @@ -24,7 +24,7 @@ async_test(t => { test_feature_availability( - 'navigator.getWakeLock("screen")', + 'new WakeLock("screen")', t, cross_origin_src, expect_feature_unavailable_default,
diff --git a/third_party/blink/web_tests/external/wpt/wake-lock/wakelock-enabled-by-feature-policy-attribute.https.sub.html b/third_party/blink/web_tests/external/wpt/wake-lock/wakelock-enabled-by-feature-policy-attribute.https.sub.html index 185f5ad1..c0066e7 100644 --- a/third_party/blink/web_tests/external/wpt/wake-lock/wakelock-enabled-by-feature-policy-attribute.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/wake-lock/wakelock-enabled-by-feature-policy-attribute.https.sub.html
@@ -13,7 +13,7 @@ async_test(t => { test_feature_availability( - 'navigator.getWakeLock("screen")', + 'new WakeLock("screen")', t, same_origin_src, expect_feature_available_default, @@ -23,7 +23,7 @@ async_test(t => { test_feature_availability( - 'navigator.getWakeLock("screen")', + 'new WakeLock("screen")', t, cross_origin_src, expect_feature_available_default,
diff --git a/third_party/blink/web_tests/external/wpt/wake-lock/wakelock-enabled-by-feature-policy.https.sub-expected.txt b/third_party/blink/web_tests/external/wpt/wake-lock/wakelock-enabled-by-feature-policy.https.sub-expected.txt new file mode 100644 index 0000000..a0328ea9 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/wake-lock/wakelock-enabled-by-feature-policy.https.sub-expected.txt
@@ -0,0 +1,6 @@ +This is a testharness.js-based test. +FAIL Feature-Policy header {"wake-lock" : ["*"]} allows the top-level document. assert_unreached: TypeError: Illegal constructor Reached unreachable code +FAIL Feature-Policy header {"wake-lock" : ["*"]} allows same-origin iframes. assert_true: new WakeLock("screen") expected true got false +FAIL Feature-Policy header {"wake-lock" : ["*"]} allows cross-origin iframes. assert_true: new WakeLock("screen") expected true got false +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/wake-lock/wakelock-enabled-by-feature-policy.https.sub.html b/third_party/blink/web_tests/external/wpt/wake-lock/wakelock-enabled-by-feature-policy.https.sub.html index eb49be5..39a2af4 100644 --- a/third_party/blink/web_tests/external/wpt/wake-lock/wakelock-enabled-by-feature-policy.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/wake-lock/wakelock-enabled-by-feature-policy.https.sub.html
@@ -11,14 +11,17 @@ const cross_origin_src = "https://{{domains[www]}}:{{ports[https][0]}}" + same_origin_src; - promise_test( - () => navigator.getWakeLock("screen"), - 'Feature-Policy header {"wake-lock" : ["*"]} allows the top-level document.' - ); + test(() => { + try { + new WakeLock("screen"); + } catch (e) { + assert_unreached(e); + } + }, 'Feature-Policy header {"wake-lock" : ["*"]} allows the top-level document.'); async_test(t => { test_feature_availability( - 'navigator.getWakeLock("screen")', + 'new WakeLock("screen")', t, same_origin_src, expect_feature_available_default @@ -27,7 +30,7 @@ async_test(t => { test_feature_availability( - 'navigator.getWakeLock("screen")', + 'new WakeLock("screen")', t, cross_origin_src, expect_feature_available_default
diff --git a/third_party/blink/web_tests/external/wpt/wake-lock/wakelock-enabled-on-self-origin-by-feature-policy.https.sub-expected.txt b/third_party/blink/web_tests/external/wpt/wake-lock/wakelock-enabled-on-self-origin-by-feature-policy.https.sub-expected.txt new file mode 100644 index 0000000..060131b3 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/wake-lock/wakelock-enabled-on-self-origin-by-feature-policy.https.sub-expected.txt
@@ -0,0 +1,6 @@ +This is a testharness.js-based test. +FAIL Feature-Policy header wake-lock "self" allows the top-level document. assert_unreached: TypeError: Illegal constructor Reached unreachable code +FAIL Feature-Policy header wake-lock "self" allows same-origin iframes. assert_true: new WakeLock("screen") expected true got false +PASS Feature-Policy header wake-lock "self" disallows cross-origin iframes. +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/wake-lock/wakelock-enabled-on-self-origin-by-feature-policy.https.sub.html b/third_party/blink/web_tests/external/wpt/wake-lock/wakelock-enabled-on-self-origin-by-feature-policy.https.sub.html index a0c25525..ab81d40 100644 --- a/third_party/blink/web_tests/external/wpt/wake-lock/wakelock-enabled-on-self-origin-by-feature-policy.https.sub.html +++ b/third_party/blink/web_tests/external/wpt/wake-lock/wakelock-enabled-on-self-origin-by-feature-policy.https.sub.html
@@ -12,13 +12,17 @@ const cross_origin_src = "https://{{domains[www]}}:{{ports[https][0]}}" + same_origin_src; - promise_test(t => { - return navigator.getWakeLock("screen"); + test(t => { + try { + new WakeLock("screen"); + } catch (e) { + assert_unreached(e); + } }, 'Feature-Policy header wake-lock "self" allows the top-level document.'); async_test(t => { test_feature_availability( - 'navigator.getWakeLock("screen")', + 'new WakeLock("screen")', t, same_origin_src, expect_feature_available_default @@ -27,7 +31,7 @@ async_test(t => { test_feature_availability( - 'navigator.getWakeLock("screen")', + 'new WakeLock("screen")', t, cross_origin_src, expect_feature_unavailable_default
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCDtlsTransport-getRemoteCertificates-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/RTCDtlsTransport-getRemoteCertificates-expected.txt deleted file mode 100644 index e4e58c43..0000000 --- a/third_party/blink/web_tests/external/wpt/webrtc/RTCDtlsTransport-getRemoteCertificates-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -FAIL RTCDtlsTransport.prototype.getRemoteCertificates dtlsTransport.getCertificates is not a function -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCDtlsTransport-getRemoteCertificates.html b/third_party/blink/web_tests/external/wpt/webrtc/RTCDtlsTransport-getRemoteCertificates.html index 0614364e..4735b75 100644 --- a/third_party/blink/web_tests/external/wpt/webrtc/RTCDtlsTransport-getRemoteCertificates.html +++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCDtlsTransport-getRemoteCertificates.html
@@ -87,7 +87,7 @@ if(dtlsTransport.state === 'connected') { onConnected(dtlsTransport); } else { - assert_array_equals(dtlsTransport.getCertificates(), [], + assert_array_equals(dtlsTransport.getRemoteCertificates(), [], 'Expect DTLS certificates be initially empty until become connected'); dtlsTransport.addEventListener('statechange', t.step_func(() => {
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/idlharness.https.window-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/idlharness.https.window-expected.txt index 5e62ee6..3b456b53 100644 --- a/third_party/blink/web_tests/external/wpt/webrtc/idlharness.https.window-expected.txt +++ b/third_party/blink/web_tests/external/wpt/webrtc/idlharness.https.window-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 506 tests; 442 PASS, 64 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 506 tests; 444 PASS, 62 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS idl_test setup PASS Test driver for asyncInitCertificate PASS Test driver for asyncInitTransports @@ -312,14 +312,14 @@ PASS RTCDtlsTransport interface: existence and properties of interface prototype object's @@unscopables property PASS RTCDtlsTransport interface: attribute iceTransport PASS RTCDtlsTransport interface: attribute state -FAIL RTCDtlsTransport interface: operation getRemoteCertificates() assert_own_property: interface prototype object missing non-static operation expected property "getRemoteCertificates" missing +PASS RTCDtlsTransport interface: operation getRemoteCertificates() PASS RTCDtlsTransport interface: attribute onstatechange PASS RTCDtlsTransport interface: attribute onerror PASS RTCDtlsTransport must be primary interface of idlTestObjects.dtlsTransport PASS Stringification of idlTestObjects.dtlsTransport PASS RTCDtlsTransport interface: idlTestObjects.dtlsTransport must inherit property "iceTransport" with the proper type PASS RTCDtlsTransport interface: idlTestObjects.dtlsTransport must inherit property "state" with the proper type -FAIL RTCDtlsTransport interface: idlTestObjects.dtlsTransport must inherit property "getRemoteCertificates()" with the proper type assert_inherits: property "getRemoteCertificates" not found in prototype chain +PASS RTCDtlsTransport interface: idlTestObjects.dtlsTransport must inherit property "getRemoteCertificates()" with the proper type PASS RTCDtlsTransport interface: idlTestObjects.dtlsTransport must inherit property "onstatechange" with the proper type PASS RTCDtlsTransport interface: idlTestObjects.dtlsTransport must inherit property "onerror" with the proper type FAIL RTCIceTransport interface: existence and properties of interface object assert_throws: interface object didn't throw TypeError when called as a constructor function "function() {
diff --git a/third_party/blink/web_tests/fast/shapes/parsing/parsing-shape-outside-expected.txt b/third_party/blink/web_tests/fast/shapes/parsing/parsing-shape-outside-expected.txt index 3a310a4..2a993e7 100644 --- a/third_party/blink/web_tests/fast/shapes/parsing/parsing-shape-outside-expected.txt +++ b/third_party/blink/web_tests/fast/shapes/parsing/parsing-shape-outside-expected.txt
@@ -156,13 +156,13 @@ PASS getComputedStyleValue("shape-outside", "polygon(nonzero, 10px 10px, 20px 20px, 30px 30px) border-box") is "polygon(10px 10px, 20px 20px, 30px 30px) border-box" PASS getCSSText("shape-outside", "polygon(nonzero, 10px 10px, 20px 20px, 30px 30px) margin-box") is "polygon(10px 10px, 20px 20px, 30px 30px) margin-box" PASS getComputedStyleValue("shape-outside", "polygon(nonzero, 10px 10px, 20px 20px, 30px 30px) margin-box") is "polygon(10px 10px, 20px 20px, 30px 30px) margin-box" -PASS getCSSText("shape-outside", "content-box polygon(nonzero, 10px 10px, 20px 20px, 30px 30px)") is "content-box polygon(10px 10px, 20px 20px, 30px 30px)" +PASS getCSSText("shape-outside", "content-box polygon(nonzero, 10px 10px, 20px 20px, 30px 30px)") is "polygon(10px 10px, 20px 20px, 30px 30px) content-box" PASS getComputedStyleValue("shape-outside", "content-box polygon(nonzero, 10px 10px, 20px 20px, 30px 30px)") is "polygon(10px 10px, 20px 20px, 30px 30px) content-box" -PASS getCSSText("shape-outside", "padding-box polygon(nonzero, 10px 10px, 20px 20px, 30px 30px)") is "padding-box polygon(10px 10px, 20px 20px, 30px 30px)" +PASS getCSSText("shape-outside", "padding-box polygon(nonzero, 10px 10px, 20px 20px, 30px 30px)") is "polygon(10px 10px, 20px 20px, 30px 30px) padding-box" PASS getComputedStyleValue("shape-outside", "padding-box polygon(nonzero, 10px 10px, 20px 20px, 30px 30px)") is "polygon(10px 10px, 20px 20px, 30px 30px) padding-box" -PASS getCSSText("shape-outside", "border-box polygon(nonzero, 10px 10px, 20px 20px, 30px 30px)") is "border-box polygon(10px 10px, 20px 20px, 30px 30px)" +PASS getCSSText("shape-outside", "border-box polygon(nonzero, 10px 10px, 20px 20px, 30px 30px)") is "polygon(10px 10px, 20px 20px, 30px 30px) border-box" PASS getComputedStyleValue("shape-outside", "border-box polygon(nonzero, 10px 10px, 20px 20px, 30px 30px)") is "polygon(10px 10px, 20px 20px, 30px 30px) border-box" -PASS getCSSText("shape-outside", "margin-box polygon(nonzero, 10px 10px, 20px 20px, 30px 30px)") is "margin-box polygon(10px 10px, 20px 20px, 30px 30px)" +PASS getCSSText("shape-outside", "margin-box polygon(nonzero, 10px 10px, 20px 20px, 30px 30px)") is "polygon(10px 10px, 20px 20px, 30px 30px) margin-box" PASS getComputedStyleValue("shape-outside", "margin-box polygon(nonzero, 10px 10px, 20px 20px, 30px 30px)") is "polygon(10px 10px, 20px 20px, 30px 30px) margin-box" PASS getCSSText("shape-outside", "linear-gradient(to right, red, blue)") is "linear-gradient(to right, red, blue)" PASS getComputedStyleValue("shape-outside", "linear-gradient(to right, red, blue)") is "linear-gradient(to right, red, blue)"
diff --git a/third_party/blink/web_tests/fast/shapes/parsing/parsing-test-utils.js b/third_party/blink/web_tests/fast/shapes/parsing/parsing-test-utils.js index 5a6e3ac..37e67daf 100644 --- a/third_party/blink/web_tests/fast/shapes/parsing/parsing-test-utils.js +++ b/third_party/blink/web_tests/fast/shapes/parsing/parsing-test-utils.js
@@ -90,10 +90,10 @@ ["polygon(nonzero, 10px 10px, 20px 20px, 30px 30px) border-box", "polygon(10px 10px, 20px 20px, 30px 30px) border-box"], ["polygon(nonzero, 10px 10px, 20px 20px, 30px 30px) margin-box", "polygon(10px 10px, 20px 20px, 30px 30px) margin-box"], - ["content-box polygon(nonzero, 10px 10px, 20px 20px, 30px 30px)", "content-box polygon(10px 10px, 20px 20px, 30px 30px)", "polygon(10px 10px, 20px 20px, 30px 30px) content-box"], - ["padding-box polygon(nonzero, 10px 10px, 20px 20px, 30px 30px)", "padding-box polygon(10px 10px, 20px 20px, 30px 30px)", "polygon(10px 10px, 20px 20px, 30px 30px) padding-box"], - ["border-box polygon(nonzero, 10px 10px, 20px 20px, 30px 30px)", "border-box polygon(10px 10px, 20px 20px, 30px 30px)", "polygon(10px 10px, 20px 20px, 30px 30px) border-box"], - ["margin-box polygon(nonzero, 10px 10px, 20px 20px, 30px 30px)", "margin-box polygon(10px 10px, 20px 20px, 30px 30px)", "polygon(10px 10px, 20px 20px, 30px 30px) margin-box"], + ["content-box polygon(nonzero, 10px 10px, 20px 20px, 30px 30px)", "polygon(10px 10px, 20px 20px, 30px 30px) content-box", "polygon(10px 10px, 20px 20px, 30px 30px) content-box"], + ["padding-box polygon(nonzero, 10px 10px, 20px 20px, 30px 30px)", "polygon(10px 10px, 20px 20px, 30px 30px) padding-box", "polygon(10px 10px, 20px 20px, 30px 30px) padding-box"], + ["border-box polygon(nonzero, 10px 10px, 20px 20px, 30px 30px)", "polygon(10px 10px, 20px 20px, 30px 30px) border-box", "polygon(10px 10px, 20px 20px, 30px 30px) border-box"], + ["margin-box polygon(nonzero, 10px 10px, 20px 20px, 30px 30px)", "polygon(10px 10px, 20px 20px, 30px 30px) margin-box", "polygon(10px 10px, 20px 20px, 30px 30px) margin-box"], "linear-gradient(to right, red, blue)", "radial-gradient(at 10px 20px, red 0%, blue 50%, green 95%)",
diff --git a/third_party/blink/web_tests/fragmentation/break-properties-expected.txt b/third_party/blink/web_tests/fragmentation/break-properties-expected.txt index f88be051..f18b6e8 100644 --- a/third_party/blink/web_tests/fragmentation/break-properties-expected.txt +++ b/third_party/blink/web_tests/fragmentation/break-properties-expected.txt
@@ -17,35 +17,35 @@ break-after:avoid-column PASS getComputedStyle(element)['break-after'] is "avoid-column" PASS getComputedStyle(element)['-webkit-column-break-after'] is "avoid" -PASS getComputedStyle(element)['page-break-after'] is "auto" +PASS getComputedStyle(element)['page-break-after'] is "" break-after:avoid-page PASS getComputedStyle(element)['break-after'] is "avoid-page" -PASS getComputedStyle(element)['-webkit-column-break-after'] is "auto" -PASS getComputedStyle(element)['page-break-after'] is "avoid" +PASS getComputedStyle(element)['-webkit-column-break-after'] is "" +PASS getComputedStyle(element)['page-break-after'] is "" break-after:column PASS getComputedStyle(element)['break-after'] is "column" PASS getComputedStyle(element)['-webkit-column-break-after'] is "always" -PASS getComputedStyle(element)['page-break-after'] is "auto" +PASS getComputedStyle(element)['page-break-after'] is "" break-after:left PASS getComputedStyle(element)['break-after'] is "left" -PASS getComputedStyle(element)['-webkit-column-break-after'] is "auto" +PASS getComputedStyle(element)['-webkit-column-break-after'] is "" PASS getComputedStyle(element)['page-break-after'] is "left" break-after:page PASS getComputedStyle(element)['break-after'] is "page" -PASS getComputedStyle(element)['-webkit-column-break-after'] is "auto" +PASS getComputedStyle(element)['-webkit-column-break-after'] is "" PASS getComputedStyle(element)['page-break-after'] is "always" break-after:recto PASS getComputedStyle(element)['break-after'] is "recto" -PASS getComputedStyle(element)['-webkit-column-break-after'] is "auto" -PASS getComputedStyle(element)['page-break-after'] is "auto" +PASS getComputedStyle(element)['-webkit-column-break-after'] is "" +PASS getComputedStyle(element)['page-break-after'] is "" break-after:right PASS getComputedStyle(element)['break-after'] is "right" -PASS getComputedStyle(element)['-webkit-column-break-after'] is "auto" +PASS getComputedStyle(element)['-webkit-column-break-after'] is "" PASS getComputedStyle(element)['page-break-after'] is "right" break-after:verso PASS getComputedStyle(element)['break-after'] is "verso" -PASS getComputedStyle(element)['-webkit-column-break-after'] is "auto" -PASS getComputedStyle(element)['page-break-after'] is "auto" +PASS getComputedStyle(element)['-webkit-column-break-after'] is "" +PASS getComputedStyle(element)['page-break-after'] is "" break-before:always PASS getComputedStyle(element)['break-before'] is "auto" PASS getComputedStyle(element)['-webkit-column-break-before'] is "auto" @@ -61,35 +61,35 @@ break-before:avoid-column PASS getComputedStyle(element)['break-before'] is "avoid-column" PASS getComputedStyle(element)['-webkit-column-break-before'] is "avoid" -PASS getComputedStyle(element)['page-break-before'] is "auto" +PASS getComputedStyle(element)['page-break-before'] is "" break-before:avoid-page PASS getComputedStyle(element)['break-before'] is "avoid-page" -PASS getComputedStyle(element)['-webkit-column-break-before'] is "auto" -PASS getComputedStyle(element)['page-break-before'] is "avoid" +PASS getComputedStyle(element)['-webkit-column-break-before'] is "" +PASS getComputedStyle(element)['page-break-before'] is "" break-before:column PASS getComputedStyle(element)['break-before'] is "column" PASS getComputedStyle(element)['-webkit-column-break-before'] is "always" -PASS getComputedStyle(element)['page-break-before'] is "auto" +PASS getComputedStyle(element)['page-break-before'] is "" break-before:left PASS getComputedStyle(element)['break-before'] is "left" -PASS getComputedStyle(element)['-webkit-column-break-before'] is "auto" +PASS getComputedStyle(element)['-webkit-column-break-before'] is "" PASS getComputedStyle(element)['page-break-before'] is "left" break-before:page PASS getComputedStyle(element)['break-before'] is "page" -PASS getComputedStyle(element)['-webkit-column-break-before'] is "auto" +PASS getComputedStyle(element)['-webkit-column-break-before'] is "" PASS getComputedStyle(element)['page-break-before'] is "always" break-before:recto PASS getComputedStyle(element)['break-before'] is "recto" -PASS getComputedStyle(element)['-webkit-column-break-before'] is "auto" -PASS getComputedStyle(element)['page-break-before'] is "auto" +PASS getComputedStyle(element)['-webkit-column-break-before'] is "" +PASS getComputedStyle(element)['page-break-before'] is "" break-before:right PASS getComputedStyle(element)['break-before'] is "right" -PASS getComputedStyle(element)['-webkit-column-break-before'] is "auto" +PASS getComputedStyle(element)['-webkit-column-break-before'] is "" PASS getComputedStyle(element)['page-break-before'] is "right" break-before:verso PASS getComputedStyle(element)['break-before'] is "verso" -PASS getComputedStyle(element)['-webkit-column-break-before'] is "auto" -PASS getComputedStyle(element)['page-break-before'] is "auto" +PASS getComputedStyle(element)['-webkit-column-break-before'] is "" +PASS getComputedStyle(element)['page-break-before'] is "" break-inside:auto PASS getComputedStyle(element)['break-inside'] is "auto" PASS getComputedStyle(element)['-webkit-column-break-inside'] is "auto" @@ -101,15 +101,15 @@ break-inside:avoid-column PASS getComputedStyle(element)['break-inside'] is "avoid-column" PASS getComputedStyle(element)['-webkit-column-break-inside'] is "avoid" -PASS getComputedStyle(element)['page-break-inside'] is "auto" +PASS getComputedStyle(element)['page-break-inside'] is "" break-inside:avoid-page PASS getComputedStyle(element)['break-inside'] is "avoid-page" -PASS getComputedStyle(element)['-webkit-column-break-inside'] is "auto" +PASS getComputedStyle(element)['-webkit-column-break-inside'] is "" PASS getComputedStyle(element)['page-break-inside'] is "avoid" -webkit-column-break-after:always PASS getComputedStyle(element)['break-after'] is "column" PASS getComputedStyle(element)['-webkit-column-break-after'] is "always" -PASS getComputedStyle(element)['page-break-after'] is "auto" +PASS getComputedStyle(element)['page-break-after'] is "" -webkit-column-break-after:avoid PASS getComputedStyle(element)['break-after'] is "avoid" PASS getComputedStyle(element)['-webkit-column-break-after'] is "avoid" @@ -121,7 +121,7 @@ -webkit-column-break-before:always PASS getComputedStyle(element)['break-before'] is "column" PASS getComputedStyle(element)['-webkit-column-break-before'] is "always" -PASS getComputedStyle(element)['page-break-before'] is "auto" +PASS getComputedStyle(element)['page-break-before'] is "" -webkit-column-break-before:avoid PASS getComputedStyle(element)['break-before'] is "avoid" PASS getComputedStyle(element)['-webkit-column-break-before'] is "avoid" @@ -140,7 +140,7 @@ PASS getComputedStyle(element)['page-break-before'] is "auto" page-break-after:always PASS getComputedStyle(element)['break-after'] is "page" -PASS getComputedStyle(element)['-webkit-column-break-after'] is "auto" +PASS getComputedStyle(element)['-webkit-column-break-after'] is "" PASS getComputedStyle(element)['page-break-after'] is "always" page-break-after:avoid PASS getComputedStyle(element)['break-after'] is "avoid" @@ -148,11 +148,11 @@ PASS getComputedStyle(element)['page-break-after'] is "avoid" page-break-after:left PASS getComputedStyle(element)['break-after'] is "left" -PASS getComputedStyle(element)['-webkit-column-break-after'] is "auto" +PASS getComputedStyle(element)['-webkit-column-break-after'] is "" PASS getComputedStyle(element)['page-break-after'] is "left" page-break-after:right PASS getComputedStyle(element)['break-after'] is "right" -PASS getComputedStyle(element)['-webkit-column-break-after'] is "auto" +PASS getComputedStyle(element)['-webkit-column-break-after'] is "" PASS getComputedStyle(element)['page-break-after'] is "right" page-break-after:verso PASS getComputedStyle(element)['break-after'] is "auto" @@ -160,7 +160,7 @@ PASS getComputedStyle(element)['page-break-after'] is "auto" page-break-before:always PASS getComputedStyle(element)['break-before'] is "page" -PASS getComputedStyle(element)['-webkit-column-break-before'] is "auto" +PASS getComputedStyle(element)['-webkit-column-break-before'] is "" PASS getComputedStyle(element)['page-break-before'] is "always" page-break-before:avoid PASS getComputedStyle(element)['break-before'] is "avoid" @@ -168,11 +168,11 @@ PASS getComputedStyle(element)['page-break-before'] is "avoid" page-break-before:left PASS getComputedStyle(element)['break-before'] is "left" -PASS getComputedStyle(element)['-webkit-column-break-before'] is "auto" +PASS getComputedStyle(element)['-webkit-column-break-before'] is "" PASS getComputedStyle(element)['page-break-before'] is "left" page-break-before:right PASS getComputedStyle(element)['break-before'] is "right" -PASS getComputedStyle(element)['-webkit-column-break-before'] is "auto" +PASS getComputedStyle(element)['-webkit-column-break-before'] is "" PASS getComputedStyle(element)['page-break-before'] is "right" page-break-before:verso PASS getComputedStyle(element)['break-before'] is "auto"
diff --git a/third_party/blink/web_tests/fragmentation/break-properties.html b/third_party/blink/web_tests/fragmentation/break-properties.html index 7d7762db..b905e4a1 100644 --- a/third_party/blink/web_tests/fragmentation/break-properties.html +++ b/third_party/blink/web_tests/fragmentation/break-properties.html
@@ -7,46 +7,46 @@ var tests = [["break-after:always", ["break-after", "auto"], ["-webkit-column-break-after", "auto"], ["page-break-after", "auto"]], // Invalid declaration ["break-after:auto", ["break-after", "auto"], ["-webkit-column-break-after", "auto"], ["page-break-after", "auto"]], ["break-after:avoid", ["break-after", "avoid"], ["-webkit-column-break-after", "avoid"], ["page-break-after", "avoid"]], - ["break-after:avoid-column", ["break-after", "avoid-column"], ["-webkit-column-break-after", "avoid"], ["page-break-after", "auto"]], - ["break-after:avoid-page", ["break-after", "avoid-page"], ["-webkit-column-break-after", "auto"], ["page-break-after", "avoid"]], - ["break-after:column", ["break-after", "column"], ["-webkit-column-break-after", "always"], ["page-break-after", "auto"]], - ["break-after:left", ["break-after", "left"], ["-webkit-column-break-after", "auto"], ["page-break-after", "left"]], - ["break-after:page", ["break-after", "page"], ["-webkit-column-break-after", "auto"], ["page-break-after", "always"]], - ["break-after:recto", ["break-after", "recto"], ["-webkit-column-break-after", "auto"], ["page-break-after", "auto"]], - ["break-after:right", ["break-after", "right"], ["-webkit-column-break-after", "auto"], ["page-break-after", "right"]], - ["break-after:verso", ["break-after", "verso"], ["-webkit-column-break-after", "auto"], ["page-break-after", "auto"]], + ["break-after:avoid-column", ["break-after", "avoid-column"], ["-webkit-column-break-after", "avoid"], ["page-break-after", ""]], + ["break-after:avoid-page", ["break-after", "avoid-page"], ["-webkit-column-break-after", ""], ["page-break-after", ""]], + ["break-after:column", ["break-after", "column"], ["-webkit-column-break-after", "always"], ["page-break-after", ""]], + ["break-after:left", ["break-after", "left"], ["-webkit-column-break-after", ""], ["page-break-after", "left"]], + ["break-after:page", ["break-after", "page"], ["-webkit-column-break-after", ""], ["page-break-after", "always"]], + ["break-after:recto", ["break-after", "recto"], ["-webkit-column-break-after", ""], ["page-break-after", ""]], + ["break-after:right", ["break-after", "right"], ["-webkit-column-break-after", ""], ["page-break-after", "right"]], + ["break-after:verso", ["break-after", "verso"], ["-webkit-column-break-after", ""], ["page-break-after", ""]], ["break-before:always", ["break-before", "auto"], ["-webkit-column-break-before", "auto"], ["page-break-before", "auto"]], // Invalid declaration ["break-before:auto", ["break-before", "auto"], ["-webkit-column-break-before", "auto"], ["page-break-before", "auto"]], ["break-before:avoid", ["break-before", "avoid"], ["-webkit-column-break-before", "avoid"], ["page-break-before", "avoid"]], - ["break-before:avoid-column", ["break-before", "avoid-column"], ["-webkit-column-break-before", "avoid"], ["page-break-before", "auto"]], - ["break-before:avoid-page", ["break-before", "avoid-page"], ["-webkit-column-break-before", "auto"], ["page-break-before", "avoid"]], - ["break-before:column", ["break-before", "column"], ["-webkit-column-break-before", "always"], ["page-break-before", "auto"]], - ["break-before:left", ["break-before", "left"], ["-webkit-column-break-before", "auto"], ["page-break-before", "left"]], - ["break-before:page", ["break-before", "page"], ["-webkit-column-break-before", "auto"], ["page-break-before", "always"]], - ["break-before:recto", ["break-before", "recto"], ["-webkit-column-break-before", "auto"], ["page-break-before", "auto"]], - ["break-before:right", ["break-before", "right"], ["-webkit-column-break-before", "auto"], ["page-break-before", "right"]], - ["break-before:verso", ["break-before", "verso"], ["-webkit-column-break-before", "auto"], ["page-break-before", "auto"]], + ["break-before:avoid-column", ["break-before", "avoid-column"], ["-webkit-column-break-before", "avoid"], ["page-break-before", ""]], + ["break-before:avoid-page", ["break-before", "avoid-page"], ["-webkit-column-break-before", ""], ["page-break-before", ""]], + ["break-before:column", ["break-before", "column"], ["-webkit-column-break-before", "always"], ["page-break-before", ""]], + ["break-before:left", ["break-before", "left"], ["-webkit-column-break-before", ""], ["page-break-before", "left"]], + ["break-before:page", ["break-before", "page"], ["-webkit-column-break-before", ""], ["page-break-before", "always"]], + ["break-before:recto", ["break-before", "recto"], ["-webkit-column-break-before", ""], ["page-break-before", ""]], + ["break-before:right", ["break-before", "right"], ["-webkit-column-break-before", ""], ["page-break-before", "right"]], + ["break-before:verso", ["break-before", "verso"], ["-webkit-column-break-before", ""], ["page-break-before", ""]], ["break-inside:auto", ["break-inside", "auto"], ["-webkit-column-break-inside", "auto"], ["page-break-inside", "auto"]], ["break-inside:avoid", ["break-inside", "avoid"], ["-webkit-column-break-inside", "avoid"], ["page-break-inside", "avoid"]], - ["break-inside:avoid-column", ["break-inside", "avoid-column"], ["-webkit-column-break-inside", "avoid"], ["page-break-inside", "auto"]], - ["break-inside:avoid-page", ["break-inside", "avoid-page"], ["-webkit-column-break-inside", "auto"], ["page-break-inside", "avoid"]], - ["-webkit-column-break-after:always", ["break-after", "column"], ["-webkit-column-break-after", "always"], ["page-break-after", "auto"]], + ["break-inside:avoid-column", ["break-inside", "avoid-column"], ["-webkit-column-break-inside", "avoid"], ["page-break-inside", ""]], + ["break-inside:avoid-page", ["break-inside", "avoid-page"], ["-webkit-column-break-inside", ""], ["page-break-inside", "avoid"]], + ["-webkit-column-break-after:always", ["break-after", "column"], ["-webkit-column-break-after", "always"], ["page-break-after", ""]], ["-webkit-column-break-after:avoid", ["break-after", "avoid"], ["-webkit-column-break-after", "avoid"], ["page-break-after", "avoid"]], ["-webkit-column-break-after:column", ["break-after", "auto"], ["-webkit-column-break-after", "auto"], ["page-break-after", "auto"]], // Invalid declaration - ["-webkit-column-break-before:always", ["break-before", "column"], ["-webkit-column-break-before", "always"], ["page-break-before", "auto"]], + ["-webkit-column-break-before:always", ["break-before", "column"], ["-webkit-column-break-before", "always"], ["page-break-before", ""]], ["-webkit-column-break-before:avoid", ["break-before", "avoid"], ["-webkit-column-break-before", "avoid"], ["page-break-before", "avoid"]], ["-webkit-column-break-before:column", ["break-before", "auto"], ["-webkit-column-break-before", "auto"], ["page-break-before", "auto"]], // Invalid declaration ["-webkit-column-break-inside:avoid", ["break-inside", "avoid"], ["-webkit-column-break-inside", "avoid"], ["page-break-inside", "avoid"]], ["-webkit-column-break-before:avoid-column", ["break-before", "auto"], ["-webkit-column-break-before", "auto"], ["page-break-before", "auto"]], // Invalid declaration - ["page-break-after:always", ["break-after", "page"], ["-webkit-column-break-after", "auto"], ["page-break-after", "always"]], + ["page-break-after:always", ["break-after", "page"], ["-webkit-column-break-after", ""], ["page-break-after", "always"]], ["page-break-after:avoid", ["break-after", "avoid"], ["-webkit-column-break-after", "avoid"], ["page-break-after", "avoid"]], - ["page-break-after:left", ["break-after", "left"], ["-webkit-column-break-after", "auto"], ["page-break-after", "left"]], - ["page-break-after:right", ["break-after", "right"], ["-webkit-column-break-after", "auto"], ["page-break-after", "right"]], + ["page-break-after:left", ["break-after", "left"], ["-webkit-column-break-after", ""], ["page-break-after", "left"]], + ["page-break-after:right", ["break-after", "right"], ["-webkit-column-break-after", ""], ["page-break-after", "right"]], ["page-break-after:verso", ["break-after", "auto"], ["-webkit-column-break-after", "auto"], ["page-break-after", "auto"]], // Invalid declaration - ["page-break-before:always", ["break-before", "page"], ["-webkit-column-break-before", "auto"], ["page-break-before", "always"]], + ["page-break-before:always", ["break-before", "page"], ["-webkit-column-break-before", ""], ["page-break-before", "always"]], ["page-break-before:avoid", ["break-before", "avoid"], ["-webkit-column-break-before", "avoid"], ["page-break-before", "avoid"]], - ["page-break-before:left", ["break-before", "left"], ["-webkit-column-break-before", "auto"], ["page-break-before", "left"]], - ["page-break-before:right", ["break-before", "right"], ["-webkit-column-break-before", "auto"], ["page-break-before", "right"]], + ["page-break-before:left", ["break-before", "left"], ["-webkit-column-break-before", ""], ["page-break-before", "left"]], + ["page-break-before:right", ["break-before", "right"], ["-webkit-column-break-before", ""], ["page-break-before", "right"]], ["page-break-before:verso", ["break-before", "auto"], ["-webkit-column-break-before", "auto"], ["page-break-before", "auto"]], // Invalid declaration ["page-break-inside:always", ["break-before", "auto"], ["-webkit-column-break-before", "auto"], ["page-break-before", "auto"]], // Invalid declaration ["page-break-inside:avoid", ["break-inside", "avoid"], ["-webkit-column-break-inside", "avoid"], ["page-break-inside", "avoid"]],
diff --git a/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt index cab535d..8637a2df 100644 --- a/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt +++ b/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -982,6 +982,7 @@ getter paymentRequestOrigin getter topOrigin getter total + method changePaymentMethod method constructor method openWindow method respondWith
diff --git a/third_party/blink/web_tests/platform/linux/external/wpt/wake-lock/wakelock-enabled-by-feature-policy-attribute.https.sub-expected.txt b/third_party/blink/web_tests/platform/linux/external/wpt/wake-lock/wakelock-enabled-by-feature-policy-attribute.https.sub-expected.txt new file mode 100644 index 0000000..6c24b217 --- /dev/null +++ b/third_party/blink/web_tests/platform/linux/external/wpt/wake-lock/wakelock-enabled-by-feature-policy-attribute.https.sub-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +FAIL Feature policy "wake-lock" can be enabled in same-origin iframe using allow="wake-lock" attribute assert_true: new WakeLock("screen") expected true got false +FAIL Feature policy "wake-lock" can be enabled in cross-origin iframe using allow="wake-lock" attribute assert_true: new WakeLock("screen") expected true got false +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/wake-lock/wakelock-enabled-by-feature-policy-attribute.https.sub-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/wake-lock/wakelock-enabled-by-feature-policy-attribute.https.sub-expected.txt new file mode 100644 index 0000000..6c24b217 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.10/external/wpt/wake-lock/wakelock-enabled-by-feature-policy-attribute.https.sub-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +FAIL Feature policy "wake-lock" can be enabled in same-origin iframe using allow="wake-lock" attribute assert_true: new WakeLock("screen") expected true got false +FAIL Feature policy "wake-lock" can be enabled in cross-origin iframe using allow="wake-lock" attribute assert_true: new WakeLock("screen") expected true got false +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/external/wpt/wake-lock/wakelock-enabled-by-feature-policy-attribute.https.sub-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.11/external/wpt/wake-lock/wakelock-enabled-by-feature-policy-attribute.https.sub-expected.txt new file mode 100644 index 0000000..6c24b217 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.11/external/wpt/wake-lock/wakelock-enabled-by-feature-policy-attribute.https.sub-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +FAIL Feature policy "wake-lock" can be enabled in same-origin iframe using allow="wake-lock" attribute assert_true: new WakeLock("screen") expected true got false +FAIL Feature policy "wake-lock" can be enabled in cross-origin iframe using allow="wake-lock" attribute assert_true: new WakeLock("screen") expected true got false +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/wake-lock/wakelock-enabled-by-feature-policy-attribute.https.sub-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/wake-lock/wakelock-enabled-by-feature-policy-attribute.https.sub-expected.txt new file mode 100644 index 0000000..6c24b217 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.12/external/wpt/wake-lock/wakelock-enabled-by-feature-policy-attribute.https.sub-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +FAIL Feature policy "wake-lock" can be enabled in same-origin iframe using allow="wake-lock" attribute assert_true: new WakeLock("screen") expected true got false +FAIL Feature policy "wake-lock" can be enabled in cross-origin iframe using allow="wake-lock" attribute assert_true: new WakeLock("screen") expected true got false +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/mac-retina/external/wpt/wake-lock/wakelock-enabled-by-feature-policy-attribute.https.sub-expected.txt b/third_party/blink/web_tests/platform/mac-retina/external/wpt/wake-lock/wakelock-enabled-by-feature-policy-attribute.https.sub-expected.txt new file mode 100644 index 0000000..6c24b217 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-retina/external/wpt/wake-lock/wakelock-enabled-by-feature-policy-attribute.https.sub-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +FAIL Feature policy "wake-lock" can be enabled in same-origin iframe using allow="wake-lock" attribute assert_true: new WakeLock("screen") expected true got false +FAIL Feature policy "wake-lock" can be enabled in cross-origin iframe using allow="wake-lock" attribute assert_true: new WakeLock("screen") expected true got false +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/mac/external/wpt/wake-lock/wakelock-enabled-by-feature-policy-attribute.https.sub-expected.txt b/third_party/blink/web_tests/platform/mac/external/wpt/wake-lock/wakelock-enabled-by-feature-policy-attribute.https.sub-expected.txt new file mode 100644 index 0000000..6c24b217 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac/external/wpt/wake-lock/wakelock-enabled-by-feature-policy-attribute.https.sub-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +FAIL Feature policy "wake-lock" can be enabled in same-origin iframe using allow="wake-lock" attribute assert_true: new WakeLock("screen") expected true got false +FAIL Feature policy "wake-lock" can be enabled in cross-origin iframe using allow="wake-lock" attribute assert_true: new WakeLock("screen") expected true got false +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/win/external/wpt/wake-lock/wakelock-enabled-by-feature-policy-attribute.https.sub-expected.txt b/third_party/blink/web_tests/platform/win/external/wpt/wake-lock/wakelock-enabled-by-feature-policy-attribute.https.sub-expected.txt new file mode 100644 index 0000000..6c24b217 --- /dev/null +++ b/third_party/blink/web_tests/platform/win/external/wpt/wake-lock/wakelock-enabled-by-feature-policy-attribute.https.sub-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +FAIL Feature policy "wake-lock" can be enabled in same-origin iframe using allow="wake-lock" attribute assert_true: new WakeLock("screen") expected true got false +FAIL Feature policy "wake-lock" can be enabled in cross-origin iframe using allow="wake-lock" attribute assert_true: new WakeLock("screen") expected true got false +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/platform/win7/external/wpt/wake-lock/wakelock-enabled-by-feature-policy-attribute.https.sub-expected.txt b/third_party/blink/web_tests/platform/win7/external/wpt/wake-lock/wakelock-enabled-by-feature-policy-attribute.https.sub-expected.txt new file mode 100644 index 0000000..6c24b217 --- /dev/null +++ b/third_party/blink/web_tests/platform/win7/external/wpt/wake-lock/wakelock-enabled-by-feature-policy-attribute.https.sub-expected.txt
@@ -0,0 +1,5 @@ +This is a testharness.js-based test. +FAIL Feature policy "wake-lock" can be enabled in same-origin iframe using allow="wake-lock" attribute assert_true: new WakeLock("screen") expected true got false +FAIL Feature policy "wake-lock" can be enabled in cross-origin iframe using allow="wake-lock" attribute assert_true: new WakeLock("screen") expected true got false +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/blink/web_tests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt index e354a28..e28cb9089 100644 --- a/third_party/blink/web_tests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -643,6 +643,7 @@ getter oncomplete getter onerror method abort + method commit method constructor method objectStore setter onabort
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt index ae16471e9..b786315 100644 --- a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -604,6 +604,7 @@ [Worker] getter oncomplete [Worker] getter onerror [Worker] method abort +[Worker] method commit [Worker] method constructor [Worker] method objectStore [Worker] setter onabort
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt index 3ba70a9..1f28aa1 100644 --- a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -3572,6 +3572,7 @@ getter oncomplete getter onerror method abort + method commit method constructor method objectStore setter onabort @@ -4945,6 +4946,7 @@ getter onstatechange getter state method constructor + method getRemoteCertificates setter onerror setter onstatechange interface RTCError : DOMException
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt index ba3e073..0ef3d63 100644 --- a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -599,6 +599,7 @@ [Worker] getter oncomplete [Worker] getter onerror [Worker] method abort +[Worker] method commit [Worker] method constructor [Worker] method objectStore [Worker] setter onabort
diff --git a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/idlharness.https.window-expected.txt b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/idlharness.https.window-expected.txt index a63dc899..11a7d97 100644 --- a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/idlharness.https.window-expected.txt +++ b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/idlharness.https.window-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 506 tests; 377 PASS, 129 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 506 tests; 378 PASS, 128 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS idl_test setup PASS Test driver for asyncInitCertificate FAIL Test driver for asyncInitTransports assert_unreached: Failed to run asyncInitTransports: Error: assert_true: Expect pc.sctp to be instance of RTCSctpTransport expected true got false Reached unreachable code @@ -312,7 +312,7 @@ PASS RTCDtlsTransport interface: existence and properties of interface prototype object's @@unscopables property PASS RTCDtlsTransport interface: attribute iceTransport PASS RTCDtlsTransport interface: attribute state -FAIL RTCDtlsTransport interface: operation getRemoteCertificates() assert_own_property: interface prototype object missing non-static operation expected property "getRemoteCertificates" missing +PASS RTCDtlsTransport interface: operation getRemoteCertificates() PASS RTCDtlsTransport interface: attribute onstatechange PASS RTCDtlsTransport interface: attribute onerror FAIL RTCDtlsTransport must be primary interface of idlTestObjects.dtlsTransport assert_equals: wrong typeof object expected "object" but got "undefined"
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 fa6b72f..f132e2a3 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
@@ -5734,6 +5734,7 @@ getter onstatechange getter state method constructor + method getRemoteCertificates setter onerror setter onstatechange interface RTCError : DOMException
diff --git a/third_party/leveldatabase/BUILD.gn b/third_party/leveldatabase/BUILD.gn index 3d32c4ad..0715bc4 100644 --- a/third_party/leveldatabase/BUILD.gn +++ b/third_party/leveldatabase/BUILD.gn
@@ -278,7 +278,7 @@ test("leveldb_db_bench") { sources = [ - "src/db/db_bench.cc", + "src/benchmarks/db_bench.cc", ] configs -= [ "//build/config/compiler:chromium_code" ] configs += [ "//build/config/compiler:no_chromium_code" ]
diff --git a/third_party/leveldatabase/README.chromium b/third_party/leveldatabase/README.chromium index 4355952..bb957d6 100644 --- a/third_party/leveldatabase/README.chromium +++ b/third_party/leveldatabase/README.chromium
@@ -1,7 +1,7 @@ Name: LevelDB: A Fast Persistent Key-Value Store Short Name: leveldb URL: https://github.com/google/leveldb.git -Version: 1.21.git.ffabb1ae86cc4eb4516a7c0824c878c3b2d19e5d +Version: 1.22.git.4bd052d7e8b0469b2b87664388e2a99cb212ecdb License: New BSD License File: src/LICENSE Security Critical: yes
diff --git a/tools/clang/scripts/build.py b/tools/clang/scripts/build.py index 29e2345..77df975 100755 --- a/tools/clang/scripts/build.py +++ b/tools/clang/scripts/build.py
@@ -39,10 +39,8 @@ COMPILER_RT_BUILD_DIR = os.path.join(LLVM_BUILD_DIR, 'compiler-rt') CLANG_DIR = os.path.join(LLVM_DIR, 'tools', 'clang') LLD_DIR = os.path.join(LLVM_DIR, 'tools', 'lld') -# compiler-rt is built as part of the regular LLVM build on Windows to get -# the 64-bit runtime, and out-of-tree elsewhere. -# TODO(thakis): Try to unify this. -if sys.platform == 'win32': +# TODO(thakis): Use projects/compiler-rt on Linux too once tests pass there. +if sys.platform in ['darwin', 'win32']: COMPILER_RT_DIR = os.path.join(LLVM_DIR, 'projects', 'compiler-rt') else: COMPILER_RT_DIR = os.path.join(LLVM_DIR, 'compiler-rt') @@ -124,7 +122,11 @@ print("Checking out %s r%s into '%s'" % (name, CLANG_REVISION, dir)) command = ['svn', 'checkout', '--force', url + '@' + CLANG_REVISION, dir] - if RunCommand(command, fail_hard=False): + # The checkout command usually succeeds and produces lots of unininteresting + # output. Hence, pass `--quiet` on the first run and run an explicit command + # to print the revision we got afterwards on the first attempt. + if RunCommand(command + ['--quiet'], fail_hard=False): + RunCommand(['svnversion', dir]) return if os.path.isdir(dir): @@ -147,6 +149,10 @@ # In case someone sends a tryjob that temporary adds lld to the checkout, # make sure it's not around on future builds. RmTree(LLD_DIR) + # Remove compiler-rt at old location. + if (sys.platform == 'darwin' and + os.path.exists(os.path.join(LLVM_DIR, 'compiler-rt'))): + RmTree(os.path.join(LLVM_DIR, 'compiler-rt')) Checkout('compiler-rt', LLVM_REPO_URL + '/compiler-rt/trunk', COMPILER_RT_DIR) if sys.platform == 'darwin': # clang needs a libc++ checkout, else -stdlib=libc++ won't find includes @@ -458,11 +464,6 @@ cxxflags = ['-stdlib=libc++'] + cflags ldflags += ['-stdlib=libc++'] deployment_target = '10.7' - # Running libc++ tests takes a long time. Since it was only needed for - # the install step above, don't build it as part of the main build. - # This makes running package.py over 10% faster (30 min instead of 34 min) - RmTree(LIBCXX_DIR) - # If building at head, define a macro that plugins can use for #ifdefing # out code that builds at head, but not at CLANG_REVISION or vice versa. @@ -547,12 +548,16 @@ '-DCMAKE_INSTALL_PREFIX=' + LLVM_BUILD_DIR, '-DCHROMIUM_TOOLS_SRC=%s' % os.path.join(CHROMIUM_DIR, 'tools', 'clang'), '-DCHROMIUM_TOOLS=%s' % ';'.join(chrome_tools)] + if sys.platform == 'darwin': + cmake_args += ['-DCOMPILER_RT_ENABLE_IOS=ON', + '-DSANITIZER_MIN_OSX_VERSION=10.7'] EnsureDirExists(LLVM_BUILD_DIR) os.chdir(LLVM_BUILD_DIR) RmCmakeCache('.') RunCommand(['cmake'] + cmake_args + [LLVM_DIR], msvc_arch='x64', env=deployment_env) + # FIXME: are compiler-rt, fuzzer part of the default target? RunCommand(['ninja'], msvc_arch='x64') # Copy in the threaded versions of lld and other tools. @@ -572,44 +577,6 @@ VerifyVersionOfBuiltClangMatchesVERSION() - # Do an out-of-tree build of compiler-rt. - # On Windows, this is used to get the 32-bit ASan run-time. - # TODO(hans): Remove once the regular build above produces this. - # On Mac and Linux, this is used to get the regular 64-bit run-time. - # Do a clobbered build due to cmake changes. - if os.path.isdir(COMPILER_RT_BUILD_DIR): - RmTree(COMPILER_RT_BUILD_DIR) - os.makedirs(COMPILER_RT_BUILD_DIR) - os.chdir(COMPILER_RT_BUILD_DIR) - # TODO(thakis): Add this once compiler-rt can build with clang-cl (see - # above). - #if args.bootstrap and sys.platform == 'win32': - # The bootstrap compiler produces 64-bit binaries by default. - #cflags += ['-m32'] - #cxxflags += ['-m32'] - compiler_rt_args = base_cmake_args + [ - '-DLLVM_ENABLE_THREADS=OFF', - '-DCMAKE_C_FLAGS=' + ' '.join(cflags), - '-DCMAKE_CXX_FLAGS=' + ' '.join(cxxflags)] - if sys.platform == 'darwin': - compiler_rt_args += ['-DCOMPILER_RT_ENABLE_IOS=ON'] - if sys.platform != 'win32': - compiler_rt_args += ['-DLLVM_CONFIG_PATH=' + - os.path.join(LLVM_BUILD_DIR, 'bin', 'llvm-config'), - '-DSANITIZER_MIN_OSX_VERSION="10.7"'] - # compiler-rt is part of the llvm checkout on Windows but a stand-alone - # directory elsewhere, see the TODO above COMPILER_RT_DIR. - RmCmakeCache('.') - RunCommand(['cmake'] + compiler_rt_args + - [LLVM_DIR if sys.platform == 'win32' else COMPILER_RT_DIR], - msvc_arch='x86', env=deployment_env) - RunCommand(['ninja', 'compiler-rt'], msvc_arch='x86') - if sys.platform != 'win32': - RunCommand(['ninja', 'fuzzer']) - - # Copy select output to the main tree. - # TODO(hans): Make this (and the .gypi and .isolate files) version number - # independent. if sys.platform == 'win32': platform = 'windows' elif sys.platform == 'darwin': @@ -617,34 +584,57 @@ else: assert sys.platform.startswith('linux') platform = 'linux' - rt_lib_src_dir = os.path.join(COMPILER_RT_BUILD_DIR, 'lib', platform) - if sys.platform == 'win32': - # TODO(thakis): This too is due to compiler-rt being part of the checkout - # on Windows, see TODO above COMPILER_RT_DIR. - rt_lib_src_dir = os.path.join(COMPILER_RT_BUILD_DIR, 'lib', 'clang', - RELEASE_VERSION, 'lib', platform) - rt_lib_dst_dir = os.path.join(LLVM_BUILD_DIR, 'lib', 'clang', RELEASE_VERSION, - 'lib', platform) - # Blacklists: - CopyDirectoryContents(os.path.join(rt_lib_src_dir, '..', '..', 'share'), - os.path.join(rt_lib_dst_dir, '..', '..', 'share')) - # Headers: - if sys.platform != 'win32': - CopyDirectoryContents( - os.path.join(COMPILER_RT_BUILD_DIR, 'include/sanitizer'), - os.path.join(LLVM_BUILD_DIR, 'lib/clang', RELEASE_VERSION, - 'include/sanitizer')) - # Static and dynamic libraries: - CopyDirectoryContents(rt_lib_src_dir, rt_lib_dst_dir) - if sys.platform == 'darwin': - for dylib in glob.glob(os.path.join(rt_lib_dst_dir, '*.dylib')): - # Fix LC_ID_DYLIB for the ASan dynamic libraries to be relative to - # @executable_path. - # TODO(glider): this is transitional. We'll need to fix the dylib - # name either in our build system, or in Clang. See also - # http://crbug.com/344836. - subprocess.call(['install_name_tool', '-id', - '@executable_path/' + os.path.basename(dylib), dylib]) + rt_lib_dst_dir = os.path.join(LLVM_BUILD_DIR, 'lib', 'clang', + RELEASE_VERSION, 'lib', platform) + + # Do an out-of-tree build of compiler-rt. + # On Windows, this is used to get the 32-bit ASan run-time. + # TODO(hans): Remove once the regular build above produces this. + if sys.platform != 'darwin': + if os.path.isdir(COMPILER_RT_BUILD_DIR): + RmTree(COMPILER_RT_BUILD_DIR) + os.makedirs(COMPILER_RT_BUILD_DIR) + os.chdir(COMPILER_RT_BUILD_DIR) + # TODO(thakis): Add this once compiler-rt can build with clang-cl (see + # above). + #if args.bootstrap and sys.platform == 'win32': + # The bootstrap compiler produces 64-bit binaries by default. + #cflags += ['-m32'] + #cxxflags += ['-m32'] + compiler_rt_args = base_cmake_args + [ + '-DLLVM_ENABLE_THREADS=OFF', + '-DCMAKE_C_FLAGS=' + ' '.join(cflags), + '-DCMAKE_CXX_FLAGS=' + ' '.join(cxxflags)] + if sys.platform != 'win32': + compiler_rt_args += ['-DLLVM_CONFIG_PATH=' + + os.path.join(LLVM_BUILD_DIR, 'bin', 'llvm-config'), + ] + RmCmakeCache('.') + RunCommand(['cmake'] + compiler_rt_args + + [LLVM_DIR if sys.platform == 'win32' else COMPILER_RT_DIR], + msvc_arch='x86', env=deployment_env) + RunCommand(['ninja', 'compiler-rt'], msvc_arch='x86') + + # Copy select output to the main tree. + # TODO(hans): Make this (and the .gypi and .isolate files) version number + # independent. + rt_lib_src_dir = os.path.join(COMPILER_RT_BUILD_DIR, 'lib', platform) + if sys.platform == 'win32': + # TODO(thakis): This too is due to compiler-rt being part of the checkout + # on Windows, see TODO above COMPILER_RT_DIR. + rt_lib_src_dir = os.path.join(COMPILER_RT_BUILD_DIR, 'lib', 'clang', + RELEASE_VERSION, 'lib', platform) + # Blacklists: + CopyDirectoryContents(os.path.join(rt_lib_src_dir, '..', '..', 'share'), + os.path.join(rt_lib_dst_dir, '..', '..', 'share')) + # Headers: + if sys.platform != 'win32': + CopyDirectoryContents( + os.path.join(COMPILER_RT_BUILD_DIR, 'include/sanitizer'), + os.path.join(LLVM_BUILD_DIR, 'lib/clang', RELEASE_VERSION, + 'include/sanitizer')) + # Static and dynamic libraries: + CopyDirectoryContents(rt_lib_src_dir, rt_lib_dst_dir) if args.with_android: make_toolchain = os.path.join( @@ -775,7 +765,22 @@ if sys.platform == 'win32': CopyDiaDllTo(os.path.join(LLVM_BUILD_DIR, 'bin')) os.chdir(LLVM_BUILD_DIR) - RunCommand(['ninja', 'check-all'], msvc_arch='x64') + test_targets = [ 'check-all' ] + if sys.platform == 'darwin': + # TODO(thakis): Run check-all on Darwin too, https://crbug.com/959361 + test_targets = [ 'check-llvm', 'check-clang', 'check-lld' ] + RunCommand(['ninja'] + test_targets, msvc_arch='x64') + + if sys.platform == 'darwin': + for dylib in glob.glob(os.path.join(rt_lib_dst_dir, '*.dylib')): + # Fix LC_ID_DYLIB for the ASan dynamic libraries to be relative to + # @executable_path. + # Has to happen after running tests. + # TODO(glider): this is transitional. We'll need to fix the dylib + # name either in our build system, or in Clang. See also + # http://crbug.com/344836. + subprocess.call(['install_name_tool', '-id', + '@executable_path/' + os.path.basename(dylib), dylib]) WriteStampFile(PACKAGE_VERSION, STAMP_FILE) WriteStampFile(PACKAGE_VERSION, FORCE_HEAD_REVISION_FILE)
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py index 2cf7df5c..d65b003 100755 --- a/tools/clang/scripts/update.py +++ b/tools/clang/scripts/update.py
@@ -37,8 +37,8 @@ # Do NOT CHANGE this if you don't know what you're doing -- see # https://chromium.googlesource.com/chromium/src/+/master/docs/updating_clang.md # Reverting problematic clang rolls is safe, though. -CLANG_REVISION = '357692' -CLANG_SUB_REVISION = 1 +CLANG_REVISION = '359912' +CLANG_SUB_REVISION = 2 PACKAGE_VERSION = '%s-%s' % (CLANG_REVISION, CLANG_SUB_REVISION) RELEASE_VERSION = '9.0.0'
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 93eabbe..116076f 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -32923,6 +32923,7 @@ <int value="-1455852875" label="WebAuthentication:disabled"/> <int value="-1455559065" label="OmniboxUIExperimentShowPlaceholderWhenCaretShowing:disabled"/> + <int value="-1454479680" label="FileHandlingAPI:enabled"/> <int value="-1454397907" label="OptimizationHints:disabled"/> <int value="-1451644187" label="OverviewSwipeToClose:enabled"/> <int value="-1450576851" label="OmniboxUIExperimentVerticalLayout:enabled"/> @@ -33791,6 +33792,7 @@ label="OmniboxUIExperimentBoldUserTextOnSearchSuggestions:disabled"/> <int value="-135223364" label="AutofillShowTypePredictions:disabled"/> <int value="-133098377" label="SyncPseudoUSSSearchEngines:disabled"/> + <int value="-131673218" label="FileHandlingAPI:disabled"/> <int value="-128687277" label="OmniboxUIExperimentHideSteadyStateUrlPathQueryAndRef:disabled"/> <int value="-127666141" label="TabGroups:disabled"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 0b8cd3c..d65224d 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -130833,7 +130833,7 @@ </histogram> <histogram name="UKM.SyncDisable.Purge" enum="Boolean" - expires_after="2019-05-01"> + expires_after="2020-05-01"> <owner>bcwhite@chromium.org</owner> <owner>rkaplow@chromium.org</owner> <summary>
diff --git a/tools/perf/contrib/leak_detection/page_sets.py b/tools/perf/contrib/leak_detection/page_sets.py index 71b75cc..7240ef6 100644 --- a/tools/perf/contrib/leak_detection/page_sets.py +++ b/tools/perf/contrib/leak_detection/page_sets.py
@@ -163,7 +163,8 @@ # https://crbug.com/892352 # 'https://www.tumblr.com/', 'https://www.paypal.com/', - 'http://www.espn.com/', + # TODO(yuzus): espn.com is flaky. https://crbug.com/959796 + #'http://www.espn.com/', 'https://edition.cnn.com/', 'https://www.pinterest.com/', 'https://www.nytimes.com/',
diff --git a/ui/accessibility/ax_range.h b/ui/accessibility/ax_range.h index 6f312de..6be40c0 100644 --- a/ui/accessibility/ax_range.h +++ b/ui/accessibility/ax_range.h
@@ -77,9 +77,8 @@ } base::string16 GetText() const { - base::string16 text; - if (IsNull()) - return text; + if (IsNull() || *anchor_ == *focus_) + return base::string16(); std::unique_ptr<AXPositionType> start, end; if (*anchor_ < *focus_) { @@ -95,6 +94,7 @@ int end_offset = end->text_offset(); DCHECK_GE(end_offset, 0); + base::string16 text; do { text += start->GetText(); start = start->CreateNextTextAnchorPosition();
diff --git a/ui/accessibility/ax_range_unittest.cc b/ui/accessibility/ax_range_unittest.cc index c5e9e04..5f95dae 100644 --- a/ui/accessibility/ax_range_unittest.cc +++ b/ui/accessibility/ax_range_unittest.cc
@@ -383,5 +383,22 @@ AXRange<AXPosition<AXNodePosition, AXNode>> non_leaf_text_offset( start->Clone(), start->Clone()); EXPECT_EQ(empty_string, non_leaf_text_offset.GetText()); + + // empty string with same position between two anchors, but different offsets + TestPositionType after_end = AXNodePosition::CreateTextPosition( + tree_.data().tree_id, line_break_.id, 1 /* text_offset */, + ax::mojom::TextAffinity::kDownstream); + TestPositionType before_start = AXNodePosition::CreateTextPosition( + tree_.data().tree_id, static_text2_.id, 0 /* text_offset */, + ax::mojom::TextAffinity::kDownstream); + + AXRange<AXPosition<AXNodePosition, AXNode>> + same_position_different_anchors_forward(after_end->Clone(), + before_start->Clone()); + EXPECT_EQ(empty_string, same_position_different_anchors_forward.GetText()); + AXRange<AXPosition<AXNodePosition, AXNode>> + same_position_different_anchors_backward(before_start->Clone(), + after_end->Clone()); + EXPECT_EQ(empty_string, same_position_different_anchors_backward.GetText()); } } // namespace ui
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux.cc b/ui/accessibility/platform/ax_platform_node_auralinux.cc index a89116d..ac00da89 100644 --- a/ui/accessibility/platform/ax_platform_node_auralinux.cc +++ b/ui/accessibility/platform/ax_platform_node_auralinux.cc
@@ -3650,6 +3650,11 @@ } } +bool AXPlatformNodeAuraLinux::IsTextOnlyObject() const { + return GetData().role == ax::mojom::Role::kListMarker || + AXPlatformNodeBase::IsTextOnlyObject(); +} + void AXPlatformNodeAuraLinux::AddAttributeToList(const char* name, const char* value, AtkAttributeSet** attributes) {
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux.h b/ui/accessibility/platform/ax_platform_node_auralinux.h index 074a94c6..0126e8b 100644 --- a/ui/accessibility/platform/ax_platform_node_auralinux.h +++ b/ui/accessibility/platform/ax_platform_node_auralinux.h
@@ -136,6 +136,7 @@ base::Optional<base::OffsetAdjuster::Adjustments> text_unicode_adjustments_ = base::nullopt; + bool IsTextOnlyObject() const override; void AddAttributeToList(const char* name, const char* value, PlatformAttributeList* attributes) override;
diff --git a/ui/accessibility/platform/ax_platform_node_base.h b/ui/accessibility/platform/ax_platform_node_base.h index abfb229..fb0cf46 100644 --- a/ui/accessibility/platform/ax_platform_node_base.h +++ b/ui/accessibility/platform/ax_platform_node_base.h
@@ -209,7 +209,7 @@ // Returns true if this node has role of StaticText, LineBreak, or // InlineTextBox - bool IsTextOnlyObject() const; + virtual bool IsTextOnlyObject() const; // Returns true if the node is an editable text field. bool IsPlainTextField() const;
diff --git a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc index b0cda21..b277b73 100644 --- a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc +++ b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc
@@ -624,6 +624,15 @@ ASSERT_HRESULT_SUCCEEDED( text_range_provider->ExpandToEnclosingUnit(TextUnit_Character)); EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L""); + + // Move both endpoints to the position between the end of the first text + // anchor and before the start of the next anchor. + ASSERT_HRESULT_SUCCEEDED(text_range_provider->MoveEndpointByUnit( + TextPatternRangeEndpoint_End, TextUnit_Character, /*count*/ -9, &count)); + ASSERT_EQ(-9, count); + ASSERT_HRESULT_SUCCEEDED( + text_range_provider->ExpandToEnclosingUnit(TextUnit_Character)); + EXPECT_UIA_TEXTRANGE_EQ(text_range_provider, L"m"); } TEST_F(AXPlatformNodeTextRangeProviderTest,
diff --git a/ui/file_manager/file_manager/background/js/launcher_search.js b/ui/file_manager/file_manager/background/js/launcher_search.js index 24c5897..fc4be8e 100644 --- a/ui/file_manager/file_manager/background/js/launcher_search.js +++ b/ui/file_manager/file_manager/background/js/launcher_search.js
@@ -240,7 +240,9 @@ chrome.fileManagerPrivate.searchDriveMetadata(param, results => { chrome.fileManagerPrivate.getDriveConnectionState(connectionState => { if (connectionState.type !== 'online') { - results = results.filter(result => result.availableOffline !== false); + results = results.filter( + result => result.entry.isDirectory || + result.availableOffline !== false); } chrome.metricsPrivate.recordTime( 'FileBrowser.LauncherSearch.Drive', Date.now() - startTime);
diff --git a/ui/file_manager/file_manager/common/js/lru_cache_unittest.js b/ui/file_manager/file_manager/common/js/lru_cache_unittest.js index a25b19a3..948f3f6e 100644 --- a/ui/file_manager/file_manager/common/js/lru_cache_unittest.js +++ b/ui/file_manager/file_manager/common/js/lru_cache_unittest.js
@@ -116,15 +116,17 @@ assertEquals(8, cache.size()); } -/** @constructor */ -function RandomNumberGenerator(seed) { - this.x = seed; -} +class RandomNumberGenerator { + /** @param {number} seed */ + constructor(seed) { + this.x = seed; + } -RandomNumberGenerator.prototype.random = function() { - this.x = (32453 * this.x + 254119) % (1 << 24); - return this.x >> 4; -}; + random() { + this.x = (32453 * this.x + 254119) % (1 << 24); + return this.x >> 4; + } +} function generateRandom3letters(generator) { const ALPHA = 'abcdefghijklmnopqrstuvwxyz';
diff --git a/ui/file_manager/file_manager/common/js/test_importer_common.js b/ui/file_manager/file_manager/common/js/test_importer_common.js index 9a514ce..df5e601 100644 --- a/ui/file_manager/file_manager/common/js/test_importer_common.js +++ b/ui/file_manager/file_manager/common/js/test_importer_common.js
@@ -20,51 +20,51 @@ /** * A {@code importer.Logger} for testing. Just sends output to the console. * - * @constructor * @implements {importer.Logger} - * @struct * @final */ -importer.TestLogger = function() { - /** @public {!TestCallRecorder} */ - this.errorRecorder = new TestCallRecorder(); +importer.TestLogger = class { + constructor() { + /** @public {!TestCallRecorder} */ + this.errorRecorder = new TestCallRecorder(); - /** @type {boolean} Should we print stuff to console */ - this.quiet_ = false; -}; - -/** - * Causes logger to stop printing anything to console. - * This can be useful when errors are expected in tests. - */ -importer.TestLogger.prototype.quiet = function() { - this.quiet_ = true; -}; - -/** @override */ -importer.TestLogger.prototype.info = function(content) { - if (!this.quiet_) { - console.log(content); + /** @type {boolean} Should we print stuff to console */ + this.quiet_ = false; } -}; -/** @override */ -importer.TestLogger.prototype.error = function(content) { - this.errorRecorder.callback(content); - if (!this.quiet_) { - console.error(content); - console.error(new Error('Error stack').stack); + /** + * Causes logger to stop printing anything to console. + * This can be useful when errors are expected in tests. + */ + quiet() { + this.quiet_ = true; } -}; -/** @override */ -importer.TestLogger.prototype.catcher = function(context) { - return error => { - this.error( - 'Caught promise error. Context: ' + context + - ' Error: ' + error.message); + /** @override */ + info(content) { if (!this.quiet_) { - console.error(error.stack); + console.log(content); } - }; + } + + /** @override */ + error(content) { + this.errorRecorder.callback(content); + if (!this.quiet_) { + console.error(content); + console.error(new Error('Error stack').stack); + } + } + + /** @override */ + catcher(context) { + return error => { + this.error( + 'Caught promise error. Context: ' + context + + ' Error: ' + error.message); + if (!this.quiet_) { + console.error(error.stack); + } + }; + } };
diff --git a/ui/file_manager/image_loader/piex/Makefile b/ui/file_manager/image_loader/piex/Makefile index 4c489bc..2419413341 100644 --- a/ui/file_manager/image_loader/piex/Makefile +++ b/ui/file_manager/image_loader/piex/Makefile
@@ -9,7 +9,7 @@ $(PIEX)/src/binary_parse/range_checked_byte_ptr.cc \ $(PIEX)/src/binary_parse/cached_paged_byte_array.cc -WAPI = ["cwrap", "addFunction", "removeFunction"] +WAPI = ["cwrap"] INCS = -I $(PIEX) -I . WASM = -s WASM=1 -fno-exceptions -Wall @@ -20,7 +20,6 @@ -s ENVIRONMENT='web' \ -s NO_DYNAMIC_EXECUTION=1 \ -s EXTRA_EXPORTED_RUNTIME_METHODS='$(WAPI)' \ - -s RESERVED_FUNCTION_POINTERS=$(shell echo $$((10*2))) \ -s TOTAL_STACK=$(shell echo $$((8*1024))) .PHONY: all clean release
diff --git a/ui/file_manager/image_loader/piex/piex.cpp b/ui/file_manager/image_loader/piex/piex.cpp index 7b1a3c6..54c2c611 100644 --- a/ui/file_manager/image_loader/piex/piex.cpp +++ b/ui/file_manager/image_loader/piex/piex.cpp
@@ -6,6 +6,7 @@ #include <assert.h> #include <emscripten.h> +#include <emscripten/bind.h> #include <emscripten/val.h> #include <stdint.h> #include <string.h> @@ -35,8 +36,8 @@ class PiexReader { public: - static void ReadImage(const char* data, size_t size, int callback) { - assert(data && callback); + static emscripten::val ReadImage(const char* data, size_t size) { + assert(data); auto result = emscripten::val::object(); PiexStreamReader reader(data, size); @@ -57,20 +58,10 @@ break; } - CallbackResult(callback, result); + return result; } private: - static void CallbackResult(int callback, const emscripten::val& result) { - const int index = callback - 1; - - auto callbacks = emscripten::val::global("functionPointers"); - assert(callbacks.as<bool>()); - - auto context = emscripten::val::undefined(); - callbacks[index].call<void>("call", context, result); - } - static emscripten::val GetProperties(const piex::PreviewImageData& image) { auto result = emscripten::val::object(); @@ -132,10 +123,10 @@ } }; -extern "C" { - -void EMSCRIPTEN_KEEPALIVE image(const char* data, size_t size, int callback) { - PiexReader::ReadImage(data, size, callback); +emscripten::val image(int data, size_t size) { + return PiexReader::ReadImage(reinterpret_cast<char*>(data), size); } -} // extern "C" +EMSCRIPTEN_BINDINGS(PiexWasmModule) { + emscripten::function("image", &image); +}
diff --git a/ui/file_manager/image_loader/piex/piex.wasm b/ui/file_manager/image_loader/piex/piex.wasm index cb11d6c..6cbbb407 100644 --- a/ui/file_manager/image_loader/piex/piex.wasm +++ b/ui/file_manager/image_loader/piex/piex.wasm
@@ -1 +1 @@ -var Module=typeof Module!=="undefined"?Module:{};var moduleOverrides={};var key;for(key in Module){if(Module.hasOwnProperty(key)){moduleOverrides[key]=Module[key]}}Module["arguments"]=[];Module["thisProgram"]="./this.program";Module["quit"]=function(status,toThrow){throw toThrow};Module["preRun"]=[];Module["postRun"]=[];var ENVIRONMENT_IS_WEB=true;var ENVIRONMENT_IS_WORKER=false;var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}else{return scriptDirectory+path}}if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(document.currentScript){scriptDirectory=document.currentScript.src}if(scriptDirectory.indexOf("blob:")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.lastIndexOf("/")+1)}else{scriptDirectory=""}Module["read"]=function shell_read(url){try{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText}catch(err){var data=tryParseAsDataURI(url);if(data){return intArrayToString(data)}throw err}};if(ENVIRONMENT_IS_WORKER){Module["readBinary"]=function readBinary(url){try{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}catch(err){var data=tryParseAsDataURI(url);if(data){return data}throw err}}}Module["readAsync"]=function readAsync(url,onload,onerror){var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=function xhr_onload(){if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}var data=tryParseAsDataURI(url);if(data){onload(data.buffer);return}onerror()};xhr.onerror=onerror;xhr.send(null)};Module["setWindowTitle"]=function(title){document.title=title}}else{}var out=Module["print"]||(typeof console!=="undefined"?console.log.bind(console):typeof print!=="undefined"?print:null);var err=Module["printErr"]||(typeof printErr!=="undefined"?printErr:typeof console!=="undefined"&&console.warn.bind(console)||out);for(key in moduleOverrides){if(moduleOverrides.hasOwnProperty(key)){Module[key]=moduleOverrides[key]}}moduleOverrides=undefined;var asm2wasmImports={"f64-rem":function(x,y){return x%y},"debugger":function(){debugger}};var jsCallStartIndex=1;var functionPointers=new Array(20);function addFunction(func,sig){var base=0;for(var i=base;i<base+20;i++){if(!functionPointers[i]){functionPointers[i]=func;return jsCallStartIndex+i}}throw"Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS."}function removeFunction(index){functionPointers[index-jsCallStartIndex]=null}if(typeof WebAssembly!=="object"){err("no native wasm support detected")}var wasmMemory;var wasmTable;var ABORT=false;var EXITSTATUS=0;function assert(condition,text){if(!condition){abort("Assertion failed: "+text)}}function getCFunc(ident){var func=Module["_"+ident];assert(func,"Cannot call unknown function "+ident+", make sure it is exported");return func}function ccall(ident,returnType,argTypes,args,opts){var toC={"string":function(str){var ret=0;if(str!==null&&str!==undefined&&str!==0){var len=(str.length<<2)+1;ret=stackAlloc(len);stringToUTF8(str,ret,len)}return ret},"array":function(arr){var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}};function convertReturnValue(ret){if(returnType==="string")return UTF8ToString(ret);if(returnType==="boolean")return Boolean(ret);return ret}var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i<args.length;i++){var converter=toC[argTypes[i]];if(converter){if(stack===0)stack=stackSave();cArgs[i]=converter(args[i])}else{cArgs[i]=args[i]}}}var ret=func.apply(null,cArgs);ret=convertReturnValue(ret);if(stack!==0)stackRestore(stack);return ret}function cwrap(ident,returnType,argTypes,opts){argTypes=argTypes||[];var numericArgs=argTypes.every(function(type){return type==="number"});var numericRet=returnType!=="string";if(numericRet&&numericArgs&&!opts){return getCFunc(ident)}return function(){return ccall(ident,returnType,argTypes,arguments,opts)}}var UTF8Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf8"):undefined;function UTF8ArrayToString(u8Array,idx,maxBytesToRead){var endIdx=idx+maxBytesToRead;var endPtr=idx;while(u8Array[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&u8Array.subarray&&UTF8Decoder){return UTF8Decoder.decode(u8Array.subarray(idx,endPtr))}else{var str="";while(idx<endPtr){var u0=u8Array[idx++];if(!(u0&128)){str+=String.fromCharCode(u0);continue}var u1=u8Array[idx++]&63;if((u0&224)==192){str+=String.fromCharCode((u0&31)<<6|u1);continue}var u2=u8Array[idx++]&63;if((u0&240)==224){u0=(u0&15)<<12|u1<<6|u2}else{u0=(u0&7)<<18|u1<<12|u2<<6|u8Array[idx++]&63}if(u0<65536){str+=String.fromCharCode(u0)}else{var ch=u0-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}}}return str}function UTF8ToString(ptr,maxBytesToRead){return ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):""}function stringToUTF8Array(str,outU8Array,outIdx,maxBytesToWrite){if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i<str.length;++i){var u=str.charCodeAt(i);if(u>=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;outU8Array[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;outU8Array[outIdx++]=192|u>>6;outU8Array[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;outU8Array[outIdx++]=224|u>>12;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;outU8Array[outIdx++]=240|u>>18;outU8Array[outIdx++]=128|u>>12&63;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}}outU8Array[outIdx]=0;return outIdx-startIdx}function stringToUTF8(str,outPtr,maxBytesToWrite){return stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite)}function lengthBytesUTF8(str){var len=0;for(var i=0;i<str.length;++i){var u=str.charCodeAt(i);if(u>=55296&&u<=57343)u=65536+((u&1023)<<10)|str.charCodeAt(++i)&1023;if(u<=127)++len;else if(u<=2047)len+=2;else if(u<=65535)len+=3;else len+=4}return len}var UTF16Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf-16le"):undefined;function writeArrayToMemory(array,buffer){HEAP8.set(array,buffer)}var WASM_PAGE_SIZE=65536;function alignUp(x,multiple){if(x%multiple>0){x+=multiple-x%multiple}return x}var buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBuffer(buf){Module["buffer"]=buffer=buf}function updateGlobalBufferViews(){Module["HEAP8"]=HEAP8=new Int8Array(buffer);Module["HEAP16"]=HEAP16=new Int16Array(buffer);Module["HEAP32"]=HEAP32=new Int32Array(buffer);Module["HEAPU8"]=HEAPU8=new Uint8Array(buffer);Module["HEAPU16"]=HEAPU16=new Uint16Array(buffer);Module["HEAPU32"]=HEAPU32=new Uint32Array(buffer);Module["HEAPF32"]=HEAPF32=new Float32Array(buffer);Module["HEAPF64"]=HEAPF64=new Float64Array(buffer)}var DYNAMIC_BASE=17216,DYNAMICTOP_PTR=8768;var TOTAL_STACK=8192;var TOTAL_MEMORY=Module["TOTAL_MEMORY"]||16777216;if(TOTAL_MEMORY<TOTAL_STACK)err("TOTAL_MEMORY should be larger than TOTAL_STACK, was "+TOTAL_MEMORY+"! (TOTAL_STACK="+TOTAL_STACK+")");if(Module["buffer"]){buffer=Module["buffer"]}else{if(typeof WebAssembly==="object"&&typeof WebAssembly.Memory==="function"){wasmMemory=new WebAssembly.Memory({"initial":TOTAL_MEMORY/WASM_PAGE_SIZE});buffer=wasmMemory.buffer}else{buffer=new ArrayBuffer(TOTAL_MEMORY)}Module["buffer"]=buffer}updateGlobalBufferViews();HEAP32[DYNAMICTOP_PTR>>2]=DYNAMIC_BASE;function callRuntimeCallbacks(callbacks){while(callbacks.length>0){var callback=callbacks.shift();if(typeof callback=="function"){callback();continue}var func=callback.func;if(typeof func==="number"){if(callback.arg===undefined){Module["dynCall_v"](func)}else{Module["dynCall_vi"](func,callback.arg)}}else{func(callback.arg===undefined?null:callback.arg)}}}var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function ensureInitRuntime(){if(runtimeInitialized)return;runtimeInitialized=true;callRuntimeCallbacks(__ATINIT__)}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}}function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}Module["preloadedImages"]={};Module["preloadedAudios"]={};var dataURIPrefix="data:application/octet-stream;base64,";function isDataURI(filename){return String.prototype.startsWith?filename.startsWith(dataURIPrefix):filename.indexOf(dataURIPrefix)===0}var wasmBinaryFile="data:application/octet-stream;base64,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eHFGBEAgACEBBQJAIAJBAEEZIAFBAXZrIAFBH0YbdCEEA0AgAEEQaiAEQR92QQJ0aiIGKAIAIgEEQCAEQQF0IQQgAiABKAIEQXhxRg0CIAEhAAwBCwsgBiADNgIAIAMgADYCGCADIAM2AgwgAyADNgIIDAILCyABQQhqIgAoAgAiAiADNgIMIAAgAzYCACADIAI2AgggAyABNgIMIANBADYCGAsFQcw4IAQgBnI2AgAgACADNgIAIAMgADYCGCADIAM2AgwgAyADNgIIC0HoOEHoOCgCAEF/aiIANgIAIAAEQA8LQZA8IQADQCAAKAIAIgNBCGohACADDQALQeg4QX82AgALDAAgACAAKAIEEIIBCxoAIABBADYCBCAAQQA2AgggACAAQQRqNgIACxkBAX8gACgCACIBBEAgACABNgIEIAEQMQsLbwEDfyMDIQQjA0EgaiQDIAQgASgCADYCACAEQQxqIgUgBCgCADYCACAAIAUgBEEIaiIGIARBBGogAhCvASICKAIAIgFFBEAgBSAAIAMQwQMgACAGKAIAIAIgBSgCABCDASAFKAIAIQELIAQkAyABCwoAIABB+A42AgALmwEBBn8jAyEFIwNBIGokAyAFIQNB/////wMgACgCBCAAKAIAIgJrQQJ1IgdBAWoiBkkEQBAABSADIAYgACgCCCACayIEQQF1IgIgAiAGSRtB/////wMgBEECdUH/////AUkbIAcgAEEIahDHASADQQhqIgQoAgAiAiABKAIANgIAIAQgAkEEajYCACAAIAMQxgEgAxDFASAFJAMLC6oCAQZ/IAFBb0sEQBAACyAAQQtqIgcsAAAiA0EASCIEBH8gACgCBCEFIAAoAghB/////wdxQX9qBSADQf8BcSEFQQoLIQIgBSABIAUgAUsbIgZBC0khAUEKIAZBEGpBcHFBf2ogARsiBiACRwRAAkACQAJAIAEEQCAAKAIAIQEgBAR/QQAhBCABIQIgAAUgACABIANB/wFxQQFqEEQaIAEQMQwDCyEBBSAGQQFqIgIQKyEBIAQEf0EBIQQgACgCAAUgASAAIANB/wFxQQFqEEQaIABBBGohAwwCCyECCyABIAIgAEEEaiIDKAIAQQFqEEQaIAIQMSAERQ0BIAZBAWohAgsgACACQYCAgIB4cjYCCCADIAU2AgAgACABNgIADAELIAcg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IAEsAAAiBEYEQCAAQQFqIQAgAUEBaiEBQQAgAkF/aiICRQ0CGgwBCwsgA0H/AXEgBEH/AXFrCwVBAAsLhQEBB38jAyEDIwNBMGokAyADQRBqIQQgA0EMaiEHIAMiBiADQSRqEDMgA0EEaiEIQbwUIQUDQCAHIAg2AgAgBCAHKAIANgIAIAYgBCAFIAUQNRogBUEEaiIFQcQURw0ACyAEEJIBIAYgAEECIAEgBCACEJEBIQkgBBCQASAGEDIgAyQDIAkLHwAgAQRAIAAgASgCABCCASAAIAEoAgQQggEgARAxCwtVACADQQA2AgAgA0EANgIEIAMgATYCCCACIAM2AgAgACgCACgCACIBBEAgACABNgIAIAIoAgAhAwsgACgCBCADENMDIABBCGoiACAAKAIAQQFqNgIAC6MBAQJ/IABBBGoiBCgCACEDIABBBGohACADBEACQCACKAIAIQQgACECIAMhAAJAAkADQAJAIAQgACgCECIDSQR/IAAoAgAiA0UNASAAIQIgAwUgAyAETw0EIABBBGoiAigCACIDRQ0DIAMLIQAMAQsLIAEgADYCAAwCCyABIAA2AgAgAiEADAELIAEgADYCACACIQALBSABIAQ2AgAgBCEACyAAC3IBA38jAyEDIwNBEGokAyABKAIAKAIIIQQgASAAQQIgAyIAIARBH3FBoAFqEQQABH9BAAUCfyAAQZIsQQIQgAFFBEAgAkEANgIAQQEMAQsgAEGULEECEIABBH9BAAUgAkEBNgIAQQELCwshBSADJAMgBQs1ACAAQQRqIQAgAiABayICQQBKBEAgACgCACABIAIQSRogACAAKAIAIAJBAnZBAnRqNgIACwspACAAQQA2AgAgAEEANgIEIABBADYCCCABBEAgACABEG0gACABEOADCwsVACAALwEAQYAETCAALwECQYAETHEL+QMBCn8jAyEHIwNBMGokAyAHQRRqIQUgB0EIaiEGIAdBBGohBCAHIgNBJGoiCEEANgIAIANBIGoiCUEANgIAAn8CQAJAAkAgAEGBBBAqRQ0AIABBggQQKkUNACAAQYEEIAkQMARAIABBggQgCBAwDQILQQAMAwsgAEGRAhAqBEAgAEGXAhAqBEAgBUEANgIAIAVBADYCBCAFQQA2AgggBkEANgIAIAZBBGoiCkEANgIAIAZBADYCCAJ/IABB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NgIAIAEQNiABQZwSNgIAIAMgATYCACACKAIAIgQgBSgCAEkEQCAEIAE2AgAgAiACKAIAQQRqNgIABSAAIAMQNwtBBBArIgFBADYCACABEDYgAUGAEjYCACADIAE2AgAgAigCACIEIAUoAgBJBEAgBCABNgIAIAIgAigCAEEEajYCAAUgACADEDcLQQQQKyIBQQA2AgAgARA2IAFB5BE2AgAgAyABNgIAIAIoAgAiBCAFKAIASQRAIAQgATYCACACIAIoAgBBBGo2AgAFIAAgAxA3C0EEECsiAUEANgIAIAEQNiABQcgRNgIAIAMgATYCACACKAIAIgQgBSgCAEkEQCAEIAE2AgAgAiACKAIAQQRqNgIABSAAIAMQNwtBBBArIgFBADYCACABEDYgAUGsETYCACADIAE2AgAgAigCACIEIAUoAgBJBEAgBCABNgIAIAIgAigCAEEEajYCAAUgACADEDcLQQQQKyIBQQA2AgAgARA2IAFBkBE2AgAgAyABNgIAIAIoAgAiBCAFKAIASQRAIAQgATYCACACIAIoAgBBBGo2AgAFIAAgAxA3C0EEECsiAUEANgIAIAEQNiABQfQQNgIAIAMgATYCACACKAIAIgQgBSgCAEkEQCAEIAE2AgAgAiACKAIAQQRqNgIABSAAIAMQNwtBBBArIgFBADYCACABEDYgAUHYEDYCACADIAE2AgAgAigCACIEIAUoAgBJBEAgBCABNgIAIAIgAigCAEEEajYCAAUgACADEDcLQQQQKyIBQQA2AgAgARA2IAFBvBA2AgAgAyABNgIAIAIoAgAiBCAFKAIASQRAIAQgATYCACACIAIoAgBBBGo2AgAFIAAgAxA3C0EEECsiAUEANgIAIAEQNiABQaAQNgIAIAMgATYCACACKAIAIgQgBSgCAEkEQCAEIAE2AgAgAiACKAIAQQRqNgIABSAAIAMQNwtBBBArIgFBADYCACABEDYgAUGEEDYCACADIAE2AgAgAigCACIEIAUoAgBJBEAgBCABNgIAIAIgAigCAEEEajYCAAUgACADEDcLQQQQKyIBQQA2AgAgARA2IAFB6A82AgAgAyABNgIAIAIoAgAiBCAFKAIASQRAIAQgATYCACACIAIoAgBBBGo2AgAFIAAgAxA3C0EEECsiAUEANgIAIAEQNiABQcwPNgIAIAMgATYCACAC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AgQgBBAtIAoQLUEAIAMoAgAgAEEDdGooAgRFDQIaCyAAQQFqIgAgCygCAEkNAAsgCCgCAEUNAUEACwwBCyACIANHBEAgAiADKAIAIAMoAgQQ5QMLQQELIQAgAxA0IAcQLQVBACEACwVBACEACyAGJAMgAAvOAQEGfyAAKAIAIgMhBSACIAEiBmsiBCAAQQhqIgcoAgAgA2tLBEAgABCLAUH/////ByAESQRAEAAFIAAgBCAHKAIAIAAoAgBrIgNBAXQiBSAFIARJG0H/////ByADQf////8DSRsQkwEgACABIAIgBBCMAQsFIAQgAEEEaiIHKAIAIANrIghLIQMgASAIaiACIAMbIgggBmsiBgRAIAUgASAGEHoaCyADBEAgACAIIAIgACgCACAEIAcoAgBrahCMAQUgByAFIAZqNgIACwsLCQAgAEEMahA0C0sBBH8gACgCACIBBEACfyABIABBBGoiAygCACICRgR/IAEFA0AgAkFYaiICEDsgASACRw0ACyAAKAIACyEEIAMgATYCACAECxAxCwsyAQF/IABBBGoiAigCACEAA0AgAEEAOgAAIAIgAigCAEEBaiIANgIAIAFBf2oiAQ0ACwsHACAAKAIIC0IBA38gACgCBCICIABBCGoiAygCACIBRwRAIAMgAUF8aiACa0ECdkF/c0ECdCABajYCAAsgACgCACIABEAgABAxCwu2AQEFfyABQQRqIgIoAgBBACAAQQRqIgUoAgAgACgCACIEayIGQQJ1a0ECdGohAyACIAM2AgAgBkEASgR/IAMgBCAGEEkaIAIhBCACKAIABSACIQQgAwshAiAAKAIAIQMgACACNgIAIAQgAzYCACAFKAIAIQMgBSABQQhqIgIoAgA2AgAgAiADNgIAIABBCGoiACgCACECIAAgAUEMaiIAKAIANgIAIAAgAjYCACABIAQoAgA2AgALXgECfyAAQQxqIgVBADYCACAAIAM2AhAgAQRAIAFB/////wNLBEAQAAUgAUECdBArIQQLCyAAIAQ2AgAgACACQQJ0IARqIgI2AgggACACNgIEIAUgAUECdCAEajYCAAs7AQJ/IwMhASMDQRBqJAMgAUIANwIAIAFBADYCCCABQa8iQQYQKCAAQaAfIAEQPiECIAEQJyABJAMgAguTAgEHfyMDIQIjA0FAayQDIAJBMGoiBUIANwIAIAVBADYCCCAFQbYiQbYiEFEQKCACQSRqIgRCADcCACAEQQA2AgggAQRAIARBvCJBBBAoBSAEQcEiQQQQKAsgAiIGIAUQfyACQQxqIAQQfyACQRhqIgNBADYCACADQQRqIgdBADYCACADQQA2AgggA0EYECsiATYCBCADIAE2AgAgAyABQRhqNgIIIAMgAiACQRhqIgEQkgQDQCABQXRqIgEQJyABIAZHDQALIAMoAgAiASAHKAIAIgZGBH9BAQUDfwJ/QQAgAEGgHyABED5FDQAaIAFBDGoiASAGRw0BQQELCwshCCADEJEEIAQQJyAFECcgAiQDIAgLBQBBoB8LBABBDgsEAEEPC0UBA38jAyECIwNBMGokAyACIgMgACABEDogASACQSxqIgAQPwR/IAMgACwAAEEAR0HVABBLBUEACyEEIAMQLSACJAMgBAuXAQEEfyMDIQUjA0FAayQDIAUiAkEMaiIDIAAgARA6IAEgAkE4aiIEED8EQCADIAQsAABBAEciBEEqEEsEQCADIAQQZgRAIAJCADcCACACQQA2AgggAkG1HkG1HhBRECggASAAIAAoAgAoAgxBP3ERAQAgAhA+IQAgAhAnBUEAIQALBUEAIQALBUEAIQALIAMQLSAFJAMgAAsFAEGAAgsEAEERCyoBAX8gABBSIAFJBEAgAEECNgIoBSAAQRRqIgIgASACKAIAajYCAAsgAAuQAQEBfyAAIAEoAgA2AgAgACABKAIEIgI2AgQgAgRAIAJBBGoiAiACKAIAQQFqNgIACyAAIAEoAgg2AgggACABKAIMIgI2AgwgAgRAIAJBBGoiAiACKAIAQQFqNgIACyAAQRBqIgAgAUEQaiIBKQIANwIAIAAgASkCCDcCCCAAIAEpAhA3AhAgACABKAIYNgIYCywAIABCADcCACAAQgA3AgggAEIANwIQIABCADcCGCAAQgA3AiAgAEEBNgIoC4kBAQJ/IAAgASgCADYCACAAIAFBBGoiAigCADYCBCABQQA2AgAgAkEANgIAIAAgAUEIaiICKAIANgIIIAAgAUEMaiIDKAIANgIMIAJBADYCACADQQA2AgAgAEEQaiIAIAFBEGoiASkCADcCACAAIAEpAgg3AgggACABKQIQNwIQIAAgASgCGDYCGAu4AwEIfyMDIQUjA0EQaiQDIAVBBGohBiAFIQcgACgCGCABTQRAIAAoAhwgAUsEQCAAKAIAIgMoAgAoAgghAiADIAJBP3ERAQAgAU0EQEGmHUHXHEG/AUGUHRALCyAAKAIAIgMoAgAoAgwhAiABIAMgAkE/cREBAG4hAyAAKAIAIgEoAgAoAhAhAiABIAMgBiAHIABBCGogAkEfcUHAAmoRAwAgACgCACIBKAIAKAIMIQIgASACQT9xEQEAIQEgACgCACICKAIAKAIIIQQgAiAEQT9xEQEAQX9qIQIgACgCACIEKAIAKAIMIQggAyACIAQgCEE/cREBAG5GBEAgACgCACIBKAIAKAIIIQICfyABIAJBP3ERAQAhCSAAKAIAIgIoAgAoAgwhBCAJCyACIARBP3ERAQAgA2xrIQELIAcoAgAiBCAGKAIAIgJPBEAgASAEIAJrRgRAIAAgAjYCECAAKAIAIgEoAgAoAgwhAiAAIAEgAkE/cREBACADbDYCICAAIAcoAgAgBigCAGs2AiQgABCYASAFJAMPCwtBph1B1xxB0wFBlB0QCwsLQaEcQdccQbsBQZQdEAsLnwEBB38jAyEEIwNBIGokAyAEIQJB/////wcgAEEEaiIGKAIAIAAoAgBrQQFqIgVJBEAQAAUgAiAFIAAoAgggACgCACIHayIIQQF0IgMgAyAFSRtB/////wcgCEH/////A0kbIAYoAgAgB2sgAEEIahB1IAJBCGoiAygCACABLAAAOgAAIAMgAygCAEEBajYCACAAIAIQdCACEHMgBCQDCwtHAQN/IwMhAyMDQSBqJAMgAyECIAAoAgggACgCACIEayABSQRAIAIgASAAKAIEIARrIABBCGoQdSAAIAIQdCACEHMLIAMkAwu1AQEHfyMDIQYjA0EQaiQDIAYhByAAQQA2AgAgAEEEaiIFQQA2AgAgAEEIaiIIQQA2AgACQAJAIAIgA2oiBCACSQ0AIAEQUiAESQ0AIAAgAxDXASADBEBBACEEA0AgByABIAIgBGoQOSIJOgAAIAUoAgAiCiAIKAIASQRAIAogCToAACAFIAUoAgBBAWo2AgAFIAAgBxDWAQsgBEEBaiIEIANHDQALCwwBCyABQQI2AigLIAYkAwuBAQECfyMDIQUjA0EQaiQDIAUiBCABIAIgAxDYASAAQgA3AgAgAEEANgIIIAAgBEEEaiIDKAIAIAQoAgBrEDggBCgCACIBIAMoAgBHBEBBACECA0AgACABIAJqLAAAEK4DIAJBAWoiAiADKAIAIAQoAgAiAWtJDQALCyAEEDQgBSQDC0sBA38jAyECIwNBQGskAyACQQxqIgMgACABEDogAkIANwIAIAJBADYCCCACQbUbQQQQKCADQQAgAhBHIQQgAhAnIAMQLSACJAMgBAsEAEESC7oBAQZ/IAAgAEEEaiAAQQhqIgMgAhBZGiAAQQxqIgUgAUcEQANAIAIoAgAhBCAFKAIAIAMoAgAgBEE/cUFAaxECAARAIAUoAgAiBiEHIAUhBANAAkAgBCADKAIANgIAIAAgA0YEQCAAIQMMAQsgAigCACEEIAcgA0F8aiIIKAIAIARBP3FBQGsRAgAEQCADIQQgCCEDDAILCwsgAyAGNgIACyAFQQRqIgQgAUcEQCAFIQMgBCEFDAELCwsL7wEBBX8jAyEGIwNBgAJqJAMgAEEARyACQQBHcUUEQEHoFkH5FkEnQYIXEAsLIAYiA0H0AWoiBBBnIANB6AFqIgciBUGcDjYCACAFQYgONgIAIAUgADYCBCAFIAE2AgggA0EEaiIAEGACQAJAAkACQAJAIAcgABD1Aw4DAgABAwsgA0GSFxBKIARBjBcgAxA8DAMLIANBrBcQSiAEQYwXIAMQPAwCCyADIAAQkAQgBCgCABARIAQgAygCADYCACADQQA2AgAMAQsgA0HFFxBKIARBjBcgAxA8CyADECwgAiAEEIcEIAAQZSAEECwgBiQDC10BAn8gAEUEQEGpG0HPGkEwQasbEAsLIAEEQCAAKAIAKAIMIQICfyAAIAJBP3ERAQAhAyABKAIAKAIMIQIgAwsgASACQT9xEQEASQ8FQbMbQc8aQTFBqxsQCwtBAAtCAQF/IAAoAgAgACgCBCIARgRAQbwaQc8aQZ0GQZsbEAsFIABBfGooAgAiACgCACgCDCEBIAAgAUE/cREBAA8LQQALJgEDfyMDIQAjA0EQaiQDIAAQmwEgABDfASECIAAQmgEgACQDIAILEgBBEyAAIAEgAiADIAQgBRABCxIAQRIgACABIAIgAyAEIAUQAQsSAEERIAAgASACIAMgBCAFEAELEgBBECAAIAEgAiADIAQgBRABCxIAQQ8gACABIAIgAyAEIAUQAQsSAEEOIAAgASACIAMgBCAFEAELCwAgACABIAIQ3QELEgBBDSAAIAEgAiADIAQgBRABCxIAQQwgACABIAIgAyAEIAUQAQsSAEELIAAgASACIAMgBCAFEAELEgBBCiAAIAEgAiADIAQgBRABCxIAQQkgACABIAIgAyAEIAUQAQsSAEEIIAAgASACIAMgBCAFEAELEgBBByAAIAEgAiADIAQgBRABCxIAQQYgACABIAIgAyAEIAUQAQsSAEEFIAAgASACIAMgBCAFEAELEgBBBCAAIAEgAiADIAQgBRABCxIAQQMgACABIAIgAyAEIAUQAQsSAEECIAAgASACIAMgBCAFEAELEgBBASAAIAEgAiADIAQgBRABCxIAQQAgACABIAIgAyAEIAUQAQsQAEETIAAgASACIAMgBBACCxAAQRIgACABIAIgAyAEEAILEABBESAAIAEgAiADIAQQAgsQAEEQIAAgASACIAMgBBACCxAAQQ8gACABIAIgAyAEEAILEABBDiAAIAEgAiADIAQQAgsQAEENIAAgASACIAMgBBACCxAAQQwgACABIAIgAyAEEAILEABBCyAAIAEgAiADIAQQAgsQAEEKIAAgASACIAMgBBACCxAAQQkgACABIAIgAyAEEAILEABBCCAAIAEgAiADIAQQAgsQAEEHIAAgASACIAMgBBACCxAAQQYgACABIAIgAyAEEAILEABBBSAAIAEgAiADIAQQAgsQAEEEIAAgASACIAMgBBACCxAAQQMgACABIAIgAyAEEAILEABBAiAAIAEgAiADIAQQAgsQAEEBIAAgASACIAMgBBACCxAAQQAgACABIAIgAyAEEAILDgBBEyAAIAEgAiADEAMLDgBBEiAAIAEgAiADEAMLDgBBESAAIAEgAiADEAMLDgBBECAAIAEgAiADEAMLLgEBfyMDIQMjA0EQaiQDIAMgADYCACADIAEQnAEQnQEgAyACEJwBEJ0BIAMkAwsOAEEPIAAgASACIAMQAwsOAEEOIAAgASACIAMQAwsOAEENIAAgASACIAMQAwsOAEEMIAAgASACIAMQAwsOAEELIAAgASACIAMQAwsOAEEKIAAgASACIAMQAwsOAEEJIAAgASACIAMQAwsOAEEIIAAgASACIAMQAwsOAEEHIAAgASACIAMQAwsOAEEGIAAgASACIAMQAwt6AQV/IwMhBCMDQRBqJANBuDgsAABFBEBBuDgsAABBAUYEf0EABUG4OEEBOgAAQQELBEACfyMDIQcjA0EQaiQDQQNBrA4QHiEGIAcLJANBwDggBjYCAAsLAn9BwDgoAgAhCCAEIAIgAxCOAiAICyAAIAEgBBAgIAQkAwsOAEEFIAAgASACIAMQAwsOAEEEIAAgASACIAMQAwsOAEEDIAAgASACIAMQAwsOAEECIAAgASACIAMQAwsOAEEBIAAgASACIAMQAwsOAEEAIAAgASACIAMQAwsIAEETIAAQBAsIAEESIAAQBAsIAEERIAAQBAsmAQF/IwMhAiMDQRBqJAMgAiABEJ4BIABBwA0gAhAPNgIAIAIkAwsIAEEQIAAQBAsIAEEPIAAQBAsIAEEOIAAQBAsIAEENIAAQBAsIAEEMIAAQBAsIAEELIAAQBAsIAEEKIAAQBAsIAEEJIAAQBAsIAEEIIAAQBAsIAEEHIAAQBAsyAQF/IwMhAyMDQRBqJAMgASgCACEBIAMgAhCjAiAAIAEgAygCABAdEG8gAxAsIAMkAwsIAEEGIAAQBAsIAEEFIAAQBAsIAEEEIAAQBAsIAEEDIAAQBAsIAEECIAAQBAsIAEEBIAAQBAsIAEEAIAAQBAsQACABIABBP3FB4AFqEQAACwYAQRMQBQsGAEESEAULSwIBfwJ8IwMhASMDQRBqJAMCfCAAKAIAQagOKAIAIAFBBGoiABAhIQMgASAAKAIANgIAIAEoAgAQGiABJAMgAwtEAAAAAAAAAABiCwYAQREQBQsGAEEQEAULBgBBDxAFCwYAQQ4QBQsGAEENEAULBgBBDBAFCwYAQQsQBQsGAEEKEAULBgBBCRAFCwYAQQgQBQs0AQF/IwMhAiMDQRBqJAMgAiAANgIAIAIoAgAgAS8BADYCACACIAIoAgBBCGo2AgAgAiQDCwYAQQcQBQsGAEEGEAULBgBBBRAFCwYAQQQQBQsGAEEDEAULBgBBAhAFCwYAQQEQBQsGAEEAEAULDgAgAEEfcUHAAWoRBQALDgBBEyAAIAEgAiADEAYLDgBBEiAAIAEgAiADEAYLDgBBESAAIAEgAiADEAYLDgBBECAAIAEgAiADEAYLDgBBDyAAIAEgAiADEAYLDgBBDiAAIAEgAiADEAYLDgBBDSAAIAEgAiADEAYLDgBBDCAAIAEgAiADEAYLDgBBCyAAIAEgAiADEAYLDgBBCiAAIAEgAiADEAYLDgBBCSAAIAEgAiADEAYLDgBBCCAAIAEgAiADEAYLDgBBByAAIAEgAiADEAYLDgBBBiAAIAEgAiADEAYLDgBBBSAAIAEgAiADEAYLDgBBBCAAIAEgAiADEAYLDgBBAyAAIAEgAiADEAYLDgBBAiAAIAEgAiADEAYLDgBBASAAIAEgAiADEAYLDgBBACAAIAEgAiADEAYLDABBEyAAIAEgAhAHCwwAQRIgACABIAIQBwsMAEERIAAgASACEAcLDABBECAAIAEgAhAHCwwAQQ8gACABIAIQBwsMAEEOIAAgASACEAcLDABBDSAAIAEgAhAHCwwAQQwgACABIAIQBwsMAEELIAAgASACEAcLDABBCiAAIAEgAhAHCwwAQQkgACABIAIQBwsMAEEIIAAgASACEAcLDABBByAAIAEgAhAHCwwAQQYgACABIAIQBwsMAEEFIAAgASACEAcLDABBBCAAIAEgAhAHCwwAQQMgACABIAIQBwsMAEECIAAgASACEAcLDABBASAAIAEgAhAHCwwAQQAgACABIAIQBwsKAEETIAAgARAICwoAQRIgACABEAgLCgBBESAAIAEQCAsKAEEQIAAgARAICwoAQQ8gACABEAgLCgBBDiAAIAEQCAsKAEENIAAgARAICwoAQQwgACABEAgLCgBBCyAAIAEQCAsKAEEKIAAgARAICwoAQQkgACABEAgLCgBBCCAAIAEQCAsKAEEHIAAgARAICwoAQQYgACABEAgLCgBBBSAAIAEQCAsKAEEEIAAgARAICwoAQQMgACABEAgLCgBBAiAAIAEQCAsKAEEBIAAgARAICwoAQQAgACABEAgLCABBEyAAEAkLCABBEiAAEAkLCABBESAAEAkLCABBECAAEAkLCABBDyAAEAkLCABBDiAAEAkLCABBDSAAEAkLCABBDCAAEAkLCABBCyAAEAkLCABBCiAAEAkLCABBCSAAEAkLCABBCCAAEAkLCABBByAAEAkLCABBBiAAEAkLCABBBSAAEAkLCABBBCAAEAkLCABBAyAAEAkLCABBAiAAEAkLCABBASAAEAkLCABBACAAEAkLWAEDfyAALAALIgFBAEgEfyAAKAIEIgJBBGoQYSIBIAI2AgAgACgCACEDIAIFIAFB/wFxIgJBBGoQYSIBIAI2AgAgACEDIAILIQAgAUEEaiADIAAQSRogAQtzAQJ/IAAgASgCCBA9BEAgASACIAMQfgUCQCAAQRBqIAAoAgwiBEEDdGohBSAAQRBqIAEgAiADEKQBIARBAUoEQCABQTZqIQQgAEEYaiEAA0AgACABIAIgAxCkASAELAAADQIgAEEIaiIAIAVJDQALCwsLC4YFAQl/IAAgASgCCBA9BEAgASACIAMQfQUCQCAAIAEoAgAQPUUEQCAAKAIMIQUgAEEQaiABIAIgAyAEEGwgBUEBTA0BIABBEGogBUEDdGohByAAQRhqIQUgACgCCCIGQQJxRQRAIAFBJGoiACgCAEEBRwRAIAZBAXFFBEAgAUE2aiEGA0AgBiwAAA0FIAAoAgBBAUYNBSAFIAEgAiADIAQQbCAFQQhqIgUgB0kNAAsMBAsgAUEYaiEGIAFBNmohCANAIAgsAAANBCAAKAIAQQFGBEAgBigCAEEBRg0FCyAFIAEgAiADIAQQbCAFQQhqIgUgB0kNAAsMAwsLIAFBNmohAANAIAAsAAANAiAFIAEgAiADIAQQbCAFQQhqIgUgB0kNAAsMAQsgASgCECACRwRAIAFBFGoiCygCACACRwRAIAEgAzYCICABQSxqIgwoAgBBBEYNAiAAQRBqIAAoAgxBA3RqIQ0gAUE0aiEHIAFBNWohBiABQTZqIQggAEEIaiEJIAFBGGohCkEAIQMgAEEQaiEFQQAhACAMAn8CQANAAkAgBSANTw0AIAdBADoAACAGQQA6AAAgBSABIAIgAkEBIAQQeyAILAAADQAgBiwAAARAAn8gBywAAEUEQCAJKAIAQQFxBEBBAQwCBUEBIQMMBAsACyAKKAIAQQFGDQQgCSgCAEECcUUNBEEBIQBBAQshAwsgBUEIaiEFDAELCyAARQRAIAsgAjYCACABQShqIgAgACgCAEEBajYCACABKAIkQQFGBEAgCigCAEECRgRAIAhBAToAACADDQNBBAwECwsLIAMNAEEEDAELQQMLNgIADAILCyADQQFGBEAgAUEBNgIgCwsLC/wBAQh/IAAgASgCCBA9BEAgASACIAMgBBB8BSABQTRqIgYsAAAhCSABQTVqIgcsAAAhCiAAQRBqIAAoAgwiCEEDdGohCyAGQQA6AAAgB0EAOgAAIABBEGogASACIAMgBCAFEHsgCEEBSgRAAkAgAUEYaiEMIABBCGohCCABQTZqIQ0gAEEYaiEAA0AgDSwAAA0BIAYsAAAEQCAMKAIAQQFGDQIgCCgCAEECcUUNAgUgBywAAARAIAgoAgBBAXFFDQMLCyAGQQA6AAAgB0EAOgAAIAAgASACIAMgBCAFEHsgAEEIaiIAIAtJDQALCwsgBiAJOgAAIAcgCjoAAAsLCAAgACABED0LPAEBfyAAIAEoAggQPQRAIAEgAiADEH4FIAAoAggiACgCACgCHCEEIAAgASACIAMgBEEfcUGgAmoRBgALC7oCAQR/IAAgASgCCBA9BEAgASACIAMQfQUCQCAAIAEoAgAQPUUEQCAAKAIIIgAoAgAoAhghBSAAIAEgAiADIAQgBUEfcUHAAmoRAwAMAQsgASgCECACRwRAIAFBFGoiBSgCACACRwRAIAEgAzYCICABQSxqIgMoAgBBBEYNAiABQTRqIgZBADoAACABQTVqIgdBADoAACAAKAIIIgAoAgAoAhQhCCAAIAEgAiACQQEgBCAIQR9xQeACahEHACADAn8CQCAHLAAABH8gBiwAAA0BQQEFQQALIQAgBSACNgIAIAFBKGoiAiACKAIAQQFqNgIAIAEoAiRBAUYEQCABKAIYQQJGBEAgAUEBOgA2IAANAkEEDAMLCyAADQBBBAwBC0EDCzYCAAwCCwsgA0EBRgRAIAFBATYCIAsLCwtCAQF/IAAgASgCCBA9BEAgASACIAMgBBB8BSAAKAIIIgAoAgAoAhQhBiAAIAEgAiADIAQgBSAGQR9xQeACahEHAAsL8QIBCn8jAyEFIwNBQGskAyAAIAAoAgAiAUF4aigCAGohBCABQXxqKAIAIQMgBSIBQcAMNgIAIAEgADYCBCABQdAMNgIIIAFBADYCDCABQRRqIQAgAUEYaiEGIAFBHGohByABQSBqIQggAUEoaiEJIAFBEGoiAkIANwIAIAJCADcCCCACQgA3AhAgAkIANwIYIAJBADYCICACQQA7ASQgAkEAOgAmIANBwAwQPQR/IAFBATYCMCADIAEgBCAEQQFBACADKAIAKAIUQR9xQeACahEHACAEQQAgBigCAEEBRhsFAn8gAyABIARBAUEAIAMoAgAoAhhBH3FBwAJqEQMAAkACQAJAIAEoAiQOAgACAQsgACgCAEEAIAkoAgBBAUYgBygCAEEBRnEgCCgCAEEBRnEbDAILQQAMAQsgBigCAEEBRwRAQQAgCSgCAEUgBygCAEEBRnEgCCgCAEEBRnFFDQEaCyACKAIACwshCiAFJAMgCgs4AQF/IwMhAiMDQRBqJAMgAiAANgIAIAEQngMhACACKAIAIAA2AgAgAiACKAIAQQhqNgIAIAIkAwsGACAAJAMLFgAgACABKAIIED0EQCABIAIgAxB+CwuWAQAgACABKAIIED0EQCABIAIgAxB9BSAAIAEoAgAQPQRAAkAgASgCECACRwRAIAFBFGoiACgCACACRwRAIAEgAzYCICAAIAI2AgAgAUEoaiIAIAAoAgBBAWo2AgAgASgCJEEBRgRAIAEoAhhBAkYEQCABQQE6ADYLCyABQQQ2AiwMAgsLIANBAUYEQCABQQE2AiALCwsLCxgAIAAgASgCCBA9BEAgASACIAMgBBB8CwvJAQEEfyMDIQUjA0FAayQDIAUhAyAAIAEQPQR/QQEFIAEEfyABEKYDIgEEfyADQQRqIgRCADcCACAEQgA3AgggBEIANwIQIARCADcCGCAEQgA3AiAgBEIANwIoIARBADYCMCADIAE2AgAgAyAANgIIIANBfzYCDCADQQE2AjAgASgCACgCHCEAIAEgAyACKAIAQQEgAEEfcUGgAmoRBgAgAygCGEEBRgR/IAIgAygCEDYCAEEBBUEACwVBAAsFQQALCyEGIAUkAyAGC3IBAn8jAyEEIwNBEGokAyADQW9LBEAQAAsgA0ELSQRAIAAgAjoACwUgACADQRBqQXBxIgUQKyIDNgIAIAAgBUGAgICAeHI2AgggACACNgIEIAMhAAsgACABIAIQRBogBEEAOgAAIAAgAmogBBApIAQkAwvDAQEHfyMDIQMjA0EQaiQDIAMiBiABOgAAIABBC2oiBCwAACIBQQBIIgcEfyAAKAIEIQIgACgCCEH/////B3FBf2oFIAFB/wFxIQJBCgshASADQQFqIQUCQAJAIAEgAkYEQCAAIAFBASABIAEQpQEgBCwAAEEASA0BBSAHDQELIAQgAkEBajoAAAwBCwJ/IAAoAgAhCCAAIAJBAWo2AgQgCAshAAsgACACaiIAIAYQKSAFQQA6AAAgAEEBaiAFECkgAyQDC8ABAQZ/IwMhBSMDQRBqJAMgBSEGIABBC2oiBywAACIEQQBIIggEfyAAKAIEIQMgACgCCEH/////B3FBf2oFIARB/wFxIQNBCgsiBCADayACSQRAIAAgBCACIANqIARrIAMgAyACIAEQswMFIAIEQCADIAgEfyAAKAIABSAACyIEaiABIAIQRBogAiADaiEBIAcsAABBAEgEQCAAIAE2AgQFIAcgAToAAAsgBkEAOgAAIAEgBGogBhApCwsgBSQDIAALiAIBB38jAyEEIwNBEGokAyAEQQRqIQMgBCICQQxqIgUQeSACQQhqIgcgASgCHCIGNgIAIAZBAUsEQCAAIAUQawUCQCABQRhqIggoAgAEQCABQRRqIgYoAgAEQCADEGcgAiABEKEBIAMgAhCiASACECwgAiABQSBqEFAgAyACEKABIAIQLCACIAcQUCADQZkZIAIQPCACECwgAiAIEFAgA0GgGSACEDwgAhAsIAIgBhBQIANBpxkgAhA8IAIQLCACIAFBEGoQaiADQa4ZIAIQPCACECwgAiABQRJqEGogA0G0GSACEDwgAhAsIAAgAxCfASADECwMAgsLIAAgBRBrCwsgBRAsIAQkAwvaAQEHfyMDIQcjA0EQaiQDIAchCCABBEAgAEELaiIGLAAAIgVBAEgEfyAAKAIIQf////8HcUF/aiEDIAAoAgQFQQohAyAFQf8BcQshBCAEIAMgBGsgAUkEfyAAIAMgASAEaiADayAEIAQQpQEgBiwAAAUgBQtBGHRBGHVBAEgEfyAAKAIABSAACyIFaiEJIAEiAwRAIAkgAkH/AXEgAxCjARoLIAEgBGohASAGLAAAQQBIBEAgACABNgIEBSAGIAE6AAALIAhBADoAACABIAVqIAgQKQsgByQDIAALjQEBBn8jAyEDIwNBEGokAyAAQQtqIgUsAAAiAUEASCICBH8gACgCBAUgAUH/AXELIQQgAyEBIARBCkkEQCAAQQogBGtBABCxAxoFIAIEQAJ/IAAoAgBBCmohBiABQQA6AAAgBgsgARApIABBCjYCBAUgAUEAOgAAIABBCmogARApIAVBCjoAAAsLIAMkAwvmAQEDfyMDIQcjA0EQaiQDQW4gAWsgAkkEQBAACyAALAALQQBIBH8gACgCAAUgAAshCCABQef///8HSQR/QQsgAUEBdCIJIAEgAmoiAiACIAlJGyICQRBqQXBxIAJBC0kbBUFvCyIJECshAiAEBEAgAiAIIAQQRBoLIAUEQCACIARqIAYgBRBEGgsgAyAEayIGBEAgBSACIARqaiAEIAhqIAYQRBoLIAFBCkcEQCAIEDELIAAgAjYCACAAIAlBgICAgHhyNgIIIAAgAyAFaiIANgIEIAdBADoAACAAIAJqIAcQKSAHJAMLVwEBfyAAQQhqIgEoAgAEQCABIAEoAgAiAUF/ajYCACABRQRAIAAoAgAoAhAhASAAIAFBP3FB4AFqEQAACwUgACgCACgCECEBIAAgAUE/cUHgAWoRAAALCzYBAn8jAyECIwNBEGokAwJ/IAAoAgAhAyACQZMYEEogAwsgAigCACABKAIAEA4gAhAsIAIkAwsFAEHEOAskAQJ/IAAoAgQiABBRQQFqIgEQYSICBH8gAiAAIAEQSQVBAAsLggIBB38jAyEEIwNBEGokAyAEQQRqIQMgBCICQQxqIgUQeSACQQhqIgcgASgCDCIGNgIAIAYEQCAAIAUQawUCQCABQQhqIggoAgAEQCABQQRqIgYoAgAEQCADEGcgAiABEKEBIAMgAhCiASACECwgAiABQSBqEFAgAyACEKABIAIQLCACIAcQUCADQZkZIAIQPCACECwgAiAIEFAgA0GgGSACEDwgAhAsIAIgBhBQIANBpxkgAhA8IAIQLCACIAEQaiADQa4ZIAIQPCACECwgAiABQQJqEGogA0G0GSACEDwgAhAsIAAgAxCfASADECwMAgsLIAAgBRBrCwsgBRAsIAQkAwvrAgBBiA1BliwQIkGQDUGbLEEBQQFBABAlQZgNQaA2QQFBgH9B/wAQDEGoDUGUNkEBQYB/Qf8AEAxBoA1BhjZBAUEAQf8BEAxBsA1BgDZBAkGAgH5B//8BEAxBuA1B8TVBAkEAQf//AxAMQcANQe01QQRBgICAgHhB/////wcQDEHIDUHgNUEEQQBBfxAMQdANQds1QQRBgICAgHhB/////wcQDEHYDUHNNUEEQQBBfxAMQeANQcc1QQQQE0HoDUHANUEIEBNBoAhBoCwQEkGIDEGsLBASQfALQQRBzSwQI0G4CEHaLBAkQegLQQBBhTQQCkHqLBCrAUGPLRCqAUG2LRCpAUHVLRCoAUH9LRCnAUGaLhCmAUGwC0EEQY4yEApBqAtBBUHIMRAKQcAuEKsBQeAuEKoBQYEvEKkBQaIvEKgBQcQvEKcBQeUvEKYBQaALQQZBijEQCkGYC0EHQcswEApBkAtBB0GHMBAKCwUAELkDC28BBH8jAyEGIwNBEGokAyAGIQggBkEIaiIHIAM2AgAgAUHAwABBDSAGQQxqIgEgBkEEahBbBH8gBCABKAIAIAcgARBABH8gAiACIAEoAgBqIAcoAgAgACAEIAUgCBBOBUEACwVBAAshCSAGJAMgCQvZAQEIfyMDIQUjA0EwaiQDIAVBIGohCCAFQRxqIQkgBUEMaiEKIAUhBiAFQSRqIQsgBUEUaiIHIAI2AgAgAEGgwABBDSAFQRhqIgAgBUEQahBbBEAgAyAAKAIAIAcgABBABEAgACgCACEMIAcoAgAhByAGIAsQMyAGQQRqIQJB9BQhAANAIAkgAjYCACAIIAkoAgA2AgAgBiAIIAAgABA1GiAAQQRqIgBB/BRHDQALIAEgASAMaiAHIAYgAyAEIAoQTiEAIAYQMgVBACEACwVBACEACyAFJAMgAAuXBAENfyMDIQIjA0HQAWokAyACQcABaiEIIAJBvAFqIQUgAkGQAWohCiACQYgBaiELIAJB4ABqIQYgAkE4aiEHIAJBEGohCSACIQMgAkHMAWohDUEAIAAgAkG4AWoiBBCFAQRAIAogBCgCABBFIAQoAgAgACAKEK4BBEAgBiAEKAIAEEUgCiAEKAIAQQwgACALIAYQrQEEQAJAIAZBgAIQKgRAIAZBgAJBByABQRhqIAFBFGoQW0UNAQsgByAEKAIAEEUgBiALKAIAIAQoAgAgACAHELwDBEAgB0GBAhAqBEAgB0GCAhAqBEAgB0GBAiABQQhqIgwQMBogDCALKAIAIAwoAgBqNgIAIAdBggIgAUEEahAwGiAJIAQoAgAQRSADIA0QMyAFIANBBGo2AgAgCCAFKAIANgIAIAMgCEHwFEHwFBA1GgJ/IAMgBiALKAIAIAQoAgAgACAJELsDIQ4gAxAyIA4LBEAgCUGTIhAqBEAgCEEEEIcBIAlBkyIgCBBcBEAgCCgCACIDKAIIIgUgAygCACIASwRAIANBDGoiDCgCACADQQRqIg0oAgBLBEAgAUEoaiIDIAUgAGtBAWoiBTYCACABQSxqIgAgDCgCACANKAIAa0EBaiIBNgIAIAUgAUkEQCADIAE2AgAgACAFNgIACwsLCyAIEDQLCyAJEDsLCwsgBxA7CwsgBhA7CyAKEDsLIAIkAws2AQJ/IwMhAiMDQRBqJAMCfyAAKAIAIQMgAkGLGBBKIAMLIAIoAgAgASgCABAOIAIQLCACJAMLtwEBBn8jAyECIwNB8ABqJAMgAkE4aiEEIAJBMGohByACQQhqIQMgAiEGQQAgACACQeAAaiIFEIUBBEAgBCAFKAIAEEUgBSgCACAAIAQQrgEEQCADIAUoAgAQRSAEIAUoAgBBBiAAIAcgAxCtAQR/IANBNxAqBH8gA0E3IAYQMAR/IAEgBigCAEEARzYCJEEBBUEACwVBAQsFQQALIQAgAxA7BUEAIQALIAQQOwVBACEACyACJAMgAAv3AgELfyMDIQQjA0EgaiQDIARBEmohBiAEQRBqIQcgBEEOaiEJIARBDGohCiAEQQhqIgVBATYCACAEQQRqIgNBADYCACAEIgtBADYCACAAQdwAIAUgAxBABH8gACADKAIAIAUgCxBABH8CfyADIAMoAgBBBGoiCDYCACALKAIABEAgBkEAOwEAIAdBADsBACAAIAggBSAGEEEEQAJAQQAhCANAIAAgAygCAEECaiAFIAcQQUUNASAJQQA7AQAgCkEAOwEAQQECfwJAIAYuAQBBkQJHDQAgACADKAIAQQRqIAUgChBBRQ0AIAAgAygCAEEGaiAFIAkQQUUNACABIAkvAQA2AgAgAiAKLwEANgIAQQAMAQsgAyADKAIAIAcvAQBBBGpqNgIAQQELRQ0EGkEAIAhBAWoiCCALKAIATw0EGiADKAIAIQwgBkEAOwEAIAdBADsBACAAIAwgBSAGEEENAAsLCwtBAAsFQQALBUEACyENIAQkAyANCyoBAX8gAEEUECsiAzYCACAAIAFBBGo2AgQgAyACKAIANgIQIABBAToACAs3AQJ/IABBHGoiAigCACIDIAAoAiBGBEAgAEEYaiABELEBBSADIAEQbiACIAIoAgBBKGo2AgALCyMAIAAgASkCADcCACAAIAEoAgg2AgggAEEMaiABQQxqELQBCzwBAX8gAEEsECsiAzYCACAAIAFBBGo2AgQgA0EQaiIBIAIoAgA2AgAgAUEEaiACQQRqEMMDIABBAToACAs+AQF/IABBBGohAyABIAJHBEAgAygCACEAA0AgACABEG4gAyADKAIAQShqIgA2AgAgAUEoaiIBIAJHDQALCwtBAQF/QebMmTMgAUkEQBAACyABQebMmTNLBEAQAAUgACABQShsECsiAjYCBCAAIAI2AgAgACABQShsIAJqNgIICwtL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IARBmChBmCgQURAoIAMgACAAKAIAKAIMQT9xEQEAIAQQPgRAIAVCADcCACAFQQA2AgggBUGdKEEIECggAkIANwMAIAJBADYCCCACQaYoQQIQKCACQQxqIgFCADcCACABQQA2AgggAUGpKEECECggAkEYaiIBQgA3AwAgAUEANgIIIAFBrChBAhAoIAJBJGoiAUIANwIAIAFBADYCCCABQa8oQQIQKCACQTBqIgFCADcDACABQQA2AgggAUGyKEECEChBACEBA0AgAQRAQQEhAQUgACAAKAIAKAIMQT9xEQEAIQEgByAFIAhBDGwgAmoQ/QMgAyABIAcQPiEBIAcQJwsgCEEBaiIIQQVHDQALIAJBPGohAANAIABBdGoiABAnIAAgAkcNAAsgBRAnBUEAIQELIAQQJwVBACEBCwVBACEBCwVBACEBCyADEC0gBiQDIAELBABBAQt2AQN/IwMhBCMDQUBrJAMgBCICQQxqIgMgACABEDogAyACQThqIgAQPwRAIAMgACwAAEEAR0EqEEsEQCACQgA3AgAgAkEANgIIIAJB1SdBBBAoIANBCCACEEchACACECcFQQAhAAsFQQAhAAsgAxAtIAQkAyAACwQAQQILkQIBBn8jAyEEIwNB0ABqJAMgBEHFAGohBSAEQQxqIQMgBCICQRhqIgYgACABEDogBiACQcQAaiIAED8EQCADQgA3AgAgA0EANgIIIAAsAAAEQCACQgA3AgAgAkEANgIIIAJBhSdBCBAoBSACQgA3AgAgAkEANgIIIAJBjidBjicQURAoCyADQQtqIgAsAABBAEgEQAJ/IAMoAgAhByAFQQA6AAAgBwsgBRApIANBADYCBAUgBUEAOgAAIAMgBRApIABBADoAAAsgA0EAEDggAyACKQIANwIAIAMgAigCCDYCCCACQgA3AgAgAkEANgIIIAIQJyAGQQYgAxBHIQAgAxAnBUEAIQALIAYQLSAEJAMgAAsEAEEDC6sFAQt/IwMhCCMDQeAAaiQDIAhB3QBqIQQgCEEkaiEGIAgiA0EYaiECIANBMGoiByAAIAEQOiAHIANB3ABqIgEQPwRAIAZCADcCACAGQQA2AgggBkGiJkEQECggB0EQIAYQRwR/QQEFIANCADcDACADQgA3AwggA0IANwMQIAEsAAAEQCACQgA3AgAgAkEANgIIIAJBsyZBBBAoIANBC2oiASwAAEEASARAAn8gAygCACEJIARBADoAACAJCyAEECkgA0EANgIEBSAEQQA6AAAgAyAEECkgAUEAOgAACyADQQAQOCADIAIpAgA3AgAgAyACKAIINgIIIAJCADcCACACQQA2AgggAhAnIAJCADcCACACQQA2AgggAkG4JkEEECgFIAJCADcCACACQQA2AgggAkG9JkEEECggA0ELaiIBLAAAQQBIBEACfyADKAIAIQogBEEAOgAAIAoLIAQQKSADQQA2AgQFIARBADoAACADIAQQKSABQQA6AAALIANBABA4IAMgAikCADcCACADIAIoAgg2AgggAkIANwIAIAJBADYCCCACECcgAkIANwIAIAJBADYCCCACQcImQQQQKAsgA0EMaiIFQQtqIgEsAABBAEgEfwJ/IAUoAgAhCyAEQQA6AAAgCwsgBBApIANBADYCECAFBSAEQQA6AAAgBSAEECkgAUEAOgAAIAULIQEgBUEAEDggASACKQIANwIAIAEgAigCCDYCCCACQgA3AgAgAkEANgIIIAIQJyAAKAIAKAIMIQEgByAAIAFBP3ERAQAgAxA+BH8gACgCACgCDCEBIAcgACABQT9xEQEAIANBDGoQPgVBAAshDCADQRhqIQADQCAAQXRqIgAQJyAAIANHDQALIAwLIQAgBhAnBUEAIQALIAcQLSAIJAMgAAuNDAERfyMDIQYjA0GAAWokAyAGQfUAaiEFIAYiBEE8aiECIARByABqIgcgACABEDogByAEQfQAaiIBED8EfyAEQgA3AwAgBEIANwMIIARCADcDECAEQgA3AxggBEIANwMgIARCADcDKCAEQgA3AzAgBEEANgI4IAEsAAAEQCACQgA3AgAgAkEANgIIIAJBniVBCBAoIARBC2oiASwAAEEASARAAn8gBCgCACEIIAVBADoAACAICyAFECkgBEEANgIEBSAFQQA6AAAgBCAFECkgAUEAOgAACyAEQQAQOCAEIAIpAgA3AgAgBCACKAIINgIIIAJCADcCACACQQA2AgggAhAnIAJCADcCACACQQA2AgggAkGnJUEIECggBEEMaiIBQQtqIgMsAABBAEgEfwJ/IAEoAgAhCSAFQQA6AAAgCQsgBRApIARBADYCECABBSAFQQA6AAAgASAFECkgA0EAOgAAIAELIQMgAUEAEDggAyACKQIANwIAIAMgAigCCDYCCCACQgA3AgAgAkEANgIIIAIQJyACQgA3AgAgAkEANgIIIAJBsCVBBBAoIARBGGoiAUELaiIDLAAAQQBIBH8CfyABKAIAIQogBUEAOgAAIAoLIAUQKSAEQQA2AhwgAQUgBUEAOgAAIAEgBRApIANBADoAACABCyEDIAFBABA4IAMgAikCADcCACADIAIoAgg2AgggAkIANwIAIAJBADYCCCACECcgAkIANwIAIAJBADYCCCACQbUlQQIQKCAEQSRqIgFBC2oiAywAAEEASAR/An8gASgCACELIAVBADoAACALCyAFECkgBEEANgIoIAEFIAVBADoAACABIAUQKSADQQA6AAAgAQshAyABQQAQOCADIAIpAgA3AgAgAyACKAIINgIIIAJCADcCACACQQA2AgggAhAnIAJCADcCACACQQA2AgggAkG4JUEIECgFIAJCADcCACACQQA2AgggAkHBJUEIECggBEELaiIBLAAAQQBIBEACfyAEKAIAIQwgBUEAOgAAIAwLIAUQKSAEQQA2AgQFIAVBADoAACAEIAUQKSABQQA6AAALIARBABA4IAQgAikCADcCACAEIAIoAgg2AgggAkIANwIAIAJBADYCCCACECcgAkIANwIAIAJBADYCCCACQcolQQgQKCAEQQxqIgFBC2oiAywAAEEASAR/An8gASgCACENIAVBADoAACANCyAFECkgBEEANgIQIAEFIAVBADoAACABIAUQKSADQQA6AAAgAQshAyABQQAQOCADIAIpAgA3AgAgAyACKAIINgIIIAJCADcCACACQQA2AgggAhAnIAJCADcCACACQQA2AgggAkHTJUEEECggBEEYaiIBQQtqIgMsAABBAEgEfwJ/IAEoAgAhDiAFQQA6AAAgDgsgBRApIARBADYCHCABBSAFQQA6AAAgASAFECkgA0EAOgAAIAELIQMgAUEAEDggAyACKQIANwIAIAMgAigCCDYCCCACQgA3AgAgAkEANgIIIAIQJyACQgA3AgAgAkEANgIIIAJB2CVBAhAoIARBJGoiAUELaiIDLAAAQQBIBH8CfyABKAIAIQ8gBUEAOgAAIA8LIAUQKSAEQQA2AiggAQUgBUEAOgAAIAEgBRApIANBADoAACABCyEDIAFBABA4IAMgAikCADcCACADIAIoAgg2AgggAkIANwIAIAJBADYCCCACECcgAkIANwIAIAJBADYCCCACQdslQQgQKAsgBEEwaiIBQQtqIgMsAABBAEgEfwJ/IAEoAgAhECAFQQA6AAAgEAsgBRApIARBADYCNCABBSAFQQA6AAAgASAFECkgA0EAOgAAIAELIQMgAUEAEDggAyACKQIANwIAIAMgAigCCDYCCCACQgA3AgAgAkEANgIIIAIQJwJ/IARBPGohEUEAIQNBACEBA0AgACgCACgCDCEFIAMgByAAIAVBP3ERAQAgAUEMbCAEahA+QQFxaiEDIAFBAWoiAUEFRw0ACyARCyEAA0AgAEF0aiIAECcgACAERw0ACyADQQFLBUEACyESIAcQLSAGJAMgEgsFAEGACAt6AQR/IwMhAiMDQRBqJAMgAkEEaiEDIAIhBCACQQxqIgUgAEF/ajYCACACQQhqIgBByRkQHxBvIAAQuQIEQCADEHkgBCAAIAUQrgIgBCgCAEH+GSADIAEQmQIgBBAsIAMQLCAAECwgAiQDBUHaGUH5FkHEAEHvGRALCwsEAEEFC/cEAQl/IwMhByMDQeAAaiQDIAdB0QBqIQQgByIDQRhqIQIgA0EkaiIGIAAgARA6IAYgA0HQAGoiARA/BEAgA0IANwMAIANCADcDCCADQgA3AxAgASwAAARAIAJCADcCACACQQA2AgggAkHMJEEEECggA0ELaiIBLAAAQQBIBEACfyADKAIAIQggBEEAOgAAIAgLIAQQKSADQQA2AgQFIARBADoAACADIAQQKSABQQA6AAALIANBABA4IAMgAikCADcCACADIAIoAgg2AgggAkIANwIAIAJBADYCCCACECcgAkIANwIAIAJBADYCCCACQdEkQQQQKAUgAkIANwIAIAJBADYCCCACQdYkQQQQKCADQQtqIgEsAABBAEgEQAJ/IAMoAgAhCSAEQQA6AAAgCQsgBBApIANBADYCBAUgBEEAOgAAIAMgBBApIAFBADoAAAsgA0EAEDggAyACKQIANwIAIAMgAigCCDYCCCACQgA3AgAgAkEANgIIIAIQJyACQgA3AgAgAkEANgIIIAJB2yRBBBAoCyADQQxqIgFBC2oiBSwAAEEASAR/An8gASgCACEKIARBADoAACAKCyAEECkgA0EANgIQIAEFIARBADoAACABIAQQKSAFQQA6AAAgAQshBCABQQAQOCAEIAIpAgA3AgAgBCACKAIINgIIIAJCADcCACACQQA2AgggAhAnIAAoAgAoAgwhASAGIAAgAUE/cREBACADED4EfyAAKAIAKAIMIQEgBiAAIAFBP3ERAQAgA0EMahA+BUEACyEBIANBGGohAANAIABBdGoiABAnIAAgA0cNAAsFQQAhAQsgBhAtIAckAyABCwQAQQYLcAEDfyMDIQMjA0FAayQDIAMiAkEMaiIEIAAgARA6IAEgAkE4ahA/BEAgAkIANwIAIAJBADYCCCACQYUkQQgQKCAAKAIAKAIMIQEgBCAAIAFBP3ERAQAgAhA+IQAgAhAnBUEAIQALIAQQLSADJAMgAAsEAEEHC14BBH8jAyECIwNBQGskAyAAKAIAKAIMIQQgAkEMaiIDIAEgACAEQT9xEQEAEJcBIAJCADcCACACQQA2AgggAkHCI0EEECggA0EAIAIQRyEFIAIQJyADEC0gAiQDIAULYQEDfyMDIQMjA0EwaiQDIAMiAiAAIAEQOiACIAJBLGoiABA/BH8gAiAALAAAQQBHIgBBKhBLBH8gAiAAEMkBBH8gAhDIAUEBcwVBAAsFQQALBUEACyEEIAIQLSADJAMgBAsEAEEJC2kBAX8jAyECIwNBEGokAyAAEGcgAiABQTBqELABIABB/xcgAhA8IAIQLCACIAFBPGoQsAEgAEGFGCACEDwgAhAsIAIgARC4AyAAIAIQvgMgAhAsIAIgARCwAyAAIAIQtQMgAhAsIAIkAwtLAQR/IAAoAgAiAQRAAn8gASAAQQRqIgMoAgAiAkYEfyABBQNAIAJBdGoiAhAnIAEgAkcNAAsgACgCAAshBCADIAE2AgAgBAsQMQsLPgEBfyAAQQRqIQMgASACRwRAIAMoAgAhAANAIAAgARB/IAMgAygCAEEMaiIANgIAIAFBDGoiASACRw0ACwsLagEDfyMDIQMjA0EwaiQDIAMiAiAAIAEQOiACIAJBLGoiABA/BH8gAiAALAAAQQBHIgBBKhBLBH8gAiAAEGYEfyACIAAQyQEEfyACEMgBBUEACwVBAAsFQQALBUEACyEEIAIQLSADJAMgBAsEAEEKC54BAQN/IwMhBCMDQUBrJAMgBCICQQxqIgMgACABEDogAyACQThqIgEQPwRAAkAgAyABLAAAQQBHIgFB0p4BEEtFBEAgAyABQdKmARBLRQRAQQAhAAwCCwsgAkIANwIAIAJBADYCCCACQeshQeshEFEQKCADIAAgACgCACgCDEE/cREBACACED4hACACECcLBUEAIQALIAMQLSAEJAMgAAsFAEG4FwsEAEELC9wBAQR/IwMhBSMDQdAAaiQDIAVBDGohBCAFIgJBGGoiAyAAIAEQOiADIAJBxABqIgEQPwRAIAMgASwAAEEARyIBQSoQSwRAIAMgARBmBEAgBEIANwIAIARBADYCCCAEQZ0hQQYQKCACQgA3AgAgAkEANgIIIAJBpCFBCBAoIAAoAgAoAgwhASADIAAgAUE/cREBACAEED4Ef0EBBSAAKAIAKAIMIQEgAyAAIAFBP3ERAQAgAhA+CyEAIAIQJyAEECcFQQAhAAsFQQAhAAsFQQAhAAsgAxAtIAUkAyAACwUAQYAKCwQAQQwLjgEBBH8jAyECIwNB0ABqJAMgAkEYaiIDIAAgARA6IAIiAUIANwMAIAFBADYCCCABQc0gQQgQKCABQQxqIgBCADcCACAAQQA2AgggAEHWIEEIECggA0EAIAEQRwR/QQEFIANBACAAEEcLIQUgAUEYaiEAA0AgAEF0aiIAECcgACABRw0ACyADEC0gAiQDIAULBABBDQtOAQN/IwMhAiMDQUBrJAMgAkEMaiIDIAAgARA6IAJCADcCACACQQA2AgggAkGGIEGGIBBRECggA0EAIAIQRyEEIAIQJyADEC0gAiQDIAQLTgEDfyMDIQIjA0FAayQDIAJBDGoiAyAAIAEQOiACQgA3AgAgAkEANgIIIAJBuR9BuR8QURAoIANBGSACEEchBCACECcgAxAtIAIkAyAECwQAQSQLGwECfyMDIQIgACMDaiQDIwNBD2pBcHEkAyACCwu2MAQAQYAIC/oF3AoAAOYLAAAECwAA0wsAAAAEAAAAAAAA3AoAAFwMAABICwAAHQwAAAAAAAABAAAAGAQAAAAAAADcCgAAAw0AANwKAAAWDQAABAsAALwOAABYBAAAAAAAANwKAAD6DgAABAsAAD0PAABYBAAAAAAAAAQLAAB7DwAAWAQAAAAAAAAECwAAwQ8AAFgEAAAAAAAABAsAAA8QAABYBAAAAAAAAAQLAABfEAAAWAQAAAAAAAAECwAArRAAAFgEAAAAAAAABAsAAPEQAABYBAAAAAAAAAQLAABGEQAAWAQAAAAAAAAECwAAhBEAAFgEAAAAAAAABAsAAMcRAABYBAAAAAAAAAQLAAAOEgAAWAQAAAAAAAAECwAAYBIAAFgEAAAAAAAABAsAAOQSAABYBAAAAAAAAAQLAABHEwAAWAQAAAAAAAAECwAAlxMAAFgEAAAAAAAABAsAANoTAABYBAAAAAAAAAQLAAA1FAAAWAQAAAAAAAAECwAA4RQAACgGAAAAAAAABAsAAGgVAABABAAAAAAAANwKAAAsGAAA3AoAAGsYAADcCgAAqRgAANwKAADvGAAA3AoAACwZAADcCgAASxkAANwKAABqGQAA3AoAAIkZAADcCgAAqBkAANwKAADHGQAA3AoAAOYZAADcCgAAIxoAAEgLAABCGgAAAAAAAAEAAAAYBAAAAAAAAEgLAACBGgAAAAAAAAEAAAAYBAAAAAAAANwKAAAlGwAASAsAAD4bAAAAAAAAAQAAACAGAAAAAAAABAsAAK8bAABQBgAAAAAAAAQLAABcGwAAYAYAAAAAAADcCgAAfRsAAAQLAACKGwAAQAYAAAAAAAAECwAA0RsAAFAGAAAAAAAALAsAAPkbAAAsCwAAsw0AACwLAAD7GwAALAsAAP0bAAAsCwAAqQ0AACwLAAD/GwAALAsAAAEcAAAsCwAAAxwAACwLAAAFHAAALAsAAAccAAAsCwAACRwAACwLAAALHAAALAsAAA0cAAAECwAADxwAAEAGAEGEDgsNCAQAABUAAAAWAAAAFQBBmQ4LiAMEAAAVAAAAFwAAABUAAACQBgAAiAYAADgEAAA4BAAAAAAAAEAEAAAYAAAAGQAAABUAAAAVAAAAFQAAAAAAAABIBAAAGgAAABsAAAAVAAAAFgAAABUAAAAAAAAAWAQAABoAAAAcAAAAFQAAABUAAAAVAAAAAAAAAGAEAAAaAAAAHQAAABcAAAAYAAAAFgAAAAAAAABwBAAAGgAAAB4AAAAZAAAAGgAAABcAAAAAAAAAgAQAABoAAAAfAAAAGwAAABwAAAAYAAAAAAAAAJAEAAAaAAAAIAAAAB0AAAAeAAAAGQAAAAAAAACgBAAAGgAAACEAAAAfAAAAIAAAABoAAAAAAAAAsAQAABoAAAAiAAAAIQAAACIAAAAbAAAAAAAAAMAEAAAaAAAAIwAAACMAAAAkAAAAHAAAAAAAAADQBAAAGgAAACQAAAAlAAAAJgAAAB0AAAAAAAAA4AQAABoAAAAlAAAAJwAAACgAAAAeAAAAAAAAAPAEAAAaAAAAJgAAACkAAAAqAAAAHwBBqRELiycFAAAaAAAAJwAAACsAAAAsAAAAIAAAAAAAAAAQBQAAGgAAACgAAAAtAAAALgAAACEAAAAAAAAAIAUAABoAAAApAAAALwAAADAAAAAiAAAAAAAAADAFAAAaAAAAKgAAADEAAAAyAAAAIwAAAAAAAABABQAAGgAAACsAAAAzAAAANAAAACQAAAAAAAAAUAUAABoAAAAsAAAANQAAADYAAAAlAAAAAAAAAGAFAAAaAAAALQAAADcAAAA4AAAAJgAAAAAAAABwBQAALgAAAC8AAAAwAAAAJwAAADEAAAAAAAAAgAUAABgAAAAyAAAAOQAAADoAAAAVAAAASgEAAAKgAAADoAAAAgIAAAECAABKAQAAAaAAAAOQAACaggAAnYIAAAqSAAAliAAAJ4gAAAMBAAAyAQAAaYcAAI2CAAAPAQAAEAEAABIBAAAGAQAAAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAB0AAAACAgAAAQIAAAQAAAAFAAAABgAAAAcAAAAXAAAALgAAAAICAAABAgAAAgIAAAECAAAAAQAAAQEAAAICAAABAgAASgEAAAABAAAgIAAAQCAAADcAAABphwAAfJIAABMRAAACAQAAAQEAAAABAAABAQAAAgIAAAECAAAXAQAAEQEAAEoBAAAgxgAAAAEAAAEBAAAXAQAAEQEAAEoBAAADoAAAAqAAABcBAAARAQAAA6AAAAKgAAACAgAAAQIAAEoBAAAAAAAAQAYAADMAAAA0AAAANQAAADYAAAAVAAAAFQAAABYAAAAVAAAAAAAAAGgGAAAzAAAANwAAADUAAAA2AAAAFQAAABYAAAAXAAAAFgAAAAAAAAB4BgAAMwAAADgAAAA1AAAANgAAABYAAAAAAAAA8AYAADMAAAA5AAAANQAAADYAAAAVAAAAFwAAABgAAAAXAAAAZGF0YSAmJiBjYWxsYmFjawBwaWV4LmNwcABSZWFkSW1hZ2UAZXJyb3IAZmFpbGVkIHRvIGV4dHJhY3QgcHJldmlldwB1bnN1cHBvcnRlZCBwcmV2aWV3IHR5cGUAdW5rbm93biBlcnJvcgAxNlBpZXhTdHJlYW1SZWFkZXIATjRwaWV4MTVTdHJlYW1JbnRlcmZhY2VFAG1ha2VyAG1vZGVsAHByZXZpZXcAdGh1bWJuYWlsAE5TdDNfXzIxMmJhc2ljX3N0cmluZ0ljTlNfMTFjaGFyX3RyYWl0c0ljRUVOU185YWxsb2NhdG9ySWNFRUVFAE5TdDNfXzIyMV9fYmFzaWNfc3RyaW5nX2NvbW1vbklMYjFFRUUAY29sb3JTcGFjZQBvcmllbnRhdGlvbgBmb3JtYXQAb2Zmc2V0AGxlbmd0aAB3aWR0aABoZWlnaHQAYWRvYmVSZ2IAc1JnYgBmdW5jdGlvblBvaW50ZXJzAGNhbGxiYWNrcy5hczxib29sPigpAENhbGxiYWNrUmVzdWx0AGNhbGwATjEwZW1zY3JpcHRlbjN2YWxFAE40cGlleDEyYmluYXJ5X3BhcnNlMTRQYWdlZEJ5dGVBcnJheUUAIWNoZWNrZXJzXy5lbXB0eSgpAG5vZGVfbW9kdWxlcy9waWV4L3NyYy9pbWFnZV90eXBlX3JlY29nbml0aW9uL2ltYWdlX3R5cGVfcmVjb2duaXRpb25fbGl0ZS5jYwBSZXF1ZXN0ZWRTaXplAGEAQ29tcGFyZQBiAEZPVmIAcG9zX2luX3BhZ2UgPCBjdXJyZW50X3BhZ2VfbGVuXwBub2RlX21vZHVsZXMvcGlleC9zcmMvYmluYXJ5X3BhcnNlL3JhbmdlX2NoZWNrZWRfYnl0ZV9wdHIuaABvcGVyYXRvcltdAG9mZnNldCA+PSBzdWJfYXJyYXlfYmVnaW5fICYmIG9mZnNldCA8IHN1Yl9hcnJheV9lbmRfAG5vZGVfbW9kdWxlcy9waWV4L3NyYy9iaW5hcnlfcGFyc2UvcmFuZ2VfY2hlY2tlZF9ieXRlX3B0ci5jYwBsb2FkUGFnZUZvck9mZnNldABmYWxzZQByZW1haW5pbmdMZW5ndGgATjRwaWV4MjJpbWFnZV90eXBlX3JlY29nbml0aW9uMTJfR0xPQkFMX19OXzExNFgzZlR5cGVDaGVja2VyRQBONHBpZXgyMmltYWdlX3R5cGVfcmVjb2duaXRpb24xMl9HTE9CQUxfX05fMTExVHlwZUNoZWNrZXJFAFNBTVNVTkcATjRwaWV4MjJpbWFnZV90eXBlX3JlY29nbml0aW9uMTJfR0xPQkFMX19OXzExNFNyd1R5cGVDaGVja2VyRQBONHBpZXgyMmltYWdlX3R5cGVfcmVjb2duaXRpb24xMl9HTE9CQUxfX05fMTE0UncyVHlwZUNoZWNrZXJFAEFSRUNPWUsATjRwaWV4MjJpbWFnZV90eXBlX3JlY29nbml0aW9uMTJfR0xPQkFMX19OXzEyMVJhd0NvbnRheE5UeXBlQ2hlY2tlckUARlVKSUZJTE0ATjRwaWV4MjJpbWFnZV90eXBlX3JlY29nbml0aW9uMTJfR0xPQkFMX19OXzExNFJhZlR5cGVDaGVja2VyRQBxa3RrAAAACABxa3RuAAAACABONHBpZXgyMmltYWdlX3R5cGVfcmVjb2duaXRpb24xMl9HTE9CQUxfX05fMTE0UXRrVHlwZUNoZWNrZXJFAEFPQwBNTQBQRU5UQVggAABONHBpZXgyMmltYWdlX3R5cGVfcmVjb2duaXRpb24xMl9HTE9CQUxfX05fMTE0UGVmVHlwZUNoZWNrZXJFAE9MWU1QAE40cGlleDIyaW1hZ2VfdHlwZV9yZWNvZ25pdGlvbjEyX0dMT0JBTF9fTl8xMTRPcmZUeXBlQ2hlY2tlckUATlJXICAgAE5JS09OAAIUAAUAFAIFAABONHBpZXgyMmltYWdlX3R5cGVfcmVjb2duaXRpb24xMl9HTE9CQUxfX05fMTE0TnJ3VHlwZUNoZWNrZXJFAE40cGlleDIyaW1hZ2VfdHlwZV9yZWNvZ25pdGlvbjEyX0dMT0JBTF9fTl8xMTROZWZUeXBlQ2hlY2tlckUAAE1STQBONHBpZXgyMmltYWdlX3R5cGVfcmVjb2duaXRpb24xMl9HTE9CQUxfX05fMTE0TXJ3VHlwZUNoZWNrZXJFAFBLVFMAAAABAE40cGlleDIyaW1hZ2VfdHlwZV9yZWNvZ25pdGlvbjEyX0dMT0JBTF9fTl8xMTRNb3NUeXBlQ2hlY2tlckUA+g0AAQD6AAACAA36AQAAAPoCAABONHBpZXgyMmltYWdlX3R5cGVfcmVjb2duaXRpb24xMl9HTE9CQUxfX05fMTE0S2RjVHlwZUNoZWNrZXJFAMYSAAEAAAAEAMYTAAEAAAAEAMYUAAIAxiAAxi0ABAAAAAEAEsYBAAQAAAAAE8YBAAQAAAAAFMYCAAAgxgAtxgQAAQAAAABONHBpZXgyMmltYWdlX3R5cGVfcmVjb2duaXRpb24xMl9HTE9CQUxfX05fMTE0RG5nVHlwZUNoZWNrZXJFAEtPREFLICAgICAgICAgICAAA+kAAgAM5QACAOkDAgAA5QwCAABONHBpZXgyMmltYWdlX3R5cGVfcmVjb2duaXRpb24xMl9HTE9CQUxfX05fMTE0RGNyVHlwZUNoZWNrZXJFAAAQurCsuwACAEhFQVBDQ0RSAE40cGlleDIyaW1hZ2VfdHlwZV9yZWNvZ25pdGlvbjEyX0dMT0JBTF9fTl8xMTRDcndUeXBlQ2hlY2tlckUAQ1ICAABONHBpZXgyMmltYWdlX3R5cGVfcmVjb2duaXRpb24xMl9HTE9CQUxfX05fMTE0Q3IyVHlwZUNoZWNrZXJFAFNPTlkAALABAAQAAAAAAgAAAwAAAwEAAwIAAwMATjRwaWV4MjJpbWFnZV90eXBlX3JlY29nbml0aW9uMTJfR0xPQkFMX19OXzExNEFyd1R5cGVDaGVja2VyRQBhcnJheQBSYW5nZUNoZWNrZWRCeXRlUHRyAE5TdDNfXzIxNGRlZmF1bHRfZGVsZXRlSU40cGlleDEyYmluYXJ5X3BhcnNlMTJfR0xPQkFMX19OXzEyME1lbW9yeVBhZ2VkQnl0ZUFycmF5RUVFAE5TdDNfXzIyMF9fc2hhcmVkX3B0cl9wb2ludGVySVBONHBpZXgxMmJpbmFyeV9wYXJzZTEyX0dMT0JBTF9fTl8xMjBNZW1vcnlQYWdlZEJ5dGVBcnJheUVOU18xNGRlZmF1bHRfZGVsZXRlSVM0X0VFTlNfOWFsbG9jYXRvcklTNF9FRUVFAE40cGlleDEyYmluYXJ5X3BhcnNlMTJfR0xPQkFMX19OXzEyME1lbW9yeVBhZ2VkQnl0ZUFycmF5RQBTaXplT2ZUeXBlKHR5cGUsIE5VTEwgKSAqIGNvdW50ID09IHZhbHVlLnNpemUoKQBub2RlX21vZHVsZXMvcGlleC9zcmMvdGlmZl9kaXJlY3RvcnkvdGlmZl9kaXJlY3RvcnkuY2MAQWRkRW50cnkASUlNTXZvaWQAYm9vbABzdGQ6OnN0cmluZwBzdGQ6OmJhc2ljX3N0cmluZzx1bnNpZ25lZCBjaGFyPgBzdGQ6OndzdHJpbmcAZW1zY3JpcHRlbjo6dmFsAGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PHNpZ25lZCBjaGFyPgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzx1bnNpZ25lZCBjaGFyPgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzxzaG9ydD4AZW1zY3JpcHRlbjo6bWVtb3J5X3ZpZXc8dW5zaWduZWQgc2hvcnQ+AGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PGludD4AZW1zY3JpcHRlbjo6bWVtb3J5X3ZpZXc8dW5zaWduZWQgaW50PgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzxpbnQ4X3Q+AGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PHVpbnQ4X3Q+AGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PGludDE2X3Q+AGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PHVpbnQxNl90PgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzxpbnQzMl90PgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzx1aW50MzJfdD4AZW1zY3JpcHRlbjo6bWVtb3J5X3ZpZXc8bG9uZyBkb3VibGU+AE4xMGVtc2NyaXB0ZW4xMW1lbW9yeV92aWV3SWVFRQBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzxkb3VibGU+AE4xMGVtc2NyaXB0ZW4xMW1lbW9yeV92aWV3SWRFRQBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzxmbG9hdD4ATjEwZW1zY3JpcHRlbjExbWVtb3J5X3ZpZXdJZkVFAGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PHVuc2lnbmVkIGxvbmc+AE4xMGVtc2NyaXB0ZW4xMW1lbW9yeV92aWV3SW1FRQBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzxsb25nPgBOMTBlbXNjcmlwdGVuMTFtZW1vcnlfdmlld0lsRUUATjEwZW1zY3JpcHRlbjExbWVtb3J5X3ZpZXdJakVFAE4xMGVtc2NyaXB0ZW4xMW1lbW9yeV92aWV3SWlFRQBOMTBlbXNjcmlwdGVuMTFtZW1vcnlfdmlld0l0RUUATjEwZW1zY3JpcHRlbjExbWVtb3J5X3ZpZXdJc0VFAE4xMGVtc2NyaXB0ZW4xMW1lbW9yeV92aWV3SWhFRQBOMTBlbXNjcmlwdGVuMTFtZW1vcnlfdmlld0lhRUUAZW1zY3JpcHRlbjo6bWVtb3J5X3ZpZXc8Y2hhcj4ATjEwZW1zY3JpcHRlbjExbWVtb3J5X3ZpZXdJY0VFAE5TdDNfXzIxMmJhc2ljX3N0cmluZ0l3TlNfMTFjaGFyX3RyYWl0c0l3RUVOU185YWxsb2NhdG9ySXdFRUVFAE5TdDNfXzIxMmJhc2ljX3N0cmluZ0loTlNfMTFjaGFyX3RyYWl0c0loRUVOU185YWxsb2NhdG9ySWhFRUVFAGRvdWJsZQBmbG9hdAB1bnNpZ25lZCBsb25nAGxvbmcAdW5zaWduZWQgaW50AGludAB1bnNpZ25lZCBzaG9ydABzaG9ydAB1bnNpZ25lZCBjaGFyAHNpZ25lZCBjaGFyAGNoYXIATlN0M19fMjE0X19zaGFyZWRfY291bnRFAE5TdDNfXzIxOV9fc2hhcmVkX3dlYWtfY291bnRFAE4xMF9fY3h4YWJpdjExNl9fc2hpbV90eXBlX2luZm9FAFN0OXR5cGVfaW5mbwBOMTBfX2N4eGFiaXYxMjBfX3NpX2NsYXNzX3R5cGVfaW5mb0UATjEwX19jeHhhYml2MTE3X19jbGFzc190eXBlX2luZm9FAE4xMF9fY3h4YWJpdjEyM19fZnVuZGFtZW50YWxfdHlwZV9pbmZvRQB2AGMAaABzAHQAaQBqAGwAbQBmAGQATjEwX19jeHhhYml2MTIxX192bWlfY2xhc3NfdHlwZV9pbmZvRQ==";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}function getBinary(){try{if(Module["wasmBinary"]){return new Uint8Array(Module["wasmBinary"])}var binary=tryParseAsDataURI(wasmBinaryFile);if(binary){return binary}if(Module["readBinary"]){return Module["readBinary"](wasmBinaryFile)}else{throw"both async and sync fetching of the wasm failed"}}catch(err){abort(err)}}function getBinaryPromise(){if(!Module["wasmBinary"]&&(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER)&&typeof fetch==="function"){return fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){if(!response["ok"]){throw"failed to load wasm binary file at '"+wasmBinaryFile+"'"}return response["arrayBuffer"]()}).catch(function(){return getBinary()})}return new Promise(function(resolve,reject){resolve(getBinary())})}function createWasm(env){var info={"env":env,"global":{"NaN":NaN,Infinity:Infinity},"global.Math":Math,"asm2wasm":asm2wasmImports};function receiveInstance(instance,module){var exports=instance.exports;Module["asm"]=exports;removeRunDependency("wasm-instantiate")}addRunDependency("wasm-instantiate");if(Module["instantiateWasm"]){try{return Module["instantiateWasm"](info,receiveInstance)}catch(e){err("Module.instantiateWasm callback failed with error: "+e);return false}}function receiveInstantiatedSource(output){receiveInstance(output["instance"])}function instantiateArrayBuffer(receiver){getBinaryPromise().then(function(binary){return WebAssembly.instantiate(binary,info)}).then(receiver,function(reason){err("failed to asynchronously prepare wasm: "+reason);abort(reason)})}if(!Module["wasmBinary"]&&typeof WebAssembly.instantiateStreaming==="function"&&!isDataURI(wasmBinaryFile)&&typeof fetch==="function"){WebAssembly.instantiateStreaming(fetch(wasmBinaryFile,{credentials:"same-origin"}),info).then(receiveInstantiatedSource,function(reason){err("wasm streaming compile failed: "+reason);err("falling back to ArrayBuffer instantiation");instantiateArrayBuffer(receiveInstantiatedSource)})}else{instantiateArrayBuffer(receiveInstantiatedSource)}return{}}Module["asm"]=function(global,env,providedBuffer){env["memory"]=wasmMemory;env["table"]=wasmTable=new WebAssembly.Table({"initial":384,"maximum":384,"element":"anyfunc"});env["__memory_base"]=1024;env["__table_base"]=0;var exports=createWasm(env);return exports};__ATINIT__.push({func:function(){__GLOBAL__sub_I_bind_cpp()}});function ___assert_fail(condition,filename,line,func){abort("Assertion failed: "+UTF8ToString(condition)+", at: "+[filename?UTF8ToString(filename):"unknown filename",line,func?UTF8ToString(func):"unknown function"])}function ___cxa_pure_virtual(){ABORT=true;throw"Pure virtual function called!"}function getShiftFromSize(size){switch(size){case 1:return 0;case 2:return 1;case 4:return 2;case 8:return 3;default:throw new TypeError("Unknown type size: "+size)}}function embind_init_charCodes(){var codes=new Array(256);for(var i=0;i<256;++i){codes[i]=String.fromCharCode(i)}embind_charCodes=codes}var embind_charCodes=undefined;function readLatin1String(ptr){var ret="";var c=ptr;while(HEAPU8[c]){ret+=embind_charCodes[HEAPU8[c++]]}return ret}var awaitingDependencies={};var registeredTypes={};var typeDependencies={};var char_0=48;var char_9=57;function makeLegalFunctionName(name){if(undefined===name){return"_unknown"}name=name.replace(/[^a-zA-Z0-9_]/g,"$");var f=name.charCodeAt(0);if(f>=char_0&&f<=char_9){return"_"+name}else{return name}}function createNamedFunction(name,body){name=makeLegalFunctionName(name);return function(){"use strict";return body.apply(this,arguments)}}function extendError(baseErrorType,errorName){var errorClass=createNamedFunction(errorName,function(message){this.name=errorName;this.message=message;var stack=new Error(message).stack;if(stack!==undefined){this.stack=this.toString()+"\n"+stack.replace(/^Error(:[^\n]*)?\n/,"")}});errorClass.prototype=Object.create(baseErrorType.prototype);errorClass.prototype.constructor=errorClass;errorClass.prototype.toString=function(){if(this.message===undefined){return this.name}else{return this.name+": "+this.message}};return errorClass}var BindingError=undefined;function throwBindingError(message){throw new BindingError(message)}var InternalError=undefined;function registerType(rawType,registeredInstance,options){options=options||{};if(!("argPackAdvance"in registeredInstance)){throw new TypeError("registerType registeredInstance requires argPackAdvance")}var name=registeredInstance.name;if(!rawType){throwBindingError('type "'+name+'" must have a positive integer typeid pointer')}if(registeredTypes.hasOwnProperty(rawType)){if(options.ignoreDuplicateRegistrations){return}else{throwBindingError("Cannot register type '"+name+"' twice")}}registeredTypes[rawType]=registeredInstance;delete typeDependencies[rawType];if(awaitingDependencies.hasOwnProperty(rawType)){var callbacks=awaitingDependencies[rawType];delete awaitingDependencies[rawType];callbacks.forEach(function(cb){cb()})}}function __embind_register_bool(rawType,name,size,trueValue,falseValue){var shift=getShiftFromSize(size);name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":function(wt){return!!wt},"toWireType":function(destructors,o){return o?trueValue:falseValue},"argPackAdvance":8,"readValueFromPointer":function(pointer){var heap;if(size===1){heap=HEAP8}else if(size===2){heap=HEAP16}else if(size===4){heap=HEAP32}else{throw new TypeError("Unknown boolean type size: "+name)}return this["fromWireType"](heap[pointer>>shift])},destructorFunction:null})}var emval_free_list=[];var emval_handle_array=[{},{value:undefined},{value:null},{value:true},{value:false}];function __emval_decref(handle){if(handle>4&&0===--emval_handle_array[handle].refcount){emval_handle_array[handle]=undefined;emval_free_list.push(handle)}}function count_emval_handles(){var count=0;for(var i=5;i<emval_handle_array.length;++i){if(emval_handle_array[i]!==undefined){++count}}return count}function get_first_emval(){for(var i=5;i<emval_handle_array.length;++i){if(emval_handle_array[i]!==undefined){return emval_handle_array[i]}}return null}function init_emval(){Module["count_emval_handles"]=count_emval_handles;Module["get_first_emval"]=get_first_emval}function __emval_register(value){switch(value){case undefined:{return 1}case null:{return 2}case true:{return 3}case false:{return 4}default:{var handle=emval_free_list.length?emval_free_list.pop():emval_handle_array.length;emval_handle_array[handle]={refcount:1,value:value};return handle}}}function simpleReadValueFromPointer(pointer){return this["fromWireType"](HEAPU32[pointer>>2])}function __embind_register_emval(rawType,name){name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":function(handle){var rv=emval_handle_array[handle].value;__emval_decref(handle);return rv},"toWireType":function(destructors,value){return __emval_register(value)},"argPackAdvance":8,"readValueFromPointer":simpleReadValueFromPointer,destructorFunction:null})}function _embind_repr(v){if(v===null){return"null"}var t=typeof v;if(t==="object"||t==="array"||t==="function"){return v.toString()}else{return""+v}}function floatReadValueFromPointer(name,shift){switch(shift){case 2:return function(pointer){return this["fromWireType"](HEAPF32[pointer>>2])};case 3:return function(pointer){return this["fromWireType"](HEAPF64[pointer>>3])};default:throw new TypeError("Unknown float type: "+name)}}function __embind_register_float(rawType,name,size){var shift=getShiftFromSize(size);name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":function(value){return value},"toWireType":function(destructors,value){if(typeof value!=="number"&&typeof value!=="boolean"){throw new TypeError('Cannot convert "'+_embind_repr(value)+'" to '+this.name)}return value},"argPackAdvance":8,"readValueFromPointer":floatReadValueFromPointer(name,shift),destructorFunction:null})}function integerReadValueFromPointer(name,shift,signed){switch(shift){case 0:return signed?function readS8FromPointer(pointer){return HEAP8[pointer]}:function readU8FromPointer(pointer){return HEAPU8[pointer]};case 1:return signed?function readS16FromPointer(pointer){return HEAP16[pointer>>1]}:function readU16FromPointer(pointer){return HEAPU16[pointer>>1]};case 2:return signed?function readS32FromPointer(pointer){return HEAP32[pointer>>2]}:function readU32FromPointer(pointer){return HEAPU32[pointer>>2]};default:throw new TypeError("Unknown integer type: "+name)}}function __embind_register_integer(primitiveType,name,size,minRange,maxRange){name=readLatin1String(name);if(maxRange===-1){maxRange=4294967295}var shift=getShiftFromSize(size);var fromWireType=function(value){return value};if(minRange===0){var bitshift=32-8*size;fromWireType=function(value){return value<<bitshift>>>bitshift}}var isUnsignedType=name.indexOf("unsigned")!=-1;registerType(primitiveType,{name:name,"fromWireType":fromWireType,"toWireType":function(destructors,value){if(typeof value!=="number"&&typeof value!=="boolean"){throw new TypeError('Cannot convert "'+_embind_repr(value)+'" to '+this.name)}if(value<minRange||value>maxRange){throw new TypeError('Passing a number "'+_embind_repr(value)+'" from JS side to C/C++ side to an argument of type "'+name+'", which is outside the valid range ['+minRange+", "+maxRange+"]!")}return isUnsignedType?value>>>0:value|0},"argPackAdvance":8,"readValueFromPointer":integerReadValueFromPointer(name,shift,minRange!==0),destructorFunction:null})}function __embind_register_memory_view(rawType,dataTypeIndex,name){var typeMapping=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array];var TA=typeMapping[dataTypeIndex];function decodeMemoryView(handle){handle=handle>>2;var heap=HEAPU32;var size=heap[handle];var data=heap[handle+1];return new TA(heap["buffer"],data,size)}name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":decodeMemoryView,"argPackAdvance":8,"readValueFromPointer":decodeMemoryView},{ignoreDuplicateRegistrations:true})}function __embind_register_std_string(rawType,name){name=readLatin1String(name);var stdStringIsUTF8=name==="std::string";registerType(rawType,{name:name,"fromWireType":function(value){var length=HEAPU32[value>>2];var str;if(stdStringIsUTF8){var endChar=HEAPU8[value+4+length];var endCharSwap=0;if(endChar!=0){endCharSwap=endChar;HEAPU8[value+4+length]=0}var decodeStartPtr=value+4;for(var i=0;i<=length;++i){var currentBytePtr=value+4+i;if(HEAPU8[currentBytePtr]==0){var stringSegment=UTF8ToString(decodeStartPtr);if(str===undefined)str=stringSegment;else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+1}}if(endCharSwap!=0)HEAPU8[value+4+length]=endCharSwap}else{var a=new Array(length);for(var i=0;i<length;++i){a[i]=String.fromCharCode(HEAPU8[value+4+i])}str=a.join("")}_free(value);return str},"toWireType":function(destructors,value){if(value instanceof ArrayBuffer){value=new Uint8Array(value)}var getLength;var valueIsOfTypeString=typeof value==="string";if(!(valueIsOfTypeString||value instanceof Uint8Array||value instanceof Uint8ClampedArray||value instanceof Int8Array)){throwBindingError("Cannot pass non-string to std::string")}if(stdStringIsUTF8&&valueIsOfTypeString){getLength=function(){return lengthBytesUTF8(value)}}else{getLength=function(){return value.length}}var length=getLength();var ptr=_malloc(4+length+1);HEAPU32[ptr>>2]=length;if(stdStringIsUTF8&&valueIsOfTypeString){stringToUTF8(value,ptr+4,length+1)}else{if(valueIsOfTypeString){for(var i=0;i<length;++i){var charCode=value.charCodeAt(i);if(charCode>255){_free(ptr);throwBindingError("String has UTF-16 code units that do not fit in 8 bits")}HEAPU8[ptr+4+i]=charCode}}else{for(var i=0;i<length;++i){HEAPU8[ptr+4+i]=value[i]}}}if(destructors!==null){destructors.push(_free,ptr)}return ptr},"argPackAdvance":8,"readValueFromPointer":simpleReadValueFromPointer,destructorFunction:function(ptr){_free(ptr)}})}function __embind_register_std_wstring(rawType,charSize,name){name=readLatin1String(name);var getHeap,shift;if(charSize===2){getHeap=function(){return HEAPU16};shift=1}else if(charSize===4){getHeap=function(){return HEAPU32};shift=2}registerType(rawType,{name:name,"fromWireType":function(value){var HEAP=getHeap();var length=HEAPU32[value>>2];var a=new Array(length);var start=value+4>>shift;for(var i=0;i<length;++i){a[i]=String.fromCharCode(HEAP[start+i])}_free(value);return a.join("")},"toWireType":function(destructors,value){var HEAP=getHeap();var length=value.length;var ptr=_malloc(4+length*charSize);HEAPU32[ptr>>2]=length;var start=ptr+4>>shift;for(var i=0;i<length;++i){HEAP[start+i]=value.charCodeAt(i)}if(destructors!==null){destructors.push(_free,ptr)}return ptr},"argPackAdvance":8,"readValueFromPointer":simpleReadValueFromPointer,destructorFunction:function(ptr){_free(ptr)}})}function __embind_register_void(rawType,name){name=readLatin1String(name);registerType(rawType,{isVoid:true,name:name,"argPackAdvance":0,"fromWireType":function(){return undefined},"toWireType":function(destructors,o){return undefined}})}function requireHandle(handle){if(!handle){throwBindingError("Cannot use deleted val. handle = "+handle)}return emval_handle_array[handle].value}function getTypeName(type){var ptr=___getTypeName(type);var rv=readLatin1String(ptr);_free(ptr);return rv}function requireRegisteredType(rawType,humanName){var impl=registeredTypes[rawType];if(undefined===impl){throwBindingError(humanName+" has unknown type "+getTypeName(rawType))}return impl}function __emval_as(handle,returnType,destructorsRef){handle=requireHandle(handle);returnType=requireRegisteredType(returnType,"emval::as");var destructors=[];var rd=__emval_register(destructors);HEAP32[destructorsRef>>2]=rd;return returnType["toWireType"](destructors,handle)}var emval_symbols={};function getStringOrSymbol(address){var symbol=emval_symbols[address];if(symbol===undefined){return readLatin1String(address)}else{return symbol}}var emval_methodCallers=[];function __emval_call_void_method(caller,handle,methodName,args){caller=emval_methodCallers[caller];handle=requireHandle(handle);methodName=getStringOrSymbol(methodName);caller(handle,methodName,null,args)}function emval_get_global(){function testGlobal(obj){obj["$$$embind_global$$$"]=obj;var success=typeof $$$embind_global$$$==="object"&&obj["$$$embind_global$$$"]===obj;if(!success){delete obj["$$$embind_global$$$"]}return success}if(typeof $$$embind_global$$$==="object"){return $$$embind_global$$$}if(typeof global==="object"&&testGlobal(global)){$$$embind_global$$$=global}else if(typeof window==="object"&&testGlobal(window)){$$$embind_global$$$=window}if(typeof $$$embind_global$$$==="object"){return $$$embind_global$$$}throw Error("unable to get global object.")}function __emval_get_global(name){if(name===0){return __emval_register(emval_get_global())}else{name=getStringOrSymbol(name);return __emval_register(emval_get_global()[name])}}function __emval_addMethodCaller(caller){var id=emval_methodCallers.length;emval_methodCallers.push(caller);return id}function __emval_lookupTypes(argCount,argTypes,argWireTypes){var a=new Array(argCount);for(var i=0;i<argCount;++i){a[i]=requireRegisteredType(HEAP32[(argTypes>>2)+i],"parameter "+i)}return a}function __emval_get_method_caller(argCount,argTypes){var types=__emval_lookupTypes(argCount,argTypes);var retType=types[0];var argN=new Array(argCount-1);var invokerFunction=function(handle,name,destructors,args){var offset=0;for(var i=0;i<argCount-1;++i){argN[i]=types[i+1].readValueFromPointer(args+offset);offset+=types[i+1].argPackAdvance}var rv=handle[name].apply(handle,argN);for(var i=0;i<argCount-1;++i){if(types[i+1].deleteObject){types[i+1].deleteObject(argN[i])}}if(!retType.isVoid){return retType.toWireType(destructors,rv)}};return __emval_addMethodCaller(invokerFunction)}function __emval_get_property(handle,key){handle=requireHandle(handle);key=requireHandle(key);return __emval_register(handle[key])}function __emval_incref(handle){if(handle>4){emval_handle_array[handle].refcount+=1}}function __emval_new_cstring(v){return __emval_register(getStringOrSymbol(v))}function __emval_new_object(){return __emval_register({})}function runDestructors(destructors){while(destructors.length){var ptr=destructors.pop();var del=destructors.pop();del(ptr)}}function __emval_run_destructors(handle){var destructors=emval_handle_array[handle].value;runDestructors(destructors);__emval_decref(handle)}function __emval_set_property(handle,key,value){handle=requireHandle(handle);key=requireHandle(key);value=requireHandle(value);handle[key]=value}function __emval_take_value(type,argv){type=requireRegisteredType(type,"_emval_take_value");var v=type["readValueFromPointer"](argv);return __emval_register(v)}function _abort(){Module["abort"]()}function _emscripten_get_heap_size(){return TOTAL_MEMORY}function abortOnCannotGrowMemory(requestedSize){abort("Cannot enlarge memory arrays to size "+requestedSize+" bytes. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value "+TOTAL_MEMORY+", (2) compile with -s ALLOW_MEMORY_GROWTH=1 which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0 ")}function emscripten_realloc_buffer(size){var PAGE_MULTIPLE=65536;size=alignUp(size,PAGE_MULTIPLE);var old=Module["buffer"];var oldSize=old.byteLength;try{var result=wasmMemory.grow((size-oldSize)/65536);if(result!==(-1|0)){return Module["buffer"]=wasmMemory.buffer}else{return null}}catch(e){return null}}function _emscripten_resize_heap(requestedSize){var oldSize=_emscripten_get_heap_size();var PAGE_MULTIPLE=65536;var LIMIT=2147483648-PAGE_MULTIPLE;if(requestedSize>LIMIT){return false}var MIN_TOTAL_MEMORY=16777216;var newSize=Math.max(oldSize,MIN_TOTAL_MEMORY);while(newSize<requestedSize){if(newSize<=536870912){newSize=alignUp(2*newSize,PAGE_MULTIPLE)}else{newSize=Math.min(alignUp((3*newSize+2147483648)/4,PAGE_MULTIPLE),LIMIT)}}var replacement=emscripten_realloc_buffer(newSize);if(!replacement||replacement.byteLength!=newSize){return false}updateGlobalBuffer(replacement);updateGlobalBufferViews();TOTAL_MEMORY=newSize;HEAPU32[DYNAMICTOP_PTR>>2]=requestedSize;return true}function _llvm_trap(){abort("trap!")}function _emscripten_memcpy_big(dest,src,num){HEAPU8.set(HEAPU8.subarray(src,src+num),dest)}function ___setErrNo(value){if(Module["___errno_location"])HEAP32[Module["___errno_location"]()>>2]=value;return value}embind_init_charCodes();BindingError=Module["BindingError"]=extendError(Error,"BindingError");InternalError=Module["InternalError"]=extendError(Error,"InternalError");init_emval();var ASSERTIONS=false;function intArrayToString(array){var ret=[];for(var i=0;i<array.length;i++){var chr=array[i];if(chr>255){if(ASSERTIONS){assert(false,"Character code "+chr+" ("+String.fromCharCode(chr)+") at offset "+i+" not in 0x00-0xFF.")}chr&=255}ret.push(String.fromCharCode(chr))}return ret.join("")}var decodeBase64=typeof atob==="function"?atob:function(input){var keyStr="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";var output="";var chr1,chr2,chr3;var enc1,enc2,enc3,enc4;var i=0;input=input.replace(/[^A-Za-z0-9\+\/\=]/g,"");do{enc1=keyStr.indexOf(input.charAt(i++));enc2=keyStr.indexOf(input.charAt(i++));enc3=keyStr.indexOf(input.charAt(i++));enc4=keyStr.indexOf(input.charAt(i++));chr1=enc1<<2|enc2>>4;chr2=(enc2&15)<<4|enc3>>2;chr3=(enc3&3)<<6|enc4;output=output+String.fromCharCode(chr1);if(enc3!==64){output=output+String.fromCharCode(chr2)}if(enc4!==64){output=output+String.fromCharCode(chr3)}}while(i<input.length);return output};function intArrayFromBase64(s){try{var decoded=decodeBase64(s);var bytes=new Uint8Array(decoded.length);for(var i=0;i<decoded.length;++i){bytes[i]=decoded.charCodeAt(i)}return bytes}catch(_){throw new Error("Converting base64 string to bytes failed.")}}function tryParseAsDataURI(filename){if(!isDataURI(filename)){return}return intArrayFromBase64(filename.slice(dataURIPrefix.length))}function jsCall_ii(index,a1){return functionPointers[index](a1)}function jsCall_iii(index,a1,a2){return functionPointers[index](a1,a2)}function jsCall_iiii(index,a1,a2,a3){return functionPointers[index](a1,a2,a3)}function jsCall_iiiii(index,a1,a2,a3,a4){return functionPointers[index](a1,a2,a3,a4)}function jsCall_v(index){functionPointers[index]()}function jsCall_vi(index,a1){functionPointers[index](a1)}function jsCall_viiii(index,a1,a2,a3,a4){functionPointers[index](a1,a2,a3,a4)}function jsCall_viiiii(index,a1,a2,a3,a4,a5){functionPointers[index](a1,a2,a3,a4,a5)}function jsCall_viiiiii(index,a1,a2,a3,a4,a5,a6){functionPointers[index](a1,a2,a3,a4,a5,a6)}var asmGlobalArg={};var asmLibraryArg={"o":abort,"k":jsCall_ii,"j":jsCall_iii,"i":jsCall_iiii,"h":jsCall_iiiii,"g":jsCall_v,"f":jsCall_vi,"e":jsCall_viiii,"d":jsCall_viiiii,"c":jsCall_viiiiii,"m":___assert_fail,"N":___cxa_pure_virtual,"v":___setErrNo,"M":__embind_register_bool,"L":__embind_register_emval,"u":__embind_register_float,"n":__embind_register_integer,"l":__embind_register_memory_view,"t":__embind_register_std_string,"K":__embind_register_std_wstring,"J":__embind_register_void,"I":__emval_as,"H":__emval_call_void_method,"s":__emval_decref,"G":__emval_get_global,"F":__emval_get_method_caller,"E":__emval_get_property,"r":__emval_incref,"D":__emval_new_cstring,"C":__emval_new_object,"B":__emval_run_destructors,"p":__emval_set_property,"q":__emval_take_value,"b":_abort,"A":_emscripten_get_heap_size,"z":_emscripten_memcpy_big,"y":_emscripten_resize_heap,"x":_llvm_trap,"w":abortOnCannotGrowMemory,"a":DYNAMICTOP_PTR};var asm=Module["asm"](asmGlobalArg,asmLibraryArg,buffer);Module["asm"]=asm;var __GLOBAL__sub_I_bind_cpp=Module["__GLOBAL__sub_I_bind_cpp"]=function(){return Module["asm"]["O"].apply(null,arguments)};var ___errno_location=Module["___errno_location"]=function(){return Module["asm"]["P"].apply(null,arguments)};var ___getTypeName=Module["___getTypeName"]=function(){return Module["asm"]["Q"].apply(null,arguments)};var _free=Module["_free"]=function(){return Module["asm"]["R"].apply(null,arguments)};var _image=Module["_image"]=function(){return Module["asm"]["S"].apply(null,arguments)};var _malloc=Module["_malloc"]=function(){return Module["asm"]["T"].apply(null,arguments)};var stackAlloc=Module["stackAlloc"]=function(){return Module["asm"]["W"].apply(null,arguments)};var stackRestore=Module["stackRestore"]=function(){return Module["asm"]["X"].apply(null,arguments)};var stackSave=Module["stackSave"]=function(){return Module["asm"]["Y"].apply(null,arguments)};var dynCall_v=Module["dynCall_v"]=function(){return Module["asm"]["U"].apply(null,arguments)};var dynCall_vi=Module["dynCall_vi"]=function(){return Module["asm"]["V"].apply(null,arguments)};Module["asm"]=asm;Module["cwrap"]=cwrap;Module["addFunction"]=addFunction;Module["removeFunction"]=removeFunction;function ExitStatus(status){this.name="ExitStatus";this.message="Program terminated with exit("+status+")";this.status=status}ExitStatus.prototype=new Error;ExitStatus.prototype.constructor=ExitStatus;dependenciesFulfilled=function runCaller(){if(!Module["calledRun"])run();if(!Module["calledRun"])dependenciesFulfilled=runCaller};function run(args){args=args||Module["arguments"];if(runDependencies>0){return}preRun();if(runDependencies>0)return;if(Module["calledRun"])return;function doRun(){if(Module["calledRun"])return;Module["calledRun"]=true;if(ABORT)return;ensureInitRuntime();preMain();if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("")},1);doRun()},1)}else{doRun()}}Module["run"]=run;function abort(what){if(Module["onAbort"]){Module["onAbort"](what)}if(what!==undefined){out(what);err(what);what=JSON.stringify(what)}else{what=""}ABORT=true;EXITSTATUS=1;throw"abort("+what+"). Build with -s ASSERTIONS=1 for more info."}Module["abort"]=abort;if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}Module["noExitRuntime"]=true;run(); +var Module=typeof Module!=="undefined"?Module:{};var moduleOverrides={};var key;for(key in Module){if(Module.hasOwnProperty(key)){moduleOverrides[key]=Module[key]}}Module["arguments"]=[];Module["thisProgram"]="./this.program";Module["quit"]=function(status,toThrow){throw toThrow};Module["preRun"]=[];Module["postRun"]=[];var ENVIRONMENT_IS_WEB=true;var ENVIRONMENT_IS_WORKER=false;var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}else{return scriptDirectory+path}}if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(document.currentScript){scriptDirectory=document.currentScript.src}if(scriptDirectory.indexOf("blob:")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.lastIndexOf("/")+1)}else{scriptDirectory=""}Module["read"]=function shell_read(url){try{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText}catch(err){var data=tryParseAsDataURI(url);if(data){return intArrayToString(data)}throw err}};if(ENVIRONMENT_IS_WORKER){Module["readBinary"]=function readBinary(url){try{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}catch(err){var data=tryParseAsDataURI(url);if(data){return data}throw err}}}Module["readAsync"]=function readAsync(url,onload,onerror){var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=function xhr_onload(){if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}var data=tryParseAsDataURI(url);if(data){onload(data.buffer);return}onerror()};xhr.onerror=onerror;xhr.send(null)};Module["setWindowTitle"]=function(title){document.title=title}}else{}var out=Module["print"]||(typeof console!=="undefined"?console.log.bind(console):typeof print!=="undefined"?print:null);var err=Module["printErr"]||(typeof printErr!=="undefined"?printErr:typeof console!=="undefined"&&console.warn.bind(console)||out);for(key in moduleOverrides){if(moduleOverrides.hasOwnProperty(key)){Module[key]=moduleOverrides[key]}}moduleOverrides=undefined;var asm2wasmImports={"f64-rem":function(x,y){return x%y},"debugger":function(){debugger}};var functionPointers=new Array(0);if(typeof WebAssembly!=="object"){err("no native wasm support detected")}var wasmMemory;var wasmTable;var ABORT=false;var EXITSTATUS=0;function assert(condition,text){if(!condition){abort("Assertion failed: "+text)}}function getCFunc(ident){var func=Module["_"+ident];assert(func,"Cannot call unknown function "+ident+", make sure it is exported");return func}function ccall(ident,returnType,argTypes,args,opts){var toC={"string":function(str){var ret=0;if(str!==null&&str!==undefined&&str!==0){var len=(str.length<<2)+1;ret=stackAlloc(len);stringToUTF8(str,ret,len)}return ret},"array":function(arr){var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}};function convertReturnValue(ret){if(returnType==="string")return UTF8ToString(ret);if(returnType==="boolean")return Boolean(ret);return ret}var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i<args.length;i++){var converter=toC[argTypes[i]];if(converter){if(stack===0)stack=stackSave();cArgs[i]=converter(args[i])}else{cArgs[i]=args[i]}}}var ret=func.apply(null,cArgs);ret=convertReturnValue(ret);if(stack!==0)stackRestore(stack);return ret}function cwrap(ident,returnType,argTypes,opts){argTypes=argTypes||[];var numericArgs=argTypes.every(function(type){return type==="number"});var numericRet=returnType!=="string";if(numericRet&&numericArgs&&!opts){return getCFunc(ident)}return function(){return ccall(ident,returnType,argTypes,arguments,opts)}}var UTF8Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf8"):undefined;function UTF8ArrayToString(u8Array,idx,maxBytesToRead){var endIdx=idx+maxBytesToRead;var endPtr=idx;while(u8Array[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&u8Array.subarray&&UTF8Decoder){return UTF8Decoder.decode(u8Array.subarray(idx,endPtr))}else{var str="";while(idx<endPtr){var u0=u8Array[idx++];if(!(u0&128)){str+=String.fromCharCode(u0);continue}var u1=u8Array[idx++]&63;if((u0&224)==192){str+=String.fromCharCode((u0&31)<<6|u1);continue}var u2=u8Array[idx++]&63;if((u0&240)==224){u0=(u0&15)<<12|u1<<6|u2}else{u0=(u0&7)<<18|u1<<12|u2<<6|u8Array[idx++]&63}if(u0<65536){str+=String.fromCharCode(u0)}else{var ch=u0-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}}}return str}function UTF8ToString(ptr,maxBytesToRead){return ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):""}function stringToUTF8Array(str,outU8Array,outIdx,maxBytesToWrite){if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i<str.length;++i){var u=str.charCodeAt(i);if(u>=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;outU8Array[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;outU8Array[outIdx++]=192|u>>6;outU8Array[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;outU8Array[outIdx++]=224|u>>12;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;outU8Array[outIdx++]=240|u>>18;outU8Array[outIdx++]=128|u>>12&63;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}}outU8Array[outIdx]=0;return outIdx-startIdx}function stringToUTF8(str,outPtr,maxBytesToWrite){return stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite)}function lengthBytesUTF8(str){var len=0;for(var i=0;i<str.length;++i){var u=str.charCodeAt(i);if(u>=55296&&u<=57343)u=65536+((u&1023)<<10)|str.charCodeAt(++i)&1023;if(u<=127)++len;else if(u<=2047)len+=2;else if(u<=65535)len+=3;else len+=4}return len}var UTF16Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf-16le"):undefined;function writeArrayToMemory(array,buffer){HEAP8.set(array,buffer)}var WASM_PAGE_SIZE=65536;function alignUp(x,multiple){if(x%multiple>0){x+=multiple-x%multiple}return x}var buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBuffer(buf){Module["buffer"]=buffer=buf}function updateGlobalBufferViews(){Module["HEAP8"]=HEAP8=new Int8Array(buffer);Module["HEAP16"]=HEAP16=new Int16Array(buffer);Module["HEAP32"]=HEAP32=new Int32Array(buffer);Module["HEAPU8"]=HEAPU8=new Uint8Array(buffer);Module["HEAPU16"]=HEAPU16=new Uint16Array(buffer);Module["HEAPU32"]=HEAPU32=new Uint32Array(buffer);Module["HEAPF32"]=HEAPF32=new Float32Array(buffer);Module["HEAPF64"]=HEAPF64=new Float64Array(buffer)}var DYNAMIC_BASE=17152,DYNAMICTOP_PTR=8704;var TOTAL_STACK=8192;var TOTAL_MEMORY=Module["TOTAL_MEMORY"]||16777216;if(TOTAL_MEMORY<TOTAL_STACK)err("TOTAL_MEMORY should be larger than TOTAL_STACK, was "+TOTAL_MEMORY+"! (TOTAL_STACK="+TOTAL_STACK+")");if(Module["buffer"]){buffer=Module["buffer"]}else{if(typeof WebAssembly==="object"&&typeof WebAssembly.Memory==="function"){wasmMemory=new WebAssembly.Memory({"initial":TOTAL_MEMORY/WASM_PAGE_SIZE});buffer=wasmMemory.buffer}else{buffer=new ArrayBuffer(TOTAL_MEMORY)}Module["buffer"]=buffer}updateGlobalBufferViews();HEAP32[DYNAMICTOP_PTR>>2]=DYNAMIC_BASE;function callRuntimeCallbacks(callbacks){while(callbacks.length>0){var callback=callbacks.shift();if(typeof callback=="function"){callback();continue}var func=callback.func;if(typeof func==="number"){if(callback.arg===undefined){Module["dynCall_v"](func)}else{Module["dynCall_vi"](func,callback.arg)}}else{func(callback.arg===undefined?null:callback.arg)}}}var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function ensureInitRuntime(){if(runtimeInitialized)return;runtimeInitialized=true;callRuntimeCallbacks(__ATINIT__)}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}}function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}Module["preloadedImages"]={};Module["preloadedAudios"]={};var dataURIPrefix="data:application/octet-stream;base64,";function isDataURI(filename){return String.prototype.startsWith?filename.startsWith(dataURIPrefix):filename.indexOf(dataURIPrefix)===0}var wasmBinaryFile="data:application/octet-stream;base64,AGFzbQEAAAABcRBgA39/fwBgAX8AYAF/AX9gAn9/AX9gBX9/f39/AGAEf39/fwF/YAAAYAR/f39/AGAGf39/f39/AGADf39/AX9gAn9/AGAAAX9gBX9/f39/AX9gBn9/f39/fwF/YAd/f39/f39/AX9gB39/f39/f38AAoYCHQNlbnYBYgAGA2VudgFjAAADZW52AWQABwNlbnYBZQABA2VudgFmAAQDZW52AWcAAANlbnYBaAADA2VudgFpAAADZW52AWoAAQNlbnYBawABA2VudgFsAAEDZW52AW0ACgNlbnYBbgAIA2VudgFvAAoDZW52AXAABANlbnYBcQACA2VudgFyAAYDZW52AXMAAgNlbnYBdAAJA2VudgF1AAsDZW52AXYABgNlbnYBdwALA2VudgF4AAIDZW52AXkACgNlbnYBegAAA2VudgxfX3RhYmxlX2Jhc2UDfwADZW52AWEDfwADZW52Bm1lbW9yeQIAgAIDZW52BXRhYmxlAXABugG6AQPLAskCAQAKAwIBAQECAQkBAQoBBQEKCgMAAQMACQMDBQUJCgAJCQoJDgoCAgIBAQUFBQEMCQkJAgMDAAEBAQMCAQoKBAQKCgICCQIBCgcNDAAJCAcAAAoJCQoHCQkBBwoCCQEHAgkKAQ0BCgACAgABCQEBCgoKCgEJBwQBAQEBAQEDCg0JDAoBAQoCCQwFCQkDCgcKCQABAQoKAgEKBwIDAgMDAgIDAwICAwoBBgoKCgAKBwcDAAIAAwILCQoKAQgHAAYFCQ8CCAQHCgEMBQkDCgcECAkKCwcECAIHBAoICQcKCQkBDwoBCgsCBg0MCgMJAAoKAAAKCgoFCgoKAQoHDQoBCgoKAAQKAwMIBAAAAwoCAAAKAAkDBQMKCQUDAwMDAwMDAwMEAwEKAwoCCgADAgMCAwIDAwICAwIDAgMDAgEAAwIDAgIDAgIDAgYGDQJ/ASMBC38BQYDGAAsHWRIBQQD+AQFCAP8BAUMAJAFEAEwBRQDkAQFGAOMBAUcA4gEBSADhAQFJAOABAUoA3wEBSwDeAQFMAN0BAU0A3AEBTgDaAQFPAOECAVAApgIBUQDTAQFSAOsBCYYCAQAjAAu6ASHLAVS9AbwBggFUuQG4AYEBXeACXd4C3QLbAtoC2AK1AdQCtQFdVNECXM8CXM0CzAJUXMkCgQHHAoIBxQJc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CwsLCzMBAX8jAyECIwNBEGokAyACIAE2AgAgACACEKwCIQEgAiQDQQAgAUEUaiABIABBBGpGGwu7AgEIfyMDIQYjA0GAAmokAyAGQRBqIQQgBkEMaiEHIAYiBSAFQfQBahAmIAVBBGohCEGQFCEDA0AgByAINgIAIAQgBygCADYCACAFIAQgAyADECgaIANBBGoiA0GYFEcNAAsgACgCACIDIABBBGoiCUcEQCADIQADQCAHIAg2AgAgBCAHKAIANgIAIAUgBCAAQRBqIgMgAxAoGiAAKAIEIgMEQCADIQADQCAAKAIAIgMEQCADIQAMAQsLBSAAIABBCGoiAygCACIAKAIARwRAIAMhAAN/IAAoAgAiCkEIaiIAKAIAIQMgAygCACAKRw0AIAMLIQALCyAAIAlHDQALCyAEEFEgBUECIAEgBBBFBEAgAkEQaiIBIARBEGoiACkCADcCACABIAApAgg3AggLIAQQUCAFECUgBiQDCygAIABB2AFqECcgAEHMAWoQGSAAQcgAahAZIABBPGoQGSAAQTBqEBkLjgEBAn8jAyECIwNBEGokAyAAEEcgAEEQahBHIABBATYCICAAQSRqIgFCADcCACABQgA3AgggAUIANwIQIAFCADcCGCABQgA3AiAgAUIANwIoIAFBADYCMCAAQdgAahBCIABB4ABqEEIgAEHoAGoQQiAAQfAAahCXAiACQQA2AgAgAEHYAWogAhCPAiACJAMLCQAgABAVEK0BC0UBA38jAyECIwNBMGokAyACQSxqIgNBADYCACACIABBBBA4IAIgASADEEshACACEB4gAygCAEUgAEEIRnEhBCACJAMgBAsEAEEEC0cBAn8gACgCBCIABEAgAEEEaiICKAIAIQEgAiABQX9qNgIAIAFFBEAgACgCACgCCCEBIAAgAUE/cUHoAGoRAQAgABD8AQsLCyYBAX8jAyECIwNBEGokAyACIAEQ0QEgAEG4DSACEAY2AgAgAiQDCxQBAX8gACABKAIAIgI2AgAgAhAJCwYAQQgQAwtVAQN/IAAoAgQiBkEIdSEFIAZBAXEEQCACKAIAIAVqKAIAIQULIAAoAgAiACgCACgCGCEHIAAgASACIAVqIANBAiAGQQJxGyAEIAdBB3FBrgFqEQQAC0MBAX9B/////wMgAUkEQBAACyABQf////8DSwRAEAAFIAAgAUECdBAdIgI2AgQgACACNgIAIAAgAUECdCACajYCCAsL/AEBCH8jAyEEIwNBEGokAyAEQQRqIQUgBCEGIABBADYCBCAAQQA2AgggACAAQQRqNgIAIAEoAgAiAiABQQRqIgdHBEAgAEEEaiEIA0AgBiAINgIAIAUgBigCADYCACAAIAUgAkEQaiIDIAMQjgIaIAIoAgQiAwRAIAMhAgNAIAIoAgAiAwRAIAMhAgwBCwsFIAIgAkEIaiIDKAIAIgIoAgBHBEAgAyECA38gAigCACIJQQhqIgIoAgAhAyADKAIAIAlHDQAgAwshAgsLIAIgB0cNAAsLIABBDGogAUEMahCNAiAAQRhqIAFBGGoQjAIgACABKAIkNgIkIAQkAwsFAEGIJwsEAEEIC1oAIAAQQEECSQR/IAIEQCACKAIARQRAIAJBATYCAAsLQQAFIAEEfyAAQQAQLEH/AXFBCHQgAEEBECxB/wFxcgUgAEEBECxB/wFxQQh0IABBABAsQf8BcXILCwsKACAAKAIoQQBHCy4BAn8gACgCBCIBIABBCGoiAigCAEcEQCACIAE2AgALIAAoAgAiAARAIAAQJAsLrQEBBX8gAUEEaiICKAIAIABBBGoiBSgCACAAKAIAIgRrIgZrIQMgAiADNgIAIAZBAEoEfyADIAQgBhA6GiACIQQgAigCAAUgAiEEIAMLIQIgACgCACEDIAAgAjYCACAEIAM2AgAgBSgCACEDIAUgAUEIaiICKAIANgIAIAIgAzYCACAAQQhqIgAoAgAhAiAAIAFBDGoiACgCADYCACAAIAI2AgAgASAEKAIANgIAC0cBAX8gAEEMaiIEQQA2AgAgACADNgIQIAAgAQR/IAEQHQVBAAsiAzYCACAAIAIgA2oiAjYCCCAAIAI2AgQgBCABIANqNgIAC5QCAQJ/IAAgASACIAMgBRBkIQYgBSgCACEHIAQoAgAgAygCACAHQR9xQUBrEQMABH8gAygCACEHIAMgBCgCADYCACAEIAc2AgAgBkEBaiEEIAUoAgAhByADKAIAIAIoAgAgB0EfcUFAaxEDAAR/IAIoAgAhBCACIAMoAgA2AgAgAyAENgIAIAZBAmohAyAFKAIAIQQgAigCACABKAIAIARBH3FBQGsRAwAEfyABKAIAIQMgASACKAIANgIAIAIgAzYCACAGQQNqIQIgBSgCACEDIAEoAgAgACgCACADQR9xQUBrEQMABH8gACgCACECIAAgASgCADYCACABIAI2AgAgBkEEagUgAgsFIAMLBSAECwUgBgsL0QEBAn8gACABIAIgBBBGIQYgBCgCACEFIAMoAgAgAigCACAFQR9xQUBrEQMABH8gAigCACEFIAIgAygCADYCACADIAU2AgAgBkEBaiEDIAQoAgAhBSACKAIAIAEoAgAgBUEfcUFAaxEDAAR/IAEoAgAhAyABIAIoAgA2AgAgAiADNgIAIAZBAmohAiAEKAIAIQMgASgCACAAKAIAIANBH3FBQGsRAwAEfyAAKAIAIQIgACABKAIANgIAIAEgAjYCACAGQQNqBSACCwUgAwsFIAYLC9gIAQp/AkACQAJAAkACQAJAA0ACQCABIQsgAUF8aiEGIAFBeGohCiABIQwgACEEAkACQAJAAkADQAJAAkAgCyAEayIAQQJ1IgUOBgcHCQoLDAALIABB/ABIDQwgBUECbUECdCAEaiEDIABBnB9KBH8gBCAFQQRtIgBBAnQgBGogAyAAQQJ0IANqIAYgAhBjBSAEIAMgBiACEEYLIQUgAigCACEAIAQoAgAgAygCACAAQR9xQUBrEQMABEAgBiEABSAEIApGDQEgCiEAA0ACQCACKAIAIQcgACgCACADKAIAIAdBH3FBQGsRAwANACAAQXxqIgAgBEcNAQwDCwsgBCgCACEHIAQgACgCADYCACAAIAc2AgAgBUEBaiEFCyAEQQRqIgggAEkEfyADIQcgCCEDIAUhCAN/A0AgAigCACEJIANBBGohBSADKAIAIAcoAgAgCUEfcUFAaxEDAARAIAUhAwwBCwsDQCACKAIAIQkgAEF8aiIAKAIAIAcoAgAgCUEfcUFAaxEDAEUNAAsgAyAASwR/IAgFIAMoAgAhCSADIAAoAgA2AgAgACAJNgIAIAAgByADIAdGGyEHIAUhAyAIQQFqIQgMAQsLBSADIQcgCCEDIAULIQAgAyAHRwRAIAIoAgAhBSAHKAIAIAMoAgAgBUEfcUFAaxEDAARAIAMoAgAhBSADIAcoAgA2AgAgByAFNgIAIABBAWohAAsLIABFBEAgBCADIAIQhQEhBSADQQRqIgAgASACEIUBDQMgBQRAQQIhBgwGCwsgAyAEayAMIANrTg0DIAQgAyACEGUgA0EEaiEEDAELCyAEQQRqIQAgAigCACEDIAQoAgAgBigCACADQR9xQUBrEQMARQRAIAAgBkYNBQNAAkAgAigCACEDIAQoAgAgACgCACADQR9xQUBrEQMADQAgAEEEaiIAIAZHDQEMBwsLIAAoAgAhAyAAIAYoAgA2AgAgBiADNgIAIABBBGohAAsgACAGRg0EIAYhAwNAA0AgAigCACEGIABBBGohBSAEKAIAIAAoAgAgBkEfcUFAaxEDAEUEQCAFIQAMAQsLA0AgAigCACEGIAQoAgAgA0F8aiIDKAIAIAZBH3FBQGsRAwANAAsgACADSQRAIAAoAgAhBiAAIAMoAgA2AgAgAyAGNgIAIAUhAAwBBUEEIQYMBAsAAAsAC0EBQQIgBRshBiAEIQAgASADIAUbIQEMAQsgA0EEaiABIAIQZSAEIQAgAyEBDAELAkAgBkEHcQ4FAAIAAgACCwsMAQsLDAULIAIoAgAhAiABQXxqIgAoAgAgBCgCACACQR9xQUBrEQMABEAgBCgCACEBIAQgACgCADYCACAAIAE2AgALDAQLIAQgBEEEaiABQXxqIAIQRhoMAwsgBCAEQQRqIARBCGogAUF8aiACEGQaDAILIAQgBEEEaiAEQQhqIARBDGogAUF8aiACEGMaDAELIAQgASACEMwBCwtiAQJ/IAEgAEggACABIAJqSHEEQAJ/IAAhBCABIAJqIQEgACACaiEAA0AgAkEASgRAIAJBAWshAiAAQQFrIgAgAUEBayIBLAAAOgAADAELCyAECyEABSAAIAEgAhA6GgsgAAtXAQN/IAAoAgQiB0EIdSEGIAdBAXEEQCADKAIAIAZqKAIAIQYLIAAoAgAiACgCACgCFCEIIAAgASACIAMgBmogBEECIAdBAnEbIAUgCEEDcUG2AWoRCAALuAEBAX8gAEEBOgA1IAIgACgCBEYEQAJAIABBAToANCAAQRBqIgQoAgAiAkUEQCAEIAE2AgAgACADNgIYIABBATYCJCAAKAIwQQFGIANBAUZxRQ0BIABBAToANgwBCyABIAJHBEAgAEEkaiIEIAQoAgBBAWo2AgAgAEEBOgA2DAELIABBGGoiASgCACIEQQJGBEAgASADNgIABSAEIQMLIAAoAjBBAUYgA0EBRnEEQCAAQQE6ADYLCwsLJgEBfyABIAAoAgRGBEAgAEEcaiIDKAIAQQFHBEAgAyACNgIACwsLbQECfyAAQRBqIgMoAgAiBARAAkAgASAERwRAIABBJGoiAyADKAIAQQFqNgIAIABBAjYCGCAAQQE6ADYMAQsgAEEYaiIDKAIAQQJGBEAgAyACNgIACwsFIAMgATYCACAAIAI2AhggAEEBNgIkCws+ACAAQgA3AgAgAEEANgIIIAEsAAtBAEgEQCAAIAEoAgAgASgCBBAaBSAAIAEpAgA3AgAgACABKAIINgIICwtOAQJ/IAIEfwJ/A0AgACwAACIDIAEsAAAiBEYEQCAAQQFqIQAgAUEBaiEBQQAgAkF/aiICRQ0CGgwBCwsgA0H/AXEgBEH/AXFrCwVBAAsLggEBB38jAyEDIwNBMGokAyADQRBqIQQgA0EMaiEHIAMiBiADQSRqECYgA0EEaiEIQbgUIQUDQCAHIAg2AgAgBCAHKAIANgIAIAYgBCAFIAUQKBogBUEEaiIFQcAURw0ACyAEEH4gBiAAQQIgASAEIAIQfSEJIAQQfCAGECUgAyQDIAkLHQAgAQRAIAAgASgCABBuIAAgASgCBBBuIAEQJAsLVQAgA0EANgIAIANBADYCBCADIAE2AgggAiADNgIAIAAoAgAoAgAiAQRAIAAgATYCACACKAIAIQMLIAAoAgQgAxCaAiAAQQhqIgAgACgCAEEBajYCAAujAQECfyAAQQRqIgQoAgAhAyAAQQRqIQAgAwRAAkAgAigCACEEIAAhAiADIQACQAJAA0ACQCAEIAAoAhAiA0kEfyAAKAIAIgNFDQEgACECIAMFIAMgBE8NBCAAQQRqIgIoAgAiA0UNAyADCyEADAELCyABIAA2AgAMAgsgASAANgIAIAIhAAwBCyABIAA2AgAgAiEACwUgASAENgIAIAQhAAsgAAtwAQN/IwMhAyMDQRBqJAMgASgCACgCCCEEIAEgAEECIAMiACAEQQFxQeQAahEFAAR/QQAFAn8gAEHTK0ECEGxFBEAgAkEANgIAQQEMAQsgAEHVK0ECEGwEf0EABSACQQE2AgBBAQsLCyEFIAMkAyAFCwQAEBALNQAgAEEEaiEAIAIgAWsiAkEASgRAIAAoAgAgASACEDoaIAAgACgCACACQQJ2QQJ0ajYCAAsLKQAgAEEANgIAIABBADYCBCAAQQA2AgggAQRAIAAgARBaIAAgARClAgsLFQAgAC8BAEGABEwgAC8BAkGABExxC/kDAQp/IwMhByMDQTBqJAMgB0EUaiEFIAdBCGohBiAHQQRqIQQgByIDQSRqIghBADYCACADQSBqIglBADYCAAJ/AkACQAJAIABBgQQQHEUNACAAQYIEEBxFDQAgAEGBBCAJECMEQCAAQYIEIAgQIw0CC0EADAMLIABBkQIQHARAIABBlwIQHARAIAVBADYCACAFQQA2AgQgBUEANgIIIAZBADYCACAGQQRqIgpBADYCACAGQQA2AggCfyAAQZECIAUQSQR/IABBlwIgBhBJBH8gBEEANgIAIAUgBhCkAgR/IABBgwIgBBAjBH8gA0EANgIAIABBhgIgAxAjIAMoAgBBBHJBBkdxBH9BAQUCfwJAAkACQCAEKAIAIgNBAWsOBwIBAQEBAAABC0EAIQMMAQtBAQwBCyACIAM2AgwgBigCACIDIAooAgAiCkYEQEEAIQQFQQAhBANAIAQgAygCAGohBCADQQRqIgMgCkcNAAsLIAggBDYCACAJIAUoAgAoAgA2AgBBAAsLBUEBCwVBAQsFQQELBUEBCyELIAYQJyAFECcgCwtFDQNBAAwECwsgAEEuEBwEQCAAQS5BByAJIAgQSA0BC0EADAILIAJBADYCDAsgAiAIKAIANgIEIAIgCSgCADYCCCAAIAEgAhCjAkEBCyEMIAckAyAMCzMBAn8gACgCACIBBEAgAEEEaiICIAE2AgAgARAkIABBADYCCCACQQA2AgAgAEEANgIACwsvACAAQQRqIQAgAiABayICQQBKBEAgACgCACABIAIQOhogACAAKAIAIAJqNgIACwsHACAAQRhqC+QEAQV/IwMhBSMDQSBqJAMgBUEQaiIDEEcgACABIAMQdgRAAkAgAxB1BEAgAkEQaiIBIAMpAgA3AgAgASADKQIINwIIDAELIAMoAgxFBEAgAiADKQIANwIAIAIgAykCCDcCCAsLCyAAQZICEBwEfyACQSBqIgEoAgBBAUYEfyAAQZICIAEQIwVBAQsFQQELIQEgBSEDIABBgcACEBwEQCAAQYHAAiADECMEQAJAIAMoAgAiBEECSARAIARBAWsNASACQQA2AiQMAQsgBEH//wNIBEAgBEECaw0BBSAEQf//A2sNAQsgAkEBNgIkCwVBACEBCwsgACACQShqIAJBLGoQpAEgAXEhASAAQY8CEBwEQCAAQY8CIAJBMGoQSiABcSEBCyAAQZACEBwEQCAAQZACIAJBPGoQSiABcSEBCyAAQY2FAhAcBEAgA0EANgIAIANBBGoiBkEANgIAIANBADYCCCAAQY2FAiADEEkEQCADKAIAIgchBCAGKAIAIAdrQQhGBEAgAigC2AEiBiAEKAIANgIAIAYgBCgCBDYCBAsLIAMQJwsgAEGDoAIQHARAIABBg6ACIAJByABqEEogAXEhAQsCQAJAIABBp5ACEBwEQEGnkAIhAwwBBSAAQRcQHARAQRchAwwCCwsMAQsgACADIAJB1ABqECMgAXEhAQsgAEGahQIQHARAQZqFAiAAQQEgAkHYAGoQRCABcSEBCyAAQZ2FAhAcBEBBnYUCIABBASACQeAAahBEIAFxIQELIABBiqQCEBwEQEGKpAIgAEEBIAJB6ABqEEQgAXEhAQsgBSQDIAELJQAgAQRAIAAgASgCABB7IAAgASgCBBB7IAFBFGoQqwEgARAkCwtJAQJ/IABBEGoiAigCACEBIAJBADYCACABBEAgARAuIAEQJAsgAEEMaiICKAIAIQEgAkEANgIAIAEEQCABEC4gARAkCyAAEKwBC8gCAQl/IwMhCSMDQSBqJAMgCUEQaiEHIAlBDGohCiAJIgggCEEcahAmIAhBBGohC0G0EyEGA0AgCiALNgIAIAcgCigCADYCACAIIAcgBiAGECgaIAZBBGoiBkHwE0cNAAsgACgCACIGIABBBGoiDEcEQCAGIQADQCAKIAs2AgAgByAKKAIANgIAIAggByAAQRBqIgYgBhAoGiAAKAIEIgYEQCAGIQADQCAAKAIAIgYEQCAGIQAMAQsLBSAAIABBCGoiBigCACIAKAIARwRAIAYhAAN/IAAoAgAiDUEIaiIAKAIAIQYgBigCACANRw0AIAYLIQALCyAAIAxHDQALCyAHIAM2AgAgByABNgIEIAcgCCACQf//A3EgBBCxAgR/IAQoAgAgBCgCBEYEf0EABSAHIAQgBRCwAgsFQQALIQ4gCBAlIAkkAyAOCxcAIABCADcCACAAQgA3AgggAEEANgIQCy8BAX9B/////wcgAUkEQBAABSAAIAEQHSICNgIEIAAgAjYCACAAIAEgAmo2AggLC3kBAn9BDBAdIgMiBEG8DjYCACAEQYgTNgIAIAQgATYCBCAEIAI2AgggACADEL4CIABBCGoiA0IANwIAIANCADcCCCADQQA2AhAgACACNgIcIABBADYCICAAQQA2AiQgAEEANgIoIAFFBEBBtChBmBxB3wBBuigQAgsLBABBDgsEAEEQC2YBAn8jAyEEIwNBMGokAyAEIgMgAUEAEDgCQAJAIAMQXw0AIAMQQCACSQ0AIAMgAygCFCIBNgIYIAMgASACajYCHCADEIQBIAAgAxDCAQwBCyABQQE2AiggABDAAQsgAxAeIAQkAwuVAQEFfyAAKAIYIgIgAEEgaiIBKAIAIgNLBEAgASADIABBJGoiBCgCACIFIAIgA2siAyADIAVLGyICaiIDNgIAIABBEGoiASABKAIAIAJqNgIAIAQgBSACayIBNgIABSAAQSRqIgEhBCABKAIAIQELIAAoAhwiACADayECIAEgA2ogAEsEQCAEIAEgAiACIAFLGzYCAAsLngMBCH8CfwJAAkACQAJAAkACQCABIABrQQJ1DgYAAAECAwQFC0EBDAULIAIoAgAhAiABQXxqIgEoAgAgACgCACACQR9xQUBrEQMABEAgACgCACECIAAgASgCADYCACABIAI2AgALQQEMBAsgACAAQQRqIAFBfGogAhBGGkEBDAMLIAAgAEEEaiAAQQhqIAFBfGogAhBkGkEBDAILIAAgAEEEaiAAQQhqIABBDGogAUF8aiACEGMaQQEMAQsgACAAQQRqIABBCGoiAyACEEYaIAEgAEEMaiIFRgR/QQEFA0ACQCACKAIAIQQgBSgCACADKAIAIARBH3FBQGsRAwAEQCAFKAIAIgchCCAFIQQDQAJAIAQgAygCADYCACAAIANGBEAgACEDDAELIAIoAgAhBCAIIANBfGoiCSgCACAEQR9xQUBrEQMABEAgAyEEIAkhAwwCCwsLIAMgBzYCACAGQQFqIgNBCEYNAQUgBiEDC0EBIAEgBUEEaiIGRg0DGgJ/IAUhCiAGIQUgAyEGIAoLIQMMAQsLIAEgBUEEakYLCwuCAQEEfyAAKAIAIgEgAEEEaiIEKAIARwRAA0AgAkECdCABaigCACIDBH8gAyADKAIAKAIEQT9xQegAahEBACAAKAIABSABCyACQQJ0akEANgIAIAJBAWoiAiAEKAIAIAAoAgAiAWtBAnVJDQALCyAAKAIAIgEEQCAAIAE2AgQgARAkCwv4CgEHfyMDIQYjA0EQaiQDIABBADYCACAAQQRqIgJBADYCACAAQQhqIgVBADYCAEEEEB0iAUEANgIAIAEQKSABQdASNgIAIAYiAyABNgIAIAIoAgAiBCAFKAIASQRAIAQgATYCACACIAIoAgBBBGo2AgAFIAAgAxAqC0EEEB0iAUEANgIAIAEQKSABQbQSNgIAIAMgATYCACACKAIAIgQgBSgCAEkEQCAEIAE2AgAgAiACKAIAQQRqNgIABSAAIAMQKgtBBBAdIgFBADYCACABECkgAUGYEjYCACADIAE2AgAgAigCACIEIAUoAgBJBEAgBCABNgIAIAIgAigCAEEEajYCAAUgACADECoLQQQQHSIBQQA2AgAgARApIAFB/BE2AgAgAyABNgIAIAIoAgAiBCAFKAIASQRAIAQgATYCACACIAIoAgBBBGo2AgAFIAAgAxAqC0EEEB0iAUEANgIAIAEQKSABQeARNgIAIAMgATYCACACKAIAIgQgBSgCAEkEQCAEIAE2AgAgAiACKAIAQQRqNgIABSAAIAMQKgtBBBAdIgFBADYCACABECkgAUHEETYCACADIAE2AgAgAigCACIEIAUoAgBJBEAgBCABNgIAIAIgAigCAEEEajYCAAUgACADECoLQQQQHSIBQQA2AgAgARApIAFBqBE2AgAgAyABNgIAIAIoAgAiBCAFKAIASQRAIAQgATYCACACIAIoAgBBBGo2AgAFIAAgAxAqC0EEEB0iAUEANgIAIAEQKSABQYwRNgIAIAMgATYCACACKAIAIgQgBSgCAEkEQCAEIAE2AgAgAiACKAIAQQRqNgIABSAAIAMQKgtBBBAdIgFBADYCACABECkgAUHwEDYCACADIAE2AgAgAigCACIEIAUoAgBJBEAgBCABNgIAIAIgAigCAEEEajYCAAUgACADECoLQQQQHSIBQQA2AgAgARApIAFB1BA2AgAgAyABNgIAIAIoAgAiBCAFKAIASQRAIAQgATYCACACIAIoAgBBBGo2AgAFIAAgAxAqC0EEEB0iAUEANgIAIAEQKSABQbgQNgIAIAMgATYCACACKAIAIgQgBSgCAEkEQCAEIAE2AgAgAiACKAIAQQRqNgIABSAAIAMQKgtBBBAdIgFBADYCACABECkgAUGcEDYCACADIAE2AgAgAigCACIEIAUoAgBJBEAgBCABNgIAIAIgAigC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AEEBajYCAAsgAEEQaiIAIAFBEGoiASkCADcCACAAIAEpAgg3AgggACABKQIQNwIQIAAgASgCGDYCGAssACAAQgA3AgAgAEIANwIIIABCADcCECAAQgA3AhggAEIANwIgIABBATYCKAsnAQJ/An8jAyEBIwNBEGokA0HkFkEDQagOQdIZQQNBARAMIAELJAMLiQEBAn8gACABKAIANgIAIAAgAUEEaiICKAIANgIEIAFBADYCACACQQA2AgAgACABQQhqIgIoAgA2AgggACABQQxqIgMoAgA2AgwgAkEANgIAIANBADYCACAAQRBqIgAgAUEQaiIBKQIANwIAIAAgASkCCDcCCCAAIAEpAhA3AhAgACABKAIYNgIYC7gDAQh/IwMhBSMDQRBqJAMgBUEEaiEGIAUhByAAKAIYIAFNBEAgACgCHCABSwRAIAAoAgAiAygCACgCCCECIAMgAkE/cRECACABTQRAQeccQZgcQb8BQdUcEAILIAAoAgAiAygCACgCDCECIAEgAyACQT9xEQIAbiEDIAAoAgAiASgCACgCECECIAEgAyAGIAcgAEEIaiACQQdxQa4BahEEACAAKAIAIgEoAgAoAgwhAiABIAJBP3ERAgAhASAAKAIAIgIoAgAoAgghBCACIARBP3ERAgBBf2ohAiAAKAIAIgQoAgAoAgwhCCADIAIgBCAIQT9xEQIAbkYEQCAAKAIAIgEoAgAoAgghAgJ/IAEgAkE/cRECACEJIAAoAgAiAigCACgCDCEEIAkLIAIgBEE/cRECACADbGshAQsgBygCACIEIAYoAgAiAk8EQCABIAQgAmtGBEAgACACNgIQIAAoAgAiASgCACgCDCECIAAgASACQT9xEQIAIANsNgIgIAAgBygCACAGKAIAazYCJCAAEIQBIAUkAw8LC0HnHEGYHEHTAUHVHBACCwtB4htBmBxBuwFB1RwQAgufAQEHfyMDIQQjA0EgaiQDIAQhAkH/////ByAAQQRqIgYoAgAgACgCAGtBAWoiBUkEQBAABSACIAUgACgCCCAAKAIAIgdrIghBAXQiAyADIAVJG0H/////ByAIQf////8DSRsgBigCACAHayAAQQhqEGIgAkEIaiIDKAIAIAEsAAA6AAAgAyADKAIAQQFqNgIAIAAgAhBhIAIQYCAEJAMLC9UBAQR/IwMhBSMDQYAC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BEEOaiEJIARBDGohCiAEQQhqIgVBATYCACAEQQRqIgNBADYCACAEIgtBADYCACAAQdwAIAUgAxA0BH8gACADKAIAIAUgCxA0BH8CfyADIAMoAgBBBGoiCDYCACALKAIABEAgBkEAOwEAIAdBADsBACAAIAggBSAGEDUEQAJAQQAhCANAIAAgAygCAEECaiAFIAcQNUUNASAJQQA7AQAgCkEAOwEAQQECfwJAIAYuAQBBkQJHDQAgACADKAIAQQRqIAUgChA1RQ0AIAAgAygCAEEGaiAFIAkQNUUNACABIAkvAQA2AgAgAiAKLwEANgIAQQAMAQsgAyADKAIAIAcvAQBBBGpqNgIAQQELRQ0EGkEAIAhBAWoiCCALKAIATw0EGiADKAIAIQwgBkEAOwEAIAdBADsBACAAIAwgBSAGEDUNAAsLCwtBAAsFQQALBUEACyENIAQkAyANCyoBAX8gAEEUEB0iAzYCACAAIAFBBGo2AgQgAyACKAIANgIQIABBAToACAs3AQJ/IABBHGoiAigCACIDIAAoAiBGBEAgAEEYaiABEJsBBSADIAEQWyACIAIoAgBBKGo2AgALCyMAIAAgASkCADcCACAAIAEoAgg2AgggAEEMaiABQQxqEJ4BCzwBAX8gAEEsEB0iAzYCACAAIAFBBGo2AgQgA0EQaiIBIAIoAgA2AgAgAUEEaiACQQRqEIgCIABBAToACAs+AQF/IABBBGohAyABIAJHBEAgAygCACEAA0AgACABEFsgAyADKAIAQShqIgA2AgAgAUEoaiIBIAJHDQALCwtBAQF/QebMmTMgAUkEQBAACyABQebMmTNLBEAQAAUgACABQShsEB0iAjYCBCAAIAI2AgAgACABQShsIAJqNgIICwtLAQN/IABBADYCACAAQQA2AgQgAEEANgIIIAFBBGoiAygCACABKAIAayIEQShtIQIgBARAIAAgAhCLAiAAIAEoAgAgAygCABCKAgsLSwEDfyAAQQA2AgAgAEEANgIEIABBADYCCCABQQRqIgMoAgAgASgCAGsiBEECdSECIAQEQCAAIAIQWiAAIAEoAgAgAygCACACEHMLC24BA38jAyEEIwNBIGokAyAEIAEoAgA2AgAgBEEMaiIFIAQoAgA2AgAgACAFIARBCGoiBiAEQQRqIAIQmgEiAigCACIBRQRAIAUgACADEIkCIAAgBigCACACIAUoAgAQbyAFKAIAIQELIAQkAyABC1gBA38gAEEANgIAIABBBGoiA0EANgIAIABBADYCCCAAQQIQWkECIQAgAygCACIEIQIDQCACIAEoAgA2AgAgAkEEaiECIABBf2oiAA0ACyADIARBCGo2AgALYAEEfyAAIAEoAgA2AgAgACABKAIEIgM2AgQgACABQQhqIgQoAgAiBTYCCCAAQQRqIQIgBQRAIAMgAjYCCCABIAFBBGoiADYCACAAQQA2AgAgBEEANgIABSAAIAI2AgALC+EBAQN/IAAgARCQAiAAQQxqIgJBADYCACAAQRBqIgNBADYCACAAQRRqIgRBADYCACACIAFBDGoiAigCADYCACADIAFBEGoiAygCADYCACAEIAFBFGoiBCgCADYCACAEQQA2AgAgA0EANgIAIAJBADYCACAAQRhqIgJBADYCACAAQRxqIgNBADYCACAAQSBqIgRBADYCACACIAFBGGoiAigCADYCACADIAFBHGoiAygCADYCACAEIAFBIGoiBCgCADYCACAEQQA2AgAgA0EANgIAIAJBADYCACAAIAEoAiQ2AiQLSAEDfyAAKAIEIgMgAEEIaiICKAIAIgFHBEADQCACIAFBWGoiATYCACABEC4gAigCACIBIANHDQALCyAAKAIAIgAEQCAAECQLC8UBAQZ/IAFBBGohAiAAKAIAIgUgAEEEaiIGKAIAIgRGBH8gACEHIAIoAgAhAyACBSACKAIAIQMDQCADQVhqIARBWGoiBBCRAiACIAIoAgBBWGoiAzYCACAEIAVHDQALIAAhByAAKAIAIQUgAgshBCAHIAM2AgAgBCAFNgIAIAYoAgAhAyAGIAFBCGoiAigCADYCACACIAM2AgAgAEEIaiIAKAIAIQMgACABQQxqIgAoAgA2AgAgACADNgIAIAEgBCgCADYCAAtdAQJ/IABBDGoiBUEANgIAIAAgAzYCECABBEAgAUHmzJkzSwRAEAAFIAFBKGwQHSEECwsgACAENgIAIAAgAkEobCAEaiICNgIIIAAgAjYCBCAFIAFBKGwgBGo2AgAL/AEBCX8jAyEGIwNBQGskAyAGQThqIQogBkEwaiEIIAZBLGohCyAGQShqIQwgBiEJIAZBNGoiDSADNgIAIAVBygIQHAR/An8gCkEANgIAIAhBADYCACAFQcoCQQQgCiAIEEgaIAggCCgCAEECdiIHNgIAIAdBAEcgAkEAR3EEQAJAQQAhBwJAAkADQCAEIAooAgAgB0ECdGogDSALEDQEQCAJIAMQNyAAIAsoAgAgAyABIAQgCSAMED1FDQIgBSAJEIcCIAkQLiAHQQFqIgcgCCgCAEkgByACSXENAQwECwsMAQsgCRAuC0EADAILC0EBCwVBAQshDiAGJAMgDgsyAQF/IABBCGoiAigCACEAA0AgAEEAOgAAIAIgAigCAEEBaiIANgIAIAFBf2oiAQ0ACwuSAQECfyAAQQA6AAAgAEEcaiECIABBBGohAQNAIAEQQiABQQhqIgEgAkcNAAsgAEE4aiECIABBIGohAQNAIAEQQiABQQhqIgEgAkcNAAsgAEEAOgA4IABBPGoQQiAAQdwAaiECIABBxABqIQEDQCABEEIgAUEIaiIBIAJHDQALIABB3ABqIgBCADcCACAAQQA2AggLpAEBB38jAyEFIwNBIGokAyAFIQIgAEEIaiIDKAIAIABBBGoiBygCACIEayABSQRAQf////8HIAEgBCAAKAIAa2oiBkkEQBAABSACIAYgAygCACAAKAIAIghrIgNBAXQiBCAEIAZJG0H/////ByADQf////8DSRsgBygCACAIayAAQQhqEGIgAiABEJYCIAAgAhBhIAIQYAsFIAAgARCuAQsgBSQDCzsBA38gAEEEaiIDKAIAIAAoAgAiBGsiAiABSQRAIAAgASACaxCYAgUgAiABSwRAIAMgASAEajYCAAsLC40CAQV/IAEgACABRiICOgAMIAJFBEACQCABIQICQANAAkAgAigCCCIDQQxqIgUsAAANAwJ/IAMoAggiASgCACIEIANGBH8gASgCBCIERQ0CIARBDGoiBCwAAA0CIAQFIARFDQQgBEEMaiIELAAADQQgBAshBiAFQQE6AAAgASAAIAFGOgAMIAYLQQE6AAAgACABRg0DIAEhAgwBCwsgAygCACACRwRAIAMQnQEgAygCCCIAQQxqIQUgACgCCCEBCyAFQQE6AAAgAUEAOgAMIAEQnAEMAQsgAiADKAIARgRAIAMQnAEgAygCCCIAQQxqIQUgACgCCCEBCyAFQQE6AAAgAUEAOgAMIAEQnQELCwtcAQF/IABBLBAdIgM2AgAgACABQQRqNgIEIAMgAigCACgCADYC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QQA2AgggAUHtJ0ECEBogAkEkaiIBQgA3AgAgAUEANgIIIAFB8CdBAhAaIAJBMGoiAUIANwMAIAFBADYCCCABQfMnQQIQGkEAIQEDQCABBEBBASEBBSAAIAAoAgAoAgxBP3ERAgAhASAHIAUgCEEMbCACahDDAiADIAEgBxAxIQEgBxAZCyAIQQFqIghBBUcNAAsgAkE8aiEAA0AgAEF0aiIAEBkgACACRw0ACyAFEBkFQQAhAQsgBBAZBUEAIQELBUEAIQELBUEAIQELIAMQHiAGJAMgAQsEAEEBC3YBA38jAyEEIwNBQGskAyAEIgJBDGoiAyAAIAEQLSADIAJBOGoiABAyBEAgAyAALAAAQQBHQSoQPARAIAJCADcCACACQQA2AgggAkGWJ0EEEBogA0EIIAIQOSEAIAIQGQVBACEACwVBACEACyADEB4gBCQDIAALBABBAguRAgEGfyMDIQQjA0HQAGokAyAEQcUAaiEFIARBDGohAyAEIgJBGGoiBiAAIAEQLSAGIAJBxABqIgAQMgRAIANCADcCACADQQA2AgggACwAAARAIAJCADcCACACQQA2AgggAkHGJkEIEBoFIAJCADcCACACQQA2AgggAkHPJkHPJhA/EBoLIANBC2oiACwAAEEASARAAn8gAygCACEHIAVBADoAACAHCyAFEBsgA0EANgIEBSAFQQA6AAAgAyAFEBsgAEEAOgAACyADQQAQKyADIAIpAgA3AgAgAyACKAIINgIIIAJCADcCACACQQA2AgggAhAZIAZBBiADEDkhACADEBkFQQAhAAsgBhAeIAQkAyAACwQAQQMLqwUBC38jAyEIIwNB4ABqJAMgCEHdAGohBCAIQSRqIQYgCCIDQRhqIQIgA0EwaiIHIAAgARAtIAcgA0HcAGoiARAyBEAgBkIANwIAIAZBADYCCCAGQeMlQRAQGiAHQRAgBhA5BH9BAQUgA0IANwMAIANCADcDCCADQgA3AxAgASwAAARAIAJCADcCACACQQA2AgggAkH0JUEEEBogA0ELaiIBLAAAQQBIBEACfyADKAIAIQkgBEEAOgAAIAkLIAQQGyADQQA2AgQFIARBADoAACADIAQQGyABQQA6AAALIANBABArIAMgAikCADcCACADIAIoAgg2AgggAkIANwIAIAJBADYCCCACEBkgAkIANwIAIAJBADYCCCACQfklQQQQGgUgAkIANwIAIAJBADYCCCACQf4lQQQQGiADQQtqIgEsAABBAEgEQAJ/IAMoAgAhCiAEQQA6AAAgCgsgBBAbIANBADYCBAUgBEEAOgAAIAMgBBAbIAFBADoAAAsgA0EAECsgAyACKQIANwIAIAMgAigCCDYCCCACQgA3AgAgAkEANgIIIAIQGSACQgA3AgAgAkEANgIIIAJBgyZBBBAaCyADQQxqIgVBC2oiASwAAEEASAR/An8gBSgCACELIARBADoAACALCyAEEBsgA0EANgIQIAUFIARBADoAACAFIAQQGyABQQA6AAAgBQshASAFQQAQKyABIAIpAgA3AgAgASACKAIINgIIIAJCADcCACACQQA2AgggAhAZIAAoAgAoAgwhASAHIAAgAUE/cRECACADEDEEfyAAKAIAKAIMIQEgByAAIAFBP3ERAgAgA0EMahAxBUEACyEMIANBGGohAANAIABBdGoiABAZIAAgA0cNAAsgDAshACAGEBkFQQAhAAsgBxAeIAgkAyAAC40MARF/IwMhBiMDQYABaiQDIAZB9QBqIQUgBiIEQTxqIQIgBEHIAGoiByAAIAEQLSAHIARB9ABqIgEQMgR/IARCADcDACAEQgA3AwggBEIANwMQIARCADcDGCAEQgA3AyAgBEIANwMoIARCADcDMCAEQQA2AjggASwAAARAIAJCADcCACACQQA2AgggAkHfJEEIEBogBEELaiIBLAAAQQBIBEACfyAEKAIAIQggBUEAOgAAIAgLIAUQGyAEQQA2AgQFIAVBADoAACAEIAUQGyABQQA6AAALIARBABArIAQgAikCADcCACAEIAIoAgg2AgggAkIANwIAIAJBADYCCCACEBkgAkIANwIAIAJBADYCCCACQegkQQgQGiAEQQxqIgFBC2oiAywAAEEASAR/An8gASgCACEJIAVBADoAACAJCyAFEBsgBEEANgIQIAEFIAVBADoAACABIAUQGyADQQA6AAAgAQshAyABQQAQKyADIAIpAgA3AgAgAyACKAIINgIIIAJCADcCACACQQA2AgggAhAZIAJCADcCACACQQA2AgggAkHxJEEEEBogBEEYaiIBQQtqIgMsAABBAEgEfwJ/IAEoAgAhCiAFQQA6AAAgCgsgBRAbIARBADYCHCABBSAFQQA6AAAgASAFEBsgA0EAOgAAIAELIQMgAUEAECsgAyACKQIANwIAIAMgAigCCDYCCCACQgA3AgAgAkEANgIIIAIQGSACQgA3AgAgAkEANgIIIAJB9iRBAhAaIARBJGoiAUELaiIDLAAAQQBIBH8CfyABKAIAIQsgBUEAOgAAIAsLIAUQGyAEQQA2AiggAQUgBUEAOgAAIAEgBRAbIANBADoAACABCyEDIAFBABArIAMgAikCADcCACADIAIoAgg2AgggAkIANwIAIAJBADYCCCACEBkgAkIANwIAIAJBADYCCCACQfkkQQgQGgUgAkIANwIAIAJBADYCCCACQYIlQQgQGiAEQQtqIgEsAABBAEgEQAJ/IAQoAgAhDCAFQQA6AAAgDAsgBRAbIARBADYCBAUgBUEAOgAAIAQgBRAbIAFBADoAAAsgBEEAECsgBCACKQIANwIAIAQgAigCCDYCCCACQgA3AgAgAkEANgIIIAIQGSACQgA3AgAgAkEANgIIIAJBiyVBCBAaIARBDGoiAUELaiIDLAAAQQBIBH8CfyABKAIAIQ0gBUEAOgAAIA0LIAUQGyAEQQA2AhAgAQUgBUEAOgAAIAEgBRAbIANBADoAACABCyEDIAFBABArIAMgAikCADcCACADIAIoAgg2AgggAkIANwIAIAJBADYCCCACEBkgAkIANwIAIAJBADYCCCACQZQlQQQQGiAEQRhqIgFBC2oiAywAAEEASAR/An8gASgCACEOIAVBADoAACAOCyAFEBsgBEEANgIcIAEFIAVBADoAACABIAUQGyADQQA6AAAgAQshAyABQQAQKyADIAIpAgA3AgAgAyACKAIINgIIIAJCADcCACACQQA2AgggAhAZIAJCADcCACACQQA2AgggAkGZJUECEBogBEEkaiIBQQtqIgMsAABBAEgEfwJ/IAEoAgAhDyAFQQA6AAAgDwsgBRAbIARBADYCKCABBSAFQQA6AAAgASAFEBsgA0EAOgAAIAELIQMgAUEAECsgAyACKQIANwIAIAMgAigCCDYCCCACQgA3AgAgAkEANgIIIAIQGSACQgA3AgAgAkEANgIIIAJBnCVBCBAaCyAEQTBqIgFBC2oiAywAAEEASAR/An8gASgCACEQIAVBADoAACAQCyAFEBsgBEEANgI0IAEFIAVBADoAACABIAUQGyADQQA6AAAgAQshAyABQQAQKyADIAIpAgA3AgAgAyACKAIINgIIIAJCADcCACACQQA2AgggAhAZAn8gBEE8aiERQQAhA0EAIQEDQCAAKAIAKAIMIQUgAyAHIAAgBUE/cRECACABQQxsIARqEDFBAXFqIQMgAUEBaiIBQQVHDQALIBELIQADQCAAQXRqIgAQGSAAIARHDQALIANBAUsFQQALIRIgBxAeIAYkAyASCwUAQYAICwQAQQUL9wQBCX8jAyEHIwNB4ABqJAMgB0HRAGohBCAHIgNBGGohAiADQSRqIgYgACABEC0gBiADQdAAaiIBEDIEQCADQgA3AwAgA0IANwMIIANCADcDECABLAAABEAgAkIANwIAIAJBADYCCCACQY0kQQQQGiADQQtqIgEsAABBAEgEQAJ/IAMoAgAhCCAEQQA6AAAgCAsgBBAbIANBADYCBAUgBEEAOgAAIAMgBBAbIAFBADoAAAsgA0EAECsgAyACKQIANwIAIAMgAigCCDYCCCACQgA3AgAgAkEANgIIIAIQGSACQgA3AgAgAkEANgIIIAJBkiRBBBAaBSACQgA3AgAgAkEANgIIIAJBlyRBBBAaIANBC2oiASwAAEEASARAAn8gAygCACEJIARBADoAACAJCyAEEBsgA0EANgIEBSAEQQA6AAAgAyAEEBsgAUEAOgAACyADQQAQKyADIAIpAgA3AgAgAyACKAIINgIIIAJCADcCACACQQA2AgggAhAZIAJCADcCACACQQA2AgggAkGcJEEEEBoLIANBDGoiAUELaiIFLAAAQQBIBH8CfyABKAIAIQogBEEAOgAAIAoLIAQQGyADQQA2AhAgAQUgBEEAOgAAIAEgBBAbIAVBADoAACABCyEEIAFBABArIAQgAikCADcCACAEIAIoAgg2AgggAkIANwIAIAJBADYCCCACEBkgACgCACgCDCEBIAYgACABQT9xEQIAIAMQMQR/IAAoAgAoAgwhASAGIAAgAUE/cRECACADQQxqEDEFQQALIQEgA0EYaiEAA0AgAEF0aiIAEBkgACADRw0ACwVBACEBCyAGEB4gByQDIAELBABBBgtwAQN/IwMhAyMDQUBrJAMgAyICQQxqIgQgACABEC0gASACQThqEDIEQCACQgA3AgAgAkEANgIIIAJBxiNBCBAaIAAoAgAoAgwhASAEIAAgAUE/cRECACACEDEh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AQAAAQEAAAICAAABAgAAFwEAABEBAABKAQAAIMYAAAABAAABAQAAFwEAABEBAABKAQAAA6AAAAKgAAAXAQAAEQEAAAOgAAACoAAAAgIAAAECAABKAQAAAAAAAEAGAAAfAAAAIAAAACEAAAAiAAAAAQAAAAEAAAACAAAAAQAAAAAAAABoBgAAHwAAACMAAAAhAAAAIgAAAAEAAAACAAAAAwAAAAIAAAAAAAAAeAYAAB8AAAAkAAAAIQAAACIAAAACAAAAAAAAAPAGAAAfAAAAJQAAACEAAAAiAAAAAQAAAAMAAAAEAAAAAwAAAGltYWdlAGRhdGEAcGlleC5jcHAAUmVhZEltYWdlAGVycm9yAGZhaWxlZCB0byBleHRyYWN0IHByZXZpZXcAdW5zdXBwb3J0ZWQgcHJldmlldyB0eXBlAHVua25vd24gZXJyb3IAMTZQaWV4U3RyZWFtUmVhZGVyAE40cGlleDE1U3RyZWFtSW50ZXJmYWNlRQBtYWtlcgBtb2RlbABwcmV2aWV3AHRodW1ibmFpbABOU3QzX18yMTJiYXNpY19zdHJpbmdJY05TXzExY2hhcl90cmFpdHNJY0VFTlNfOWFsbG9jYXRvckljRUVFRQBOU3QzX18yMjFfX2Jhc2ljX3N0cmluZ19jb21tb25JTGIxRUVFAGNvbG9yU3BhY2UAb3JpZW50YXRpb24AZm9ybWF0AG9mZnNldABsZW5ndGgAd2lkdGgAaGVpZ2h0AGFkb2JlUmdiAHNSZ2IATjEwZW1zY3JpcHRlbjN2YWxFAGlpaWkATjRwaWV4MTJiaW5hcnlfcGFyc2UxNFBhZ2VkQnl0ZUFycmF5RQAhY2hlY2tlcnNfLmVtcHR5KCkAbm9kZV9tb2R1bGVzL3BpZXgvc3JjL2ltYWdlX3R5cGVfcmVjb2duaXRpb24vaW1hZ2VfdHlwZV9yZWNvZ25pdGlvbl9saXRlLmNjAFJlcXVlc3RlZFNpemUAYQBDb21wYXJlAGIARk9WYgBwb3NfaW5fcGFnZSA8IGN1cnJlbnRfcGFnZV9sZW5fAG5vZGVfbW9kdWxlcy9waWV4L3NyYy9iaW5hcnlfcGFyc2UvcmFuZ2VfY2hlY2tlZF9ieXRlX3B0ci5oAG9wZXJhdG9yW10Ab2Zmc2V0ID49IHN1Yl9hcnJheV9iZWdpbl8gJiYgb2Zmc2V0IDwgc3ViX2FycmF5X2VuZF8Abm9kZV9tb2R1bGVzL3BpZXgvc3JjL2JpbmFyeV9wYXJzZS9yYW5nZV9jaGVja2VkX2J5dGVfcHRyLmNjAGxvYWRQYWdlRm9yT2Zmc2V0AGZhbHNlAHJlbWFpbmluZ0xlbmd0aABONHBpZXgyMmltYWdlX3R5cGVfcmVjb2duaXRpb24xMl9HTE9CQUxfX05fMTE0WDNmVHlwZUNoZWNrZXJFAE40cGlleDIyaW1hZ2VfdHlwZV9yZWNvZ25pdGlvbjEyX0dMT0JBTF9fTl8xMTFUeXBlQ2hlY2tlckUAU0FNU1VORwBONHBpZXgyMmltYWdlX3R5cGVfcmVjb2duaXRpb24xMl9HTE9CQUxfX05fMTE0U3J3VHlwZUNoZWNrZXJFAE40cGlleDIyaW1hZ2VfdHlwZV9yZWNvZ25pdGlvbjEyX0dMT0JBTF9fTl8xMTRSdzJUeXBlQ2hlY2tlckUAQVJFQ09ZSwBONHBpZXgyMmltYWdlX3R5cGVfcmVjb2duaXRpb24xMl9HTE9CQUxfX05fMTIxUmF3Q29udGF4TlR5cGVDaGVja2VyRQBGVUpJRklMTQBONHBpZXgyMmltYWdlX3R5cGVfcmVjb2duaXRpb24xMl9HTE9CQUxfX05fMTE0UmFmVHlwZUNoZWNrZXJFAHFrdGsAAAAIAHFrdG4AAAAIAE40cGlleDIyaW1hZ2VfdHlwZV9yZWNvZ25pdGlvbjEyX0dMT0JBTF9fTl8xMTRRdGtUeXBlQ2hlY2tlckUAQU9DAE1NAFBFTlRBWCAAAE40cGlleDIyaW1hZ2VfdHlwZV9yZWNvZ25pdGlvbjEyX0dMT0JBTF9fTl8xMTRQZWZUeXBlQ2hlY2tlckUAT0xZTVAATjRwaWV4MjJpbWFnZV90eXBlX3JlY29nbml0aW9uMTJfR0xPQkFMX19OXzExNE9yZlR5cGVDaGVja2VyRQBOUlcgICAATklLT04AAhQABQAUAgUAAE40cGlleDIyaW1hZ2VfdHlwZV9yZWNvZ25pdGlvbjEyX0dMT0JBTF9fTl8xMTROcndUeXBlQ2hlY2tlckUATjRwaWV4MjJpbWFnZV90eXBlX3JlY29nbml0aW9uMTJfR0xPQkFMX19OXzExNE5lZlR5cGVDaGVja2VyRQAATVJNAE40cGlleDIyaW1hZ2VfdHlwZV9yZWNvZ25pdGlvbjEyX0dMT0JBTF9fTl8xMTRNcndUeXBlQ2hlY2tlckUAUEtUUwAAAAEATjRwaWV4MjJpbWFnZV90eXBlX3JlY29nbml0aW9uMTJfR0xPQkFMX19OXzExNE1vc1R5cGVDaGVja2VyRQD6DQABAPoAAAIADfoBAAAA+gIAAE40cGlleDIyaW1hZ2VfdHlwZV9yZWNvZ25pdGlvbjEyX0dMT0JBTF9fTl8xMTRLZGNUeXBlQ2hlY2tlckUAxhIAAQAAAAQAxhMAAQAAAAQAxhQAAgDGIADGLQAEAAAAAQASxgEABAAAAAATxgEABAAAAAAUxgIAACDGAC3GBAABAAAAAE40cGlleDIyaW1hZ2VfdHlwZV9yZWNvZ25pdGlvbjEyX0dMT0JBTF9fTl8xMTREbmdUeXBlQ2hlY2tlckUAS09EQUsgICAgICAgICAgIAAD6QACAAzlAAIA6QMCAADlDAIAAE40cGlleDIyaW1hZ2VfdHlwZV9yZWNvZ25pdGlvbjEyX0dMT0JBTF9fTl8xMTREY3JUeXBlQ2hlY2tlckUAABC6sKy7AAIASEVBUENDRFIATjRwaWV4MjJpbWFnZV90eXBlX3JlY29nbml0aW9uMTJfR0xPQkFMX19OXzExNENyd1R5cGVDaGVja2VyRQBDUgIAAE40cGlleDIyaW1hZ2VfdHlwZV9yZWNvZ25pdGlvbjEyX0dMT0JBTF9fTl8xMTRDcjJUeXBlQ2hlY2tlckUAU09OWQAAsAEABAAAAAACAAADAAADAQADAgADAwBONHBpZXgyMmltYWdlX3R5cGVfcmVjb2duaXRpb24xMl9HTE9CQUxfX05fMTE0QXJ3VHlwZUNoZWNrZXJFAGFycmF5AFJhbmdlQ2hlY2tlZEJ5dGVQdHIATlN0M19fMjE0ZGVmYXVsdF9kZWxldGVJTjRwaWV4MTJiaW5hcnlfcGFyc2UxMl9HTE9CQUxfX05fMTIwTWVtb3J5UGFnZWRCeXRlQXJyYXlFRUUATlN0M19fMjIwX19zaGFyZWRfcHRyX3BvaW50ZXJJUE40cGlleDEyYmluYXJ5X3BhcnNlMTJfR0xPQkFMX19OXzEyME1lbW9yeVBhZ2VkQnl0ZUFycmF5RU5TXzE0ZGVmYXVsdF9kZWxldGVJUzRfRUVOU185YWxsb2NhdG9ySVM0X0VFRUUATjRwaWV4MTJiaW5hcnlfcGFyc2UxMl9HTE9CQUxfX05fMTIwTWVtb3J5UGFnZWRCeXRlQXJyYXlFAFNpemVPZlR5cGUodHlwZSwgTlVMTCApICogY291bnQgPT0gdmFsdWUuc2l6ZSgpAG5vZGVfbW9kdWxlcy9waWV4L3NyYy90aWZmX2RpcmVjdG9yeS90aWZmX2RpcmVjdG9yeS5jYwBBZGRFbnRyeQBJSU1Ndm9pZABib29sAHN0ZDo6c3RyaW5nAHN0ZDo6YmFzaWNfc3RyaW5nPHVuc2lnbmVkIGNoYXI+AHN0ZDo6d3N0cmluZwBlbXNjcmlwdGVuOjp2YWwAZW1zY3JpcHRlbjo6bWVtb3J5X3ZpZXc8c2lnbmVkIGNoYXI+AGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PHVuc2lnbmVkIGNoYXI+AGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PHNob3J0PgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzx1bnNpZ25lZCBzaG9ydD4AZW1zY3JpcHRlbjo6bWVtb3J5X3ZpZXc8aW50PgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzx1bnNpZ25lZCBpbnQ+AGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PGludDhfdD4AZW1zY3JpcHRlbjo6bWVtb3J5X3ZpZXc8dWludDhfdD4AZW1zY3JpcHRlbjo6bWVtb3J5X3ZpZXc8aW50MTZfdD4AZW1zY3JpcHRlbjo6bWVtb3J5X3ZpZXc8dWludDE2X3Q+AGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PGludDMyX3Q+AGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PHVpbnQzMl90PgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzxsb25nIGRvdWJsZT4ATjEwZW1zY3JpcHRlbjExbWVtb3J5X3ZpZXdJZUVFAGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PGRvdWJsZT4ATjEwZW1zY3JpcHRlbjExbWVtb3J5X3ZpZXdJZEVFAGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PGZsb2F0PgBOMTBlbXNjcmlwdGVuMTFtZW1vcnlfdmlld0lmRUUAZW1zY3JpcHRlbjo6bWVtb3J5X3ZpZXc8dW5zaWduZWQgbG9uZz4ATjEwZW1zY3JpcHRlbjExbWVtb3J5X3ZpZXdJbUVFAGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PGxvbmc+AE4xMGVtc2NyaXB0ZW4xMW1lbW9yeV92aWV3SWxFRQBOMTBlbXNjcmlwdGVuMTFtZW1vcnlfdmlld0lqRUUATjEwZW1zY3JpcHRlbjExbWVtb3J5X3ZpZXdJaUVFAE4xMGVtc2NyaXB0ZW4xMW1lbW9yeV92aWV3SXRFRQBOMTBlbXNjcmlwdGVuMTFtZW1vcnlfdmlld0lzRUUATjEwZW1zY3JpcHRlbjExbWVtb3J5X3ZpZXdJaEVFAE4xMGVtc2NyaXB0ZW4xMW1lbW9yeV92aWV3SWFFRQBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzxjaGFyPgBOMTBlbXNjcmlwdGVuMTFtZW1vcnlfdmlld0ljRUUATlN0M19fMjEyYmFzaWNfc3RyaW5nSXdOU18xMWNoYXJfdHJhaXRzSXdFRU5TXzlhbGxvY2F0b3JJd0VFRUUATlN0M19fMjEyYmFzaWNfc3RyaW5nSWhOU18xMWNoYXJfdHJhaXRzSWhFRU5TXzlhbGxvY2F0b3JJaEVFRUUAZG91YmxlAGZsb2F0AHVuc2lnbmVkIGxvbmcAbG9uZwB1bnNpZ25lZCBpbnQAaW50AHVuc2lnbmVkIHNob3J0AHNob3J0AHVuc2lnbmVkIGNoYXIAc2lnbmVkIGNoYXIAY2hhcgBOU3QzX18yMTRfX3NoYXJlZF9jb3VudEUATlN0M19fMjE5X19zaGFyZWRfd2Vha19jb3VudEUATjEwX19jeHhhYml2MTE2X19zaGltX3R5cGVfaW5mb0UAU3Q5dHlwZV9pbmZvAE4xMF9fY3h4YWJpdjEyMF9fc2lfY2xhc3NfdHlwZV9pbmZvRQBOMTBfX2N4eGFiaXYxMTdfX2NsYXNzX3R5cGVfaW5mb0UATjEwX19jeHhhYml2MTIzX19mdW5kYW1lbnRhbF90eXBlX2luZm9FAHYAYwBoAHMAdABpAGoAbABtAGYAZABOMTBfX2N4eGFiaXYxMjFfX3ZtaV9jbGFzc190eXBlX2luZm9F";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}function getBinary(){try{if(Module["wasmBinary"]){return new Uint8Array(Module["wasmBinary"])}var binary=tryParseAsDataURI(wasmBinaryFile);if(binary){return binary}if(Module["readBinary"]){return Module["readBinary"](wasmBinaryFile)}else{throw"both async and sync fetching of the wasm failed"}}catch(err){abort(err)}}function getBinaryPromise(){if(!Module["wasmBinary"]&&(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER)&&typeof fetch==="function"){return fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){if(!response["ok"]){throw"failed to load wasm binary file at '"+wasmBinaryFile+"'"}return response["arrayBuffer"]()}).catch(function(){return getBinary()})}return new Promise(function(resolve,reject){resolve(getBinary())})}function createWasm(env){var info={"env":env,"global":{"NaN":NaN,Infinity:Infinity},"global.Math":Math,"asm2wasm":asm2wasmImports};function receiveInstance(instance,module){var exports=instance.exports;Module["asm"]=exports;removeRunDependency("wasm-instantiate")}addRunDependency("wasm-instantiate");if(Module["instantiateWasm"]){try{return Module["instantiateWasm"](info,receiveInstance)}catch(e){err("Module.instantiateWasm callback failed with error: "+e);return false}}function receiveInstantiatedSource(output){receiveInstance(output["instance"])}function instantiateArrayBuffer(receiver){getBinaryPromise().then(function(binary){return WebAssembly.instantiate(binary,info)}).then(receiver,function(reason){err("failed to asynchronously prepare wasm: "+reason);abort(reason)})}if(!Module["wasmBinary"]&&typeof WebAssembly.instantiateStreaming==="function"&&!isDataURI(wasmBinaryFile)&&typeof fetch==="function"){WebAssembly.instantiateStreaming(fetch(wasmBinaryFile,{credentials:"same-origin"}),info).then(receiveInstantiatedSource,function(reason){err("wasm streaming compile failed: "+reason);err("falling back to ArrayBuffer instantiation");instantiateArrayBuffer(receiveInstantiatedSource)})}else{instantiateArrayBuffer(receiveInstantiatedSource)}return{}}Module["asm"]=function(global,env,providedBuffer){env["memory"]=wasmMemory;env["table"]=wasmTable=new WebAssembly.Table({"initial":186,"maximum":186,"element":"anyfunc"});env["__memory_base"]=1024;env["__table_base"]=0;var exports=createWasm(env);return exports};__ATINIT__.push({func:function(){globalCtors()}});function ___assert_fail(condition,filename,line,func){abort("Assertion failed: "+UTF8ToString(condition)+", at: "+[filename?UTF8ToString(filename):"unknown filename",line,func?UTF8ToString(func):"unknown function"])}function ___cxa_pure_virtual(){ABORT=true;throw"Pure virtual function called!"}function getShiftFromSize(size){switch(size){case 1:return 0;case 2:return 1;case 4:return 2;case 8:return 3;default:throw new TypeError("Unknown type size: "+size)}}function embind_init_charCodes(){var codes=new Array(256);for(var i=0;i<256;++i){codes[i]=String.fromCharCode(i)}embind_charCodes=codes}var embind_charCodes=undefined;function readLatin1String(ptr){var ret="";var c=ptr;while(HEAPU8[c]){ret+=embind_charCodes[HEAPU8[c++]]}return ret}var awaitingDependencies={};var registeredTypes={};var typeDependencies={};var char_0=48;var char_9=57;function makeLegalFunctionName(name){if(undefined===name){return"_unknown"}name=name.replace(/[^a-zA-Z0-9_]/g,"$");var f=name.charCodeAt(0);if(f>=char_0&&f<=char_9){return"_"+name}else{return name}}function createNamedFunction(name,body){name=makeLegalFunctionName(name);return function(){"use strict";return body.apply(this,arguments)}}function extendError(baseErrorType,errorName){var errorClass=createNamedFunction(errorName,function(message){this.name=errorName;this.message=message;var stack=new Error(message).stack;if(stack!==undefined){this.stack=this.toString()+"\n"+stack.replace(/^Error(:[^\n]*)?\n/,"")}});errorClass.prototype=Object.create(baseErrorType.prototype);errorClass.prototype.constructor=errorClass;errorClass.prototype.toString=function(){if(this.message===undefined){return this.name}else{return this.name+": "+this.message}};return errorClass}var BindingError=undefined;function throwBindingError(message){throw new BindingError(message)}var InternalError=undefined;function throwInternalError(message){throw new InternalError(message)}function whenDependentTypesAreResolved(myTypes,dependentTypes,getTypeConverters){myTypes.forEach(function(type){typeDependencies[type]=dependentTypes});function onComplete(typeConverters){var myTypeConverters=getTypeConverters(typeConverters);if(myTypeConverters.length!==myTypes.length){throwInternalError("Mismatched type converter count")}for(var i=0;i<myTypes.length;++i){registerType(myTypes[i],myTypeConverters[i])}}var typeConverters=new Array(dependentTypes.length);var unregisteredTypes=[];var registered=0;dependentTypes.forEach(function(dt,i){if(registeredTypes.hasOwnProperty(dt)){typeConverters[i]=registeredTypes[dt]}else{unregisteredTypes.push(dt);if(!awaitingDependencies.hasOwnProperty(dt)){awaitingDependencies[dt]=[]}awaitingDependencies[dt].push(function(){typeConverters[i]=registeredTypes[dt];++registered;if(registered===unregisteredTypes.length){onComplete(typeConverters)}})}});if(0===unregisteredTypes.length){onComplete(typeConverters)}}function registerType(rawType,registeredInstance,options){options=options||{};if(!("argPackAdvance"in registeredInstance)){throw new TypeError("registerType registeredInstance requires argPackAdvance")}var name=registeredInstance.name;if(!rawType){throwBindingError('type "'+name+'" must have a positive integer typeid pointer')}if(registeredTypes.hasOwnProperty(rawType)){if(options.ignoreDuplicateRegistrations){return}else{throwBindingError("Cannot register type '"+name+"' twice")}}registeredTypes[rawType]=registeredInstance;delete typeDependencies[rawType];if(awaitingDependencies.hasOwnProperty(rawType)){var callbacks=awaitingDependencies[rawType];delete awaitingDependencies[rawType];callbacks.forEach(function(cb){cb()})}}function __embind_register_bool(rawType,name,size,trueValue,falseValue){var shift=getShiftFromSize(size);name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":function(wt){return!!wt},"toWireType":function(destructors,o){return o?trueValue:falseValue},"argPackAdvance":8,"readValueFromPointer":function(pointer){var heap;if(size===1){heap=HEAP8}else if(size===2){heap=HEAP16}else if(size===4){heap=HEAP32}else{throw new TypeError("Unknown boolean type size: "+name)}return this["fromWireType"](heap[pointer>>shift])},destructorFunction:null})}var emval_free_list=[];var emval_handle_array=[{},{value:undefined},{value:null},{value:true},{value:false}];function __emval_decref(handle){if(handle>4&&0===--emval_handle_array[handle].refcount){emval_handle_array[handle]=undefined;emval_free_list.push(handle)}}function count_emval_handles(){var count=0;for(var i=5;i<emval_handle_array.length;++i){if(emval_handle_array[i]!==undefined){++count}}return count}function get_first_emval(){for(var i=5;i<emval_handle_array.length;++i){if(emval_handle_array[i]!==undefined){return emval_handle_array[i]}}return null}function init_emval(){Module["count_emval_handles"]=count_emval_handles;Module["get_first_emval"]=get_first_emval}function __emval_register(value){switch(value){case undefined:{return 1}case null:{return 2}case true:{return 3}case false:{return 4}default:{var handle=emval_free_list.length?emval_free_list.pop():emval_handle_array.length;emval_handle_array[handle]={refcount:1,value:value};return handle}}}function simpleReadValueFromPointer(pointer){return this["fromWireType"](HEAPU32[pointer>>2])}function __embind_register_emval(rawType,name){name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":function(handle){var rv=emval_handle_array[handle].value;__emval_decref(handle);return rv},"toWireType":function(destructors,value){return __emval_register(value)},"argPackAdvance":8,"readValueFromPointer":simpleReadValueFromPointer,destructorFunction:null})}function _embind_repr(v){if(v===null){return"null"}var t=typeof v;if(t==="object"||t==="array"||t==="function"){return v.toString()}else{return""+v}}function floatReadValueFromPointer(name,shift){switch(shift){case 2:return function(pointer){return this["fromWireType"](HEAPF32[pointer>>2])};case 3:return function(pointer){return this["fromWireType"](HEAPF64[pointer>>3])};default:throw new TypeError("Unknown float type: "+name)}}function __embind_register_float(rawType,name,size){var shift=getShiftFromSize(size);name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":function(value){return value},"toWireType":function(destructors,value){if(typeof value!=="number"&&typeof value!=="boolean"){throw new TypeError('Cannot convert "'+_embind_repr(value)+'" to '+this.name)}return value},"argPackAdvance":8,"readValueFromPointer":floatReadValueFromPointer(name,shift),destructorFunction:null})}function runDestructors(destructors){while(destructors.length){var ptr=destructors.pop();var del=destructors.pop();del(ptr)}}function craftInvokerFunction(humanName,argTypes,classType,cppInvokerFunc,cppTargetFunc){var argCount=argTypes.length;if(argCount<2){throwBindingError("argTypes array size mismatch! Must at least get return value and 'this' types!")}var isClassMethodFunc=argTypes[1]!==null&&classType!==null;var needsDestructorStack=false;for(var i=1;i<argTypes.length;++i){if(argTypes[i]!==null&&argTypes[i].destructorFunction===undefined){needsDestructorStack=true;break}}var returns=argTypes[0].name!=="void";var argsWired=new Array(argCount-2);return function(){if(arguments.length!==argCount-2){throwBindingError("function "+humanName+" called with "+arguments.length+" arguments, expected "+(argCount-2)+" args!")}var destructors=needsDestructorStack?[]:null;var thisWired;if(isClassMethodFunc){thisWired=argTypes[1].toWireType(destructors,this)}for(var i=0;i<argCount-2;++i){argsWired[i]=argTypes[i+2].toWireType(destructors,arguments[i])}var invokerFuncArgs=isClassMethodFunc?[cppTargetFunc,thisWired]:[cppTargetFunc];var rv=cppInvokerFunc.apply(null,invokerFuncArgs.concat(argsWired));if(needsDestructorStack){runDestructors(destructors)}else{for(var i=isClassMethodFunc?1:2;i<argTypes.length;i++){var param=i===1?thisWired:argsWired[i-2];if(argTypes[i].destructorFunction!==null){argTypes[i].destructorFunction(param)}}}if(returns){return argTypes[0].fromWireType(rv)}}}function ensureOverloadTable(proto,methodName,humanName){if(undefined===proto[methodName].overloadTable){var prevFunc=proto[methodName];proto[methodName]=function(){if(!proto[methodName].overloadTable.hasOwnProperty(arguments.length)){throwBindingError("Function '"+humanName+"' called with an invalid number of arguments ("+arguments.length+") - expects one of ("+proto[methodName].overloadTable+")!")}return proto[methodName].overloadTable[arguments.length].apply(this,arguments)};proto[methodName].overloadTable=[];proto[methodName].overloadTable[prevFunc.argCount]=prevFunc}}function exposePublicSymbol(name,value,numArguments){if(Module.hasOwnProperty(name)){if(undefined===numArguments||undefined!==Module[name].overloadTable&&undefined!==Module[name].overloadTable[numArguments]){throwBindingError("Cannot register public name '"+name+"' twice")}ensureOverloadTable(Module,name,name);if(Module.hasOwnProperty(numArguments)){throwBindingError("Cannot register multiple overloads of a function with the same number of arguments ("+numArguments+")!")}Module[name].overloadTable[numArguments]=value}else{Module[name]=value;if(undefined!==numArguments){Module[name].numArguments=numArguments}}}function heap32VectorToArray(count,firstElement){var array=[];for(var i=0;i<count;i++){array.push(HEAP32[(firstElement>>2)+i])}return array}function replacePublicSymbol(name,value,numArguments){if(!Module.hasOwnProperty(name)){throwInternalError("Replacing nonexistant public symbol")}if(undefined!==Module[name].overloadTable&&undefined!==numArguments){Module[name].overloadTable[numArguments]=value}else{Module[name]=value;Module[name].argCount=numArguments}}function embind__requireFunction(signature,rawFunction){signature=readLatin1String(signature);function makeDynCaller(dynCall){return function(){var args=new Array(arguments.length+1);args[0]=rawFunction;for(var i=0;i<arguments.length;i++){args[i+1]=arguments[i]}return dynCall.apply(null,args)}}var fp;if(Module["FUNCTION_TABLE_"+signature]!==undefined){fp=Module["FUNCTION_TABLE_"+signature][rawFunction]}else if(typeof FUNCTION_TABLE!=="undefined"){fp=FUNCTION_TABLE[rawFunction]}else{var dc=Module["dynCall_"+signature];if(dc===undefined){dc=Module["dynCall_"+signature.replace(/f/g,"d")];if(dc===undefined){throwBindingError("No dynCall invoker for signature: "+signature)}}fp=makeDynCaller(dc)}if(typeof fp!=="function"){throwBindingError("unknown function pointer with signature "+signature+": "+rawFunction)}return fp}var UnboundTypeError=undefined;function getTypeName(type){var ptr=___getTypeName(type);var rv=readLatin1String(ptr);_free(ptr);return rv}function throwUnboundTypeError(message,types){var unboundTypes=[];var seen={};function visit(type){if(seen[type]){return}if(registeredTypes[type]){return}if(typeDependencies[type]){typeDependencies[type].forEach(visit);return}unboundTypes.push(type);seen[type]=true}types.forEach(visit);throw new UnboundTypeError(message+": "+unboundTypes.map(getTypeName).join([", "]))}function __embind_register_function(name,argCount,rawArgTypesAddr,signature,rawInvoker,fn){var argTypes=heap32VectorToArray(argCount,rawArgTypesAddr);name=readLatin1String(name);rawInvoker=embind__requireFunction(signature,rawInvoker);exposePublicSymbol(name,function(){throwUnboundTypeError("Cannot call "+name+" due to unbound types",argTypes)},argCount-1);whenDependentTypesAreResolved([],argTypes,function(argTypes){var invokerArgsArray=[argTypes[0],null].concat(argTypes.slice(1));replacePublicSymbol(name,craftInvokerFunction(name,invokerArgsArray,null,rawInvoker,fn),argCount-1);return[]})}function integerReadValueFromPointer(name,shift,signed){switch(shift){case 0:return signed?function readS8FromPointer(pointer){return HEAP8[pointer]}:function readU8FromPointer(pointer){return HEAPU8[pointer]};case 1:return signed?function readS16FromPointer(pointer){return HEAP16[pointer>>1]}:function readU16FromPointer(pointer){return HEAPU16[pointer>>1]};case 2:return signed?function readS32FromPointer(pointer){return HEAP32[pointer>>2]}:function readU32FromPointer(pointer){return HEAPU32[pointer>>2]};default:throw new TypeError("Unknown integer type: "+name)}}function __embind_register_integer(primitiveType,name,size,minRange,maxRange){name=readLatin1String(name);if(maxRange===-1){maxRange=4294967295}var shift=getShiftFromSize(size);var fromWireType=function(value){return value};if(minRange===0){var bitshift=32-8*size;fromWireType=function(value){return value<<bitshift>>>bitshift}}var isUnsignedType=name.indexOf("unsigned")!=-1;registerType(primitiveType,{name:name,"fromWireType":fromWireType,"toWireType":function(destructors,value){if(typeof value!=="number"&&typeof value!=="boolean"){throw new TypeError('Cannot convert "'+_embind_repr(value)+'" to '+this.name)}if(value<minRange||value>maxRange){throw new TypeError('Passing a number "'+_embind_repr(value)+'" from JS side to C/C++ side to an argument of type "'+name+'", which is outside the valid range ['+minRange+", "+maxRange+"]!")}return isUnsignedType?value>>>0:value|0},"argPackAdvance":8,"readValueFromPointer":integerReadValueFromPointer(name,shift,minRange!==0),destructorFunction:null})}function __embind_register_memory_view(rawType,dataTypeIndex,name){var typeMapping=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array];var TA=typeMapping[dataTypeIndex];function decodeMemoryView(handle){handle=handle>>2;var heap=HEAPU32;var size=heap[handle];var data=heap[handle+1];return new TA(heap["buffer"],data,size)}name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":decodeMemoryView,"argPackAdvance":8,"readValueFromPointer":decodeMemoryView},{ignoreDuplicateRegistrations:true})}function __embind_register_std_string(rawType,name){name=readLatin1String(name);var stdStringIsUTF8=name==="std::string";registerType(rawType,{name:name,"fromWireType":function(value){var length=HEAPU32[value>>2];var str;if(stdStringIsUTF8){var endChar=HEAPU8[value+4+length];var endCharSwap=0;if(endChar!=0){endCharSwap=endChar;HEAPU8[value+4+length]=0}var decodeStartPtr=value+4;for(var i=0;i<=length;++i){var currentBytePtr=value+4+i;if(HEAPU8[currentBytePtr]==0){var stringSegment=UTF8ToString(decodeStartPtr);if(str===undefined)str=stringSegment;else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+1}}if(endCharSwap!=0)HEAPU8[value+4+length]=endCharSwap}else{var a=new Array(length);for(var i=0;i<length;++i){a[i]=String.fromCharCode(HEAPU8[value+4+i])}str=a.join("")}_free(value);return str},"toWireType":function(destructors,value){if(value instanceof ArrayBuffer){value=new Uint8Array(value)}var getLength;var valueIsOfTypeString=typeof value==="string";if(!(valueIsOfTypeString||value instanceof Uint8Array||value instanceof Uint8ClampedArray||value instanceof Int8Array)){throwBindingError("Cannot pass non-string to std::string")}if(stdStringIsUTF8&&valueIsOfTypeString){getLength=function(){return lengthBytesUTF8(value)}}else{getLength=function(){return value.length}}var length=getLength();var ptr=_malloc(4+length+1);HEAPU32[ptr>>2]=length;if(stdStringIsUTF8&&valueIsOfTypeString){stringToUTF8(value,ptr+4,length+1)}else{if(valueIsOfTypeString){for(var i=0;i<length;++i){var charCode=value.charCodeAt(i);if(charCode>255){_free(ptr);throwBindingError("String has UTF-16 code units that do not fit in 8 bits")}HEAPU8[ptr+4+i]=charCode}}else{for(var i=0;i<length;++i){HEAPU8[ptr+4+i]=value[i]}}}if(destructors!==null){destructors.push(_free,ptr)}return ptr},"argPackAdvance":8,"readValueFromPointer":simpleReadValueFromPointer,destructorFunction:function(ptr){_free(ptr)}})}function __embind_register_std_wstring(rawType,charSize,name){name=readLatin1String(name);var getHeap,shift;if(charSize===2){getHeap=function(){return HEAPU16};shift=1}else if(charSize===4){getHeap=function(){return HEAPU32};shift=2}registerType(rawType,{name:name,"fromWireType":function(value){var HEAP=getHeap();var length=HEAPU32[value>>2];var a=new Array(length);var start=value+4>>shift;for(var i=0;i<length;++i){a[i]=String.fromCharCode(HEAP[start+i])}_free(value);return a.join("")},"toWireType":function(destructors,value){var HEAP=getHeap();var length=value.length;var ptr=_malloc(4+length*charSize);HEAPU32[ptr>>2]=length;var start=ptr+4>>shift;for(var i=0;i<length;++i){HEAP[start+i]=value.charCodeAt(i)}if(destructors!==null){destructors.push(_free,ptr)}return ptr},"argPackAdvance":8,"readValueFromPointer":simpleReadValueFromPointer,destructorFunction:function(ptr){_free(ptr)}})}function __embind_register_void(rawType,name){name=readLatin1String(name);registerType(rawType,{isVoid:true,name:name,"argPackAdvance":0,"fromWireType":function(){return undefined},"toWireType":function(destructors,o){return undefined}})}function __emval_incref(handle){if(handle>4){emval_handle_array[handle].refcount+=1}}var emval_symbols={};function getStringOrSymbol(address){var symbol=emval_symbols[address];if(symbol===undefined){return readLatin1String(address)}else{return symbol}}function __emval_new_cstring(v){return __emval_register(getStringOrSymbol(v))}function __emval_new_object(){return __emval_register({})}function requireHandle(handle){if(!handle){throwBindingError("Cannot use deleted val. handle = "+handle)}return emval_handle_array[handle].value}function __emval_set_property(handle,key,value){handle=requireHandle(handle);key=requireHandle(key);value=requireHandle(value);handle[key]=value}function requireRegisteredType(rawType,humanName){var impl=registeredTypes[rawType];if(undefined===impl){throwBindingError(humanName+" has unknown type "+getTypeName(rawType))}return impl}function __emval_take_value(type,argv){type=requireRegisteredType(type,"_emval_take_value");var v=type["readValueFromPointer"](argv);return __emval_register(v)}function _abort(){Module["abort"]()}function _emscripten_get_heap_size(){return TOTAL_MEMORY}function abortOnCannotGrowMemory(requestedSize){abort("Cannot enlarge memory arrays to size "+requestedSize+" bytes. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value "+TOTAL_MEMORY+", (2) compile with -s ALLOW_MEMORY_GROWTH=1 which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0 ")}function emscripten_realloc_buffer(size){var PAGE_MULTIPLE=65536;size=alignUp(size,PAGE_MULTIPLE);var old=Module["buffer"];var oldSize=old.byteLength;try{var result=wasmMemory.grow((size-oldSize)/65536);if(result!==(-1|0)){return Module["buffer"]=wasmMemory.buffer}else{return null}}catch(e){return null}}function _emscripten_resize_heap(requestedSize){var oldSize=_emscripten_get_heap_size();var PAGE_MULTIPLE=65536;var LIMIT=2147483648-PAGE_MULTIPLE;if(requestedSize>LIMIT){return false}var MIN_TOTAL_MEMORY=16777216;var newSize=Math.max(oldSize,MIN_TOTAL_MEMORY);while(newSize<requestedSize){if(newSize<=536870912){newSize=alignUp(2*newSize,PAGE_MULTIPLE)}else{newSize=Math.min(alignUp((3*newSize+2147483648)/4,PAGE_MULTIPLE),LIMIT)}}var replacement=emscripten_realloc_buffer(newSize);if(!replacement||replacement.byteLength!=newSize){return false}updateGlobalBuffer(replacement);updateGlobalBufferViews();TOTAL_MEMORY=newSize;HEAPU32[DYNAMICTOP_PTR>>2]=requestedSize;return true}function _llvm_trap(){abort("trap!")}function _emscripten_memcpy_big(dest,src,num){HEAPU8.set(HEAPU8.subarray(src,src+num),dest)}function ___setErrNo(value){if(Module["___errno_location"])HEAP32[Module["___errno_location"]()>>2]=value;return value}embind_init_charCodes();BindingError=Module["BindingError"]=extendError(Error,"BindingError");InternalError=Module["InternalError"]=extendError(Error,"InternalError");init_emval();UnboundTypeError=Module["UnboundTypeError"]=extendError(Error,"UnboundTypeError");var ASSERTIONS=false;function intArrayToString(array){var ret=[];for(var i=0;i<array.length;i++){var chr=array[i];if(chr>255){if(ASSERTIONS){assert(false,"Character code "+chr+" ("+String.fromCharCode(chr)+") at offset "+i+" not in 0x00-0xFF.")}chr&=255}ret.push(String.fromCharCode(chr))}return ret.join("")}var decodeBase64=typeof atob==="function"?atob:function(input){var keyStr="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";var output="";var chr1,chr2,chr3;var enc1,enc2,enc3,enc4;var i=0;input=input.replace(/[^A-Za-z0-9\+\/\=]/g,"");do{enc1=keyStr.indexOf(input.charAt(i++));enc2=keyStr.indexOf(input.charAt(i++));enc3=keyStr.indexOf(input.charAt(i++));enc4=keyStr.indexOf(input.charAt(i++));chr1=enc1<<2|enc2>>4;chr2=(enc2&15)<<4|enc3>>2;chr3=(enc3&3)<<6|enc4;output=output+String.fromCharCode(chr1);if(enc3!==64){output=output+String.fromCharCode(chr2)}if(enc4!==64){output=output+String.fromCharCode(chr3)}}while(i<input.length);return output};function intArrayFromBase64(s){try{var decoded=decodeBase64(s);var bytes=new Uint8Array(decoded.length);for(var i=0;i<decoded.length;++i){bytes[i]=decoded.charCodeAt(i)}return bytes}catch(_){throw new Error("Converting base64 string to bytes failed.")}}function tryParseAsDataURI(filename){if(!isDataURI(filename)){return}return intArrayFromBase64(filename.slice(dataURIPrefix.length))}var asmGlobalArg={};var asmLibraryArg={"e":abort,"d":___assert_fail,"v":___cxa_pure_virtual,"j":___setErrNo,"p":__embind_register_bool,"o":__embind_register_emval,"i":__embind_register_float,"n":__embind_register_function,"f":__embind_register_integer,"c":__embind_register_memory_view,"m":__embind_register_std_string,"z":__embind_register_std_wstring,"y":__embind_register_void,"l":__emval_decref,"k":__emval_incref,"x":__emval_new_cstring,"w":__emval_new_object,"g":__emval_set_property,"h":__emval_take_value,"b":_abort,"u":_emscripten_get_heap_size,"t":_emscripten_memcpy_big,"s":_emscripten_resize_heap,"r":_llvm_trap,"q":abortOnCannotGrowMemory,"a":DYNAMICTOP_PTR};var asm=Module["asm"](asmGlobalArg,asmLibraryArg,buffer);Module["asm"]=asm;var ___errno_location=Module["___errno_location"]=function(){return Module["asm"]["A"].apply(null,arguments)};var ___getTypeName=Module["___getTypeName"]=function(){return Module["asm"]["B"].apply(null,arguments)};var _free=Module["_free"]=function(){return Module["asm"]["C"].apply(null,arguments)};var _malloc=Module["_malloc"]=function(){return Module["asm"]["D"].apply(null,arguments)};var globalCtors=Module["globalCtors"]=function(){return Module["asm"]["O"].apply(null,arguments)};var stackAlloc=Module["stackAlloc"]=function(){return Module["asm"]["P"].apply(null,arguments)};var stackRestore=Module["stackRestore"]=function(){return Module["asm"]["Q"].apply(null,arguments)};var stackSave=Module["stackSave"]=function(){return Module["asm"]["R"].apply(null,arguments)};var dynCall_ii=Module["dynCall_ii"]=function(){return Module["asm"]["E"].apply(null,arguments)};var dynCall_iii=Module["dynCall_iii"]=function(){return Module["asm"]["F"].apply(null,arguments)};var dynCall_iiii=Module["dynCall_iiii"]=function(){return Module["asm"]["G"].apply(null,arguments)};var dynCall_iiiii=Module["dynCall_iiiii"]=function(){return Module["asm"]["H"].apply(null,arguments)};var dynCall_v=Module["dynCall_v"]=function(){return Module["asm"]["I"].apply(null,arguments)};var dynCall_vi=Module["dynCall_vi"]=function(){return Module["asm"]["J"].apply(null,arguments)};var dynCall_viii=Module["dynCall_viii"]=function(){return Module["asm"]["K"].apply(null,arguments)};var dynCall_viiii=Module["dynCall_viiii"]=function(){return Module["asm"]["L"].apply(null,arguments)};var dynCall_viiiii=Module["dynCall_viiiii"]=function(){return Module["asm"]["M"].apply(null,arguments)};var dynCall_viiiiii=Module["dynCall_viiiiii"]=function(){return Module["asm"]["N"].apply(null,arguments)};Module["asm"]=asm;Module["cwrap"]=cwrap;function ExitStatus(status){this.name="ExitStatus";this.message="Program terminated with exit("+status+")";this.status=status}ExitStatus.prototype=new Error;ExitStatus.prototype.constructor=ExitStatus;dependenciesFulfilled=function runCaller(){if(!Module["calledRun"])run();if(!Module["calledRun"])dependenciesFulfilled=runCaller};function run(args){args=args||Module["arguments"];if(runDependencies>0){return}preRun();if(runDependencies>0)return;if(Module["calledRun"])return;function doRun(){if(Module["calledRun"])return;Module["calledRun"]=true;if(ABORT)return;ensureInitRuntime();preMain();if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("")},1);doRun()},1)}else{doRun()}}Module["run"]=run;function abort(what){if(Module["onAbort"]){Module["onAbort"](what)}if(what!==undefined){out(what);err(what);what=JSON.stringify(what)}else{what=""}ABORT=true;EXITSTATUS=1;throw"abort("+what+"). Build with -s ASSERTIONS=1 for more info."}Module["abort"]=abort;if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}Module["noExitRuntime"]=true;run();
diff --git a/ui/file_manager/image_loader/piex/tests.html b/ui/file_manager/image_loader/piex/tests.html index 9d5a8ee..7baa39a3 100644 --- a/ui/file_manager/image_loader/piex/tests.html +++ b/ui/file_manager/image_loader/piex/tests.html
@@ -20,18 +20,15 @@ this.length = buffer.byteLength; } - process(resolve) { + process() { this.memory = Module._malloc(this.length); if (!this.memory) throw new Error('image malloc failure'); - this.callback = Module.addFunction((result) => { - resolve(this.result = result); - }, 'vi'); - - // Process the image: blocks until |callback| is called. Module.HEAP8.set(this.source, this.memory); - Module._image(this.memory, this.length, this.callback); + this.result = Module.image(this.memory, this.length); + + return this.result; } preview() { @@ -74,7 +71,6 @@ } close() { - Module.removeFunction(this.callback); Module._free(this.memory); } } @@ -254,7 +250,7 @@ // Extract the preview|thumbnail images, render them. return new Promise((resolve) => { - imageBuffer.process(resolve); + resolve(imageBuffer.process()); }).then((result) => { let preview = imageBuffer.preview(); let thumb = imageBuffer.thumbnail();
diff --git a/ui/file_manager/integration_tests/file_manager/launcher_search.js b/ui/file_manager/integration_tests/file_manager/launcher_search.js index 7addd7a..c4988c4b 100644 --- a/ui/file_manager/integration_tests/file_manager/launcher_search.js +++ b/ui/file_manager/integration_tests/file_manager/launcher_search.js
@@ -50,6 +50,8 @@ const hostedDocument = Object.assign( {}, ENTRIES.testDocument, {nameText: 'testDocument.txt.gdoc', targetPath: 'testDocument.txt'}); + const photos = Object.assign( + {}, ENTRIES.photos, {nameText: 'photos.txt', targetPath: 'photos.txt'}); /** * Tests Local and Drive files show up in search results. @@ -57,8 +59,8 @@ testcase.launcherSearch = async () => { // Create a file in Downloads, and a pinned and unpinned file in Drive. await setupAndWaitUntilReady( - 'downloads', [ENTRIES.tallText], - [ENTRIES.hello, ENTRIES.pinned, hostedDocument]); + 'downloads', [ENTRIES.tallText, photos], + [ENTRIES.hello, ENTRIES.pinned, hostedDocument, photos]); const result = JSON.parse(await sendTestMessage({ name: 'runLauncherSearch', @@ -67,6 +69,8 @@ chrome.test.assertEq( [ ENTRIES.hello.targetPath, + photos.targetPath, + photos.targetPath, ENTRIES.pinned.targetPath, ENTRIES.tallText.targetPath, hostedDocument.targetPath, @@ -80,8 +84,8 @@ testcase.launcherSearchOffline = async () => { // Create a file in Downloads, and a pinned and unpinned file in Drive. await setupAndWaitUntilReady( - 'downloads', [ENTRIES.tallText], - [ENTRIES.hello, ENTRIES.pinned, hostedDocument]); + 'downloads', [ENTRIES.tallText, photos], + [ENTRIES.hello, ENTRIES.pinned, hostedDocument, photos]); const result = JSON.parse(await sendTestMessage({ name: 'runLauncherSearch', @@ -89,6 +93,8 @@ })); chrome.test.assertEq( [ + photos.targetPath, + photos.targetPath, ENTRIES.pinned.targetPath, ENTRIES.tallText.targetPath, ],
diff --git a/ui/webui/resources/cr_components/chromeos/network/network_config.html b/ui/webui/resources/cr_components/chromeos/network/network_config.html index 7d44f7b..fcab8984 100644 --- a/ui/webui/resources/cr_components/chromeos/network/network_config.html +++ b/ui/webui/resources/cr_components/chromeos/network/network_config.html
@@ -1,9 +1,14 @@ <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_onc_types.html"> +<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html"> <link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html"> +<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_indicator.html"> +<link rel="import" href="chrome://resources/html/action_link.html"> +<link rel="import" href="chrome://resources/html/action_link_css.html"> <link rel="import" href="chrome://resources/html/i18n_behavior.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"> <link rel="import" href="network_config_input.html"> <link rel="import" href="network_config_select.html"> <link rel="import" href="network_config_toggle.html"> @@ -12,7 +17,7 @@ <dom-module id="network-config"> <template> - <style include="network-shared iron-flex"> + <style include="network-shared settings-shared action-link iron-flex"> </style> <!-- SSID (WiFi) --> @@ -174,6 +179,31 @@ </div> </template> + <!-- AutoConnect (WiFi) --> + <template is="dom-if" if="[[configCanAutoConnect_(type)]]" restamp> + <div class="property-box"> + <div id="autoConnectLabel" + class="start">[[i18n('networkAutoConnect')]]</div> + <template is="dom-if" + if="[[isAutoConnectEnforcedByPolicy_(globalPolicy)]]" restamp> + <cr-policy-indicator indicator-type="devicePolicy"> + </cr-policy-indicator> + </template> + <cr-toggle id="autoConnect" checked="{{autoConnect_}}" + disabled="[[autoConnectDisabled_(globalPolicy)]]" + aria-labeledby="autoConnectLabel"> + </cr-toggle> + </div> + </template> + + <!-- Hidden Network Warning --> + <template is="dom-if" if="{{autoConnect_}}" restamp> + <div> + <iron-icon icon="cr:warning"></iron-icon> + [[i18nAdvanced('hiddenNetworkWarning')]] + </div> + </template> + </template> <script src="network_config.js"></script> </dom-module>
diff --git a/ui/webui/resources/cr_components/chromeos/network/network_config.js b/ui/webui/resources/cr_components/chromeos/network/network_config.js index 9724299..14b525e 100644 --- a/ui/webui/resources/cr_components/chromeos/network/network_config.js +++ b/ui/webui/resources/cr_components/chromeos/network/network_config.js
@@ -175,6 +175,12 @@ }, /** + * Whether the device should automatically connect to the network. + * @private + */ + autoConnect_: Boolean, + + /** * Security value, used for Ethernet and Wifi and to detect when Security * changes. * @private @@ -380,6 +386,13 @@ this.focusFirstInput_(); }); } + if (this.type == CrOnc.Type.VPN || + (this.globalPolicy && + this.globalPolicy.AllowOnlyPolicyNetworksToConnect)) { + this.autoConnect_ = false; + } else { + this.autoConnect_ = true; + } this.onCertificateListsChanged_(); this.updateIsConfigured_(); this.setShareNetwork_(); @@ -407,12 +420,9 @@ const propertiesToSet = this.getPropertiesToSet_(); if (this.getSource_() == CrOnc.Source.NONE) { - // Set 'AutoConnect' to false for VPN or if prohibited by policy. - // Note: Do not set AutoConnect to true, the connection manager will do - // that on a successful connection (unless set to false here). - if (this.type == CrOnc.Type.VPN || - (this.globalPolicy && - this.globalPolicy.AllowOnlyPolicyNetworksToConnect)) { + if (!this.autoConnect_) { + // Note: Do not set AutoConnect to true, the connection manager will do + // that on a successful connection (unless set to false here). CrOnc.setTypeProperty(propertiesToSet, 'AutoConnect', false); } this.networkingPrivate.createNetwork( @@ -1276,6 +1286,32 @@ * @return {boolean} * @private */ + configCanAutoConnect_: function() { + // Only WiFi can choose whether or not to autoConnect. + return this.type == CrOnc.Type.WI_FI; + }, + + /** + * @return {boolean} + * @private + */ + autoConnectDisabled_: function() { + return this.isAutoConnectEnforcedByPolicy_(); + }, + + /** + * @return {boolean} + * @private + */ + isAutoConnectEnforcedByPolicy_: function() { + return !!this.globalPolicy && + !!this.globalPolicy.AllowOnlyPolicyNetworksToAutoconnect; + }, + + /** + * @return {boolean} + * @private + */ selectedUserCertHashIsValid_: function() { return !!this.selectedUserCertHash_ && this.selectedUserCertHash_ != NO_CERTS_HASH;