diff --git a/BUILD.gn b/BUILD.gn index 48b7396..97ce0d2 100644 --- a/BUILD.gn +++ b/BUILD.gn
@@ -681,6 +681,7 @@ "//chrome/installer/setup:setup_unittests", "//chrome_elf:chrome_elf_unittests", "//chrome_elf:dll_hash_main", + "//cloud_print:cloud_print_unittests", "//components/wifi:wifi_test", "//net:quic_client", "//net:quic_server",
diff --git a/DEPS b/DEPS index 7bbe07b..5c9c3797 100644 --- a/DEPS +++ b/DEPS
@@ -40,11 +40,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': 'b048e81c5c27fe6c6134eaf9ab96594e2eee0d1d', + 'skia_revision': '91db12d89c214235e24599f3ec18df2f952e99eb', # 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': 'e01db2c9ecb62bbdedb9c74c7e282bbaa8131eb3', + 'v8_revision': '6cddaff4ec73ce23ceec1e77829d12705dfed900', # 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. @@ -56,7 +56,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling build tools # and whatever else without interference from each other. - 'buildtools_revision': '102c16366d8b26e4a116d42f334860756d0e268e', + 'buildtools_revision': '64e38f0cebdde27aa0cfb405f330063582f9ac76', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -64,7 +64,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': '4bed2af0c049bf499dcdb1327a47d40b4c0db92d', + 'pdfium_revision': '7341149c634e0ab9a619898826440f6e952cf0aa', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling openmax_dl # and whatever else without interference from each other. @@ -96,7 +96,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': '627b0d9726b50a0cbd92ddb741d31ba5c184a2e5', + 'catapult_revision': '750e652668fcfb915d77007f14c5b6befb3a704e', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other.
diff --git a/WATCHLISTS b/WATCHLISTS index a90202e0..a278cd03 100644 --- a/WATCHLISTS +++ b/WATCHLISTS
@@ -578,7 +578,7 @@ 'filepath': 'content/common/sandbox.*linux.cc', }, 'mac': { - 'filepath': '(_|/)(cocoa|mac)(_|\.)|/(cocoa|mac)/|\.mm?$', + 'filepath': '(_|/)(cocoa|mac)(_|\.)|/(cocoa|mac)/|^((?!ios\/).)*\.mm?$', }, 'manifest': { 'filepath': 'content/(browser|renderer)/manifest/'\
diff --git a/base/feature_list.cc b/base/feature_list.cc index 89b105d..c2f268b 100644 --- a/base/feature_list.cc +++ b/base/feature_list.cc
@@ -12,6 +12,7 @@ #include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/metrics/field_trial.h" +#include "base/pickle.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" @@ -27,6 +28,42 @@ // Tracks whether the FeatureList instance was initialized via an accessor. bool g_initialized_from_accessor = false; +const uint32_t kFeatureType = 0x06567CA6 + 1; // SHA1(FeatureEntry) v1 + +// An allocator entry for a feature in shared memory. The FeatureEntry is +// followed by a base::Pickle object that contains the feature and trial name. +// Any changes to this structure requires a bump in kFeatureType defined above. +struct FeatureEntry { + // Expected size for 32/64-bit check. + static constexpr size_t kExpectedInstanceSize = 8; + + // Specifies whether a feature override enables or disables the feature. Same + // values as the OverrideState enum in feature_list.h + uint32_t override_state; + + // Size of the pickled structure, NOT the total size of this entry. + uint32_t pickle_size; + + // Reads the feature and trial name from the pickle. Calling this is only + // valid on an initialized entry that's in shared memory. + bool GetFeatureAndTrialName(StringPiece* feature_name, + StringPiece* trial_name) const { + const char* src = + reinterpret_cast<const char*>(this) + sizeof(FeatureEntry); + + Pickle pickle(src, pickle_size); + PickleIterator pickle_iter(pickle); + + if (!pickle_iter.ReadStringPiece(feature_name)) + return false; + + // Return true because we are not guaranteed to have a trial name anyways. + auto sink = pickle_iter.ReadStringPiece(trial_name); + ALLOW_UNUSED_LOCAL(sink); + return true; + } +}; + // Some characters are not allowed to appear in feature names or the associated // field trial names, as they are used as special characters for command-line // serialization. This function checks that the strings are ASCII (since they @@ -56,6 +93,31 @@ initialized_from_command_line_ = true; } +void FeatureList::InitializeFromSharedMemory( + PersistentMemoryAllocator* allocator) { + DCHECK(!initialized_); + + PersistentMemoryAllocator::Iterator iter(allocator); + + PersistentMemoryAllocator::Reference ref; + while ((ref = iter.GetNextOfType(kFeatureType)) != + PersistentMemoryAllocator::kReferenceNull) { + const FeatureEntry* entry = + allocator->GetAsObject<const FeatureEntry>(ref, kFeatureType); + + OverrideState override_state = + static_cast<OverrideState>(entry->override_state); + + StringPiece feature_name; + StringPiece trial_name; + if (!entry->GetFeatureAndTrialName(&feature_name, &trial_name)) + continue; + + FieldTrial* trial = FieldTrialList::Find(trial_name.as_string()); + RegisterOverride(feature_name, override_state, trial); + } +} + bool FeatureList::IsFeatureOverriddenFromCommandLine( const std::string& feature_name, OverrideState state) const { @@ -98,6 +160,33 @@ RegisterOverride(feature_name, override_state, field_trial); } +void FeatureList::AddFeaturesToAllocator(PersistentMemoryAllocator* allocator) { + DCHECK(initialized_); + + for (const auto& override : overrides_) { + Pickle pickle; + pickle.WriteString(override.first); + if (override.second.field_trial) + pickle.WriteString(override.second.field_trial->trial_name()); + + size_t total_size = sizeof(FeatureEntry) + pickle.size(); + PersistentMemoryAllocator::Reference ref = + allocator->Allocate(total_size, kFeatureType); + if (!ref) + return; + + FeatureEntry* entry = + allocator->GetAsObject<FeatureEntry>(ref, kFeatureType); + entry->override_state = override.second.overridden_state; + entry->pickle_size = pickle.size(); + + char* dst = reinterpret_cast<char*>(entry) + sizeof(FeatureEntry); + memcpy(dst, pickle.data(), pickle.size()); + + allocator->MakeIterable(ref); + } +} + void FeatureList::GetFeatureOverrides(std::string* enable_overrides, std::string* disable_overrides) { DCHECK(initialized_);
diff --git a/base/feature_list.h b/base/feature_list.h index 80209ba..daedd73 100644 --- a/base/feature_list.h +++ b/base/feature_list.h
@@ -13,6 +13,7 @@ #include "base/base_export.h" #include "base/gtest_prod_util.h" #include "base/macros.h" +#include "base/metrics/persistent_memory_allocator.h" #include "base/strings/string_piece.h" #include "base/synchronization/lock.h" @@ -92,6 +93,11 @@ void InitializeFromCommandLine(const std::string& enable_features, const std::string& disable_features); + // Initializes feature overrides through the field trial allocator, which + // we're using to store the feature names, their override state, and the name + // of the associated field trial. + void InitializeFromSharedMemory(PersistentMemoryAllocator* allocator); + // Specifies whether a feature override enables or disables the feature. enum OverrideState { OVERRIDE_USE_DEFAULT, @@ -124,6 +130,9 @@ OverrideState override_state, FieldTrial* field_trial); + // Loops through feature overrides and serializes them all into |allocator|. + void AddFeaturesToAllocator(PersistentMemoryAllocator* allocator); + // Returns comma-separated lists of feature names (in the same format that is // accepted by InitializeFromCommandLine()) corresponding to features that // have been overridden - either through command-line or via FieldTrials. For @@ -180,6 +189,10 @@ private: FRIEND_TEST_ALL_PREFIXES(FeatureListTest, CheckFeatureIdentity); + FRIEND_TEST_ALL_PREFIXES(FeatureListTest, + StoreAndRetrieveFeaturesFromSharedMemory); + FRIEND_TEST_ALL_PREFIXES(FeatureListTest, + StoreAndRetrieveAssociatedFeaturesFromSharedMemory); struct OverrideEntry { // The overridden enable (on/off) state of the feature.
diff --git a/base/feature_list_unittest.cc b/base/feature_list_unittest.cc index 9d1dcb7..189e974 100644 --- a/base/feature_list_unittest.cc +++ b/base/feature_list_unittest.cc
@@ -13,6 +13,7 @@ #include "base/macros.h" #include "base/memory/ptr_util.h" #include "base/metrics/field_trial.h" +#include "base/metrics/persistent_memory_allocator.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "testing/gtest/include/gtest/gtest.h" @@ -468,4 +469,68 @@ EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault)); } +TEST_F(FeatureListTest, StoreAndRetrieveFeaturesFromSharedMemory) { + std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList); + + // Create some overrides. + feature_list->RegisterOverride(kFeatureOffByDefaultName, + FeatureList::OVERRIDE_ENABLE_FEATURE, nullptr); + feature_list->RegisterOverride( + kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE, nullptr); + feature_list->FinalizeInitialization(); + + // Create an allocator and store the overrides. + std::unique_ptr<SharedMemory> shm(new SharedMemory()); + shm->CreateAndMapAnonymous(4 << 10); + SharedPersistentMemoryAllocator allocator(std::move(shm), 1, "", false); + feature_list->AddFeaturesToAllocator(&allocator); + + std::unique_ptr<base::FeatureList> feature_list2(new base::FeatureList); + + // Check that the new feature list is empty. + EXPECT_FALSE(feature_list2->IsFeatureOverriddenFromCommandLine( + kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE)); + EXPECT_FALSE(feature_list2->IsFeatureOverriddenFromCommandLine( + kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE)); + + feature_list2->InitializeFromSharedMemory(&allocator); + // Check that the new feature list now has 2 overrides. + EXPECT_TRUE(feature_list2->IsFeatureOverriddenFromCommandLine( + kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE)); + EXPECT_TRUE(feature_list2->IsFeatureOverriddenFromCommandLine( + kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE)); +} + +TEST_F(FeatureListTest, StoreAndRetrieveAssociatedFeaturesFromSharedMemory) { + FieldTrialList field_trial_list(nullptr); + std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList); + + // Create some overrides. + FieldTrial* trial1 = FieldTrialList::CreateFieldTrial("TrialExample1", "A"); + FieldTrial* trial2 = FieldTrialList::CreateFieldTrial("TrialExample2", "B"); + feature_list->RegisterFieldTrialOverride( + kFeatureOnByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial1); + feature_list->RegisterFieldTrialOverride( + kFeatureOffByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial2); + feature_list->FinalizeInitialization(); + + // Create an allocator and store the overrides. + std::unique_ptr<SharedMemory> shm(new SharedMemory()); + shm->CreateAndMapAnonymous(4 << 10); + SharedPersistentMemoryAllocator allocator(std::move(shm), 1, "", false); + feature_list->AddFeaturesToAllocator(&allocator); + + std::unique_ptr<base::FeatureList> feature_list2(new base::FeatureList); + feature_list2->InitializeFromSharedMemory(&allocator); + feature_list2->FinalizeInitialization(); + + // Check that the field trials are still associated. + FieldTrial* associated_trial1 = + feature_list2->GetAssociatedFieldTrial(kFeatureOnByDefault); + FieldTrial* associated_trial2 = + feature_list2->GetAssociatedFieldTrial(kFeatureOffByDefault); + EXPECT_EQ(associated_trial1, trial1); + EXPECT_EQ(associated_trial2, trial2); +} + } // namespace base
diff --git a/base/metrics/field_trial.cc b/base/metrics/field_trial.cc index f11ef35..505bba24 100644 --- a/base/metrics/field_trial.cc +++ b/base/metrics/field_trial.cc
@@ -10,7 +10,6 @@ #include "base/base_switches.h" #include "base/build_time.h" #include "base/command_line.h" -#include "base/feature_list.h" #include "base/logging.h" #include "base/metrics/field_trial_param_associator.h" #include "base/pickle.h" @@ -49,6 +48,10 @@ // for now while the implementation is fleshed out (e.g. data format, single // shared memory segment). See https://codereview.chromium.org/2365273004/ and // crbug.com/653874 +// The browser is the only process that has write access to the shared memory. +// This is safe from race conditions because MakeIterable is a release operation +// and GetNextOfType is an acquire operation, so memory writes before +// MakeIterable happen before memory reads after GetNextOfType. const bool kUseSharedMemoryForFieldTrials = true; // Constants for the field trial allocator. @@ -248,7 +251,19 @@ return true; } -void AddForceFieldTrialsFlag(CommandLine* cmd_line) { +void AddFeatureAndFieldTrialFlags(const char* enable_features_switch, + const char* disable_features_switch, + CommandLine* cmd_line) { + std::string enabled_features; + std::string disabled_features; + FeatureList::GetInstance()->GetFeatureOverrides(&enabled_features, + &disabled_features); + + if (!enabled_features.empty()) + cmd_line->AppendSwitchASCII(enable_features_switch, enabled_features); + if (!disabled_features.empty()) + cmd_line->AppendSwitchASCII(disable_features_switch, disabled_features); + std::string field_trial_states; FieldTrialList::AllStatesToString(&field_trial_states); if (!field_trial_states.empty()) { @@ -805,6 +820,24 @@ } } +// static +void FieldTrialList::CreateFeaturesFromCommandLine( + const base::CommandLine& command_line, + const char* enable_features_switch, + const char* disable_features_switch, + FeatureList* feature_list) { + // Fallback to command line if not using shared memory. + if (!kUseSharedMemoryForFieldTrials || + !global_->field_trial_allocator_.get()) { + return feature_list->InitializeFromCommandLine( + command_line.GetSwitchValueASCII(enable_features_switch), + command_line.GetSwitchValueASCII(disable_features_switch)); + } + + feature_list->InitializeFromSharedMemory( + global_->field_trial_allocator_.get()); +} + #if defined(POSIX_WITH_ZYGOTE) // static bool FieldTrialList::CreateTrialsFromDescriptor(int fd_key) { @@ -854,12 +887,19 @@ // static void FieldTrialList::CopyFieldTrialStateToFlags( const char* field_trial_handle_switch, + const char* enable_features_switch, + const char* disable_features_switch, CommandLine* cmd_line) { // TODO(lawrencewu): Ideally, having the global would be guaranteed. However, // content browser tests currently don't create a FieldTrialList because they // don't run ChromeBrowserMainParts code where it's done for Chrome. - if (!global_) + // Some tests depend on the enable and disable features flag switch, though, + // so we can still add those even though AllStatesToString() will be a no-op. + if (!global_) { + AddFeatureAndFieldTrialFlags(enable_features_switch, + disable_features_switch, cmd_line); return; + } #if defined(OS_WIN) || defined(POSIX_WITH_ZYGOTE) // Use shared memory to pass the state if the feature is enabled, otherwise @@ -869,7 +909,8 @@ // If the readonly handle didn't get duplicated properly, then fallback to // original behavior. if (global_->readonly_allocator_handle_ == kInvalidPlatformFile) { - AddForceFieldTrialsFlag(cmd_line); + AddFeatureAndFieldTrialFlags(enable_features_switch, + disable_features_switch, cmd_line); return; } @@ -895,7 +936,8 @@ } #endif - AddForceFieldTrialsFlag(cmd_line); + AddFeatureAndFieldTrialFlags(enable_features_switch, disable_features_switch, + cmd_line); } // static @@ -1171,6 +1213,10 @@ AddToAllocatorWhileLocked(registered.second); } + // Add all existing features. + FeatureList::GetInstance()->AddFeaturesToAllocator( + global_->field_trial_allocator_.get()); + #if defined(OS_WIN) || defined(POSIX_WITH_ZYGOTE) // Set |readonly_allocator_handle_| so we can pass it to be inherited and // via the command line.
diff --git a/base/metrics/field_trial.h b/base/metrics/field_trial.h index 01bb35c..7fedb37 100644 --- a/base/metrics/field_trial.h +++ b/base/metrics/field_trial.h
@@ -65,6 +65,7 @@ #include "base/base_export.h" #include "base/command_line.h" +#include "base/feature_list.h" #include "base/files/file.h" #include "base/gtest_prod_util.h" #include "base/macros.h" @@ -508,6 +509,14 @@ const char* field_trial_handle_switch, int fd_key); + // Creates base::Feature overrides from the command line by first trying to + // use shared memory and then falling back to the command line if it fails. + static void CreateFeaturesFromCommandLine( + const base::CommandLine& command_line, + const char* enable_features_switch, + const char* disable_features_switch, + FeatureList* feature_list); + #if defined(OS_WIN) // On Windows, we need to explicitly pass down any handles to be inherited. // This function adds the shared memory handle to field trial state to the @@ -527,6 +536,8 @@ // Needs the |field_trial_handle_switch| argument to be passed in since base/ // can't depend on content/. static void CopyFieldTrialStateToFlags(const char* field_trial_handle_switch, + const char* enable_features_switch, + const char* disable_features_switch, base::CommandLine* cmd_line); // Create a FieldTrial with the given |name| and using 100% probability for
diff --git a/base/metrics/field_trial_unittest.cc b/base/metrics/field_trial_unittest.cc index 6c07026..05776a11 100644 --- a/base/metrics/field_trial_unittest.cc +++ b/base/metrics/field_trial_unittest.cc
@@ -19,6 +19,7 @@ #include "base/strings/stringprintf.h" #include "base/test/gtest_util.h" #include "base/test/mock_entropy_provider.h" +#include "base/test/scoped_feature_list.h" #include "testing/gtest/include/gtest/gtest.h" namespace base { @@ -1145,15 +1146,21 @@ base::FilePath test_file_path = base::FilePath(FILE_PATH_LITERAL("Program")); base::CommandLine cmd_line = base::CommandLine(test_file_path); const char field_trial_handle[] = "test-field-trial-handle"; + const char enable_features_switch[] = "test-enable-features"; + const char disable_features_switch[] = "test-disable-features"; - base::FieldTrialList::CopyFieldTrialStateToFlags(field_trial_handle, - &cmd_line); + base::FieldTrialList::CopyFieldTrialStateToFlags( + field_trial_handle, enable_features_switch, disable_features_switch, + &cmd_line); EXPECT_TRUE(cmd_line.HasSwitch(field_trial_handle) || cmd_line.HasSwitch(switches::kForceFieldTrials)); } #endif TEST(FieldTrialListTest, InstantiateAllocator) { + test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.Init(); + FieldTrialList field_trial_list(nullptr); FieldTrialList::CreateFieldTrial("Trial1", "Group1"); @@ -1176,6 +1183,9 @@ // Scoping the first FieldTrialList, as we need another one to test that it // matches. { + test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.Init(); + FieldTrialList field_trial_list(nullptr); FieldTrialList::CreateFieldTrial("Trial1", "Group1"); FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded(); @@ -1198,6 +1208,9 @@ constexpr char kTrialName[] = "trial"; base::SharedMemoryHandle handle; { + test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.Init(); + // Create a simulated trial and a real trial and call group() on them, which // should only add the real trial to the field trial allocator. FieldTrialList field_trial_list(nullptr); @@ -1230,6 +1243,9 @@ } TEST(FieldTrialListTest, AssociateFieldTrialParams) { + test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.Init(); + std::string trial_name("Trial1"); std::string group_name("Group1"); @@ -1266,6 +1282,9 @@ base::SharedMemoryHandle handle; { + test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.Init(); + // Create a field trial with some params. FieldTrialList field_trial_list(nullptr); FieldTrial* trial =
diff --git a/base/numerics/safe_conversions.h b/base/numerics/safe_conversions.h index 21fe3a80..98086039 100644 --- a/base/numerics/safe_conversions.h +++ b/base/numerics/safe_conversions.h
@@ -55,19 +55,17 @@ // Convenience function for determining if a numeric value is negative without // throwing compiler warnings on: unsigned(value) < 0. -template <typename T> -constexpr typename std::enable_if<std::numeric_limits<T>::is_signed, bool>::type -IsValueNegative(T value) { - static_assert(std::numeric_limits<T>::is_specialized, - "Argument must be numeric."); +template <typename T, + typename std::enable_if<std::is_signed<T>::value>::type* = nullptr> +constexpr bool IsValueNegative(T value) { + static_assert(std::is_arithmetic<T>::value, "Argument must be numeric."); return value < 0; } -template <typename T> -constexpr typename std::enable_if<!std::numeric_limits<T>::is_signed, - bool>::type IsValueNegative(T) { - static_assert(std::numeric_limits<T>::is_specialized, - "Argument must be numeric."); +template <typename T, + typename std::enable_if<!std::is_signed<T>::value>::type* = nullptr> +constexpr bool IsValueNegative(T) { + static_assert(std::is_arithmetic<T>::value, "Argument must be numeric."); return false; } @@ -117,7 +115,7 @@ return constraint == RANGE_VALID ? static_cast<Dst>(value) : (constraint == RANGE_UNDERFLOW - ? std::numeric_limits<Dst>::min() + ? std::numeric_limits<Dst>::lowest() : (constraint == RANGE_OVERFLOW ? std::numeric_limits<Dst>::max() : NaNHandler::template HandleFailure<Dst>())); @@ -132,7 +130,7 @@ typename Src> constexpr Dst saturated_cast(Src value) { using SrcType = typename UnderlyingType<Src>::type; - return std::numeric_limits<Dst>::is_iec559 + return std::is_floating_point<Dst>::value ? static_cast<Dst>( static_cast<SrcType>(value)) // Floating point optimization. : internal::saturated_cast_impl<Dst, NaNHandler>( @@ -147,8 +145,7 @@ constexpr Dst strict_cast(Src value) { using SrcType = typename UnderlyingType<Src>::type; static_assert(UnderlyingType<Src>::is_numeric, "Argument must be numeric."); - static_assert(std::numeric_limits<Dst>::is_specialized, - "Result must be numeric."); + static_assert(std::is_arithmetic<Dst>::value, "Result must be numeric."); // If you got here from a compiler error, it's because you tried to assign // from a source type to a destination type that has insufficient range. @@ -193,7 +190,7 @@ template <typename T> class StrictNumeric { public: - typedef T type; + using type = T; constexpr StrictNumeric() : value_(0) {} @@ -269,8 +266,8 @@ using internal::StrictNumeric; using internal::MakeStrictNum; -// Explicitly make a shorter size_t typedef for convenience. -typedef StrictNumeric<size_t> SizeT; +// Explicitly make a shorter size_t alias for convenience. +using SizeT = StrictNumeric<size_t>; } // namespace base
diff --git a/base/numerics/safe_conversions_impl.h b/base/numerics/safe_conversions_impl.h index be9eaa1..ef5adf0 100644 --- a/base/numerics/safe_conversions_impl.h +++ b/base/numerics/safe_conversions_impl.h
@@ -16,14 +16,20 @@ namespace internal { // The std library doesn't provide a binary max_exponent for integers, however -// we can compute one by adding one to the number of non-sign bits. This allows -// for accurate range comparisons between floating point and integer types. +// we can compute an analog using std::numeric_limits<>::digits. template <typename NumericType> struct MaxExponent { - static const int value = std::numeric_limits<NumericType>::is_iec559 + static const int value = std::is_floating_point<NumericType>::value ? std::numeric_limits<NumericType>::max_exponent - : (sizeof(NumericType) * CHAR_BIT + 1 - - std::numeric_limits<NumericType>::is_signed); + : std::numeric_limits<NumericType>::digits + 1; +}; + +// The number of bits (including the sign) in an integer. Eliminates sizeof +// hacks. +template <typename NumericType> +struct IntegerBitsPlusSign { + static const int value = std::numeric_limits<NumericType>::digits + + std::is_signed<NumericType>::value; }; enum IntegerRepresentation { @@ -33,7 +39,7 @@ // A range for a given nunmeric Src type is contained for a given numeric Dst // type if both numeric_limits<Src>::max() <= numeric_limits<Dst>::max() and -// numeric_limits<Src>::min() >= numeric_limits<Dst>::min() are true. +// numeric_limits<Src>::lowest() >= numeric_limits<Dst>::lowest() are true. // We implement this as template specializations rather than simple static // comparisons to ensure type correctness in our comparisons. enum NumericRangeRepresentation { @@ -44,16 +50,14 @@ // Helper templates to statically determine if our destination type can contain // maximum and minimum values represented by the source type. -template < - typename Dst, - typename Src, - IntegerRepresentation DstSign = std::numeric_limits<Dst>::is_signed - ? INTEGER_REPRESENTATION_SIGNED - : INTEGER_REPRESENTATION_UNSIGNED, - IntegerRepresentation SrcSign = - std::numeric_limits<Src>::is_signed - ? INTEGER_REPRESENTATION_SIGNED - : INTEGER_REPRESENTATION_UNSIGNED > +template <typename Dst, + typename Src, + IntegerRepresentation DstSign = std::is_signed<Dst>::value + ? INTEGER_REPRESENTATION_SIGNED + : INTEGER_REPRESENTATION_UNSIGNED, + IntegerRepresentation SrcSign = std::is_signed<Src>::value + ? INTEGER_REPRESENTATION_SIGNED + : INTEGER_REPRESENTATION_UNSIGNED> struct StaticDstRangeRelationToSrcRange; // Same sign: Dst is guaranteed to contain Src only if its range is equal or @@ -135,8 +139,8 @@ // such that the resulting maximum is represented exactly as a floating point. template <typename Dst, typename Src> struct NarrowingRange { - typedef typename std::numeric_limits<Src> SrcLimits; - typedef typename std::numeric_limits<Dst> DstLimits; + using SrcLimits = typename std::numeric_limits<Src>; + using DstLimits = typename std::numeric_limits<Dst>; // The following logic avoids warnings where the max function is // instantiated with invalid values for a bit shift (even though // such a function can never be called). @@ -154,23 +158,19 @@ return DstLimits::max() - static_cast<Dst>((UINTMAX_C(1) << shift) - 1); } - static constexpr Dst min() { - return std::numeric_limits<Dst>::is_iec559 ? -DstLimits::max() - : DstLimits::min(); - } + static constexpr Dst lowest() { return DstLimits::lowest(); } }; -template < - typename Dst, - typename Src, - IntegerRepresentation DstSign = std::numeric_limits<Dst>::is_signed - ? INTEGER_REPRESENTATION_SIGNED - : INTEGER_REPRESENTATION_UNSIGNED, - IntegerRepresentation SrcSign = std::numeric_limits<Src>::is_signed - ? INTEGER_REPRESENTATION_SIGNED - : INTEGER_REPRESENTATION_UNSIGNED, - NumericRangeRepresentation DstRange = - StaticDstRangeRelationToSrcRange<Dst, Src>::value > +template <typename Dst, + typename Src, + IntegerRepresentation DstSign = std::is_signed<Dst>::value + ? INTEGER_REPRESENTATION_SIGNED + : INTEGER_REPRESENTATION_UNSIGNED, + IntegerRepresentation SrcSign = std::is_signed<Src>::value + ? INTEGER_REPRESENTATION_SIGNED + : INTEGER_REPRESENTATION_UNSIGNED, + NumericRangeRepresentation DstRange = + StaticDstRangeRelationToSrcRange<Dst, Src>::value> struct DstRangeRelationToSrcRangeImpl; // The following templates are for ranges that must be verified at runtime. We @@ -200,7 +200,7 @@ NUMERIC_RANGE_NOT_CONTAINED> { static constexpr RangeConstraint Check(Src value) { return GetRangeConstraint((value <= NarrowingRange<Dst, Src>::max()), - (value >= NarrowingRange<Dst, Src>::min())); + (value >= NarrowingRange<Dst, Src>::lowest())); } }; @@ -224,7 +224,7 @@ INTEGER_REPRESENTATION_UNSIGNED, NUMERIC_RANGE_NOT_CONTAINED> { static constexpr RangeConstraint Check(Src value) { - return sizeof(Dst) > sizeof(Src) + return IntegerBitsPlusSign<Dst>::value > IntegerBitsPlusSign<Src>::value ? RANGE_VALID : GetRangeConstraint( value <= static_cast<Src>(NarrowingRange<Dst, Src>::max()), @@ -251,83 +251,48 @@ template <typename Dst, typename Src> constexpr RangeConstraint DstRangeRelationToSrcRange(Src value) { - static_assert(std::numeric_limits<Src>::is_specialized, - "Argument must be numeric."); - static_assert(std::numeric_limits<Dst>::is_specialized, - "Result must be numeric."); + static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric."); + static_assert(std::is_arithmetic<Dst>::value, "Result must be numeric."); return DstRangeRelationToSrcRangeImpl<Dst, Src>::Check(value); } // Integer promotion templates used by the portable checked integer arithmetic. template <size_t Size, bool IsSigned> -struct IntegerForSizeAndSign; -template <> -struct IntegerForSizeAndSign<1, true> { - typedef int8_t type; -}; -template <> -struct IntegerForSizeAndSign<1, false> { - typedef uint8_t type; -}; -template <> -struct IntegerForSizeAndSign<2, true> { - typedef int16_t type; -}; -template <> -struct IntegerForSizeAndSign<2, false> { - typedef uint16_t type; -}; -template <> -struct IntegerForSizeAndSign<4, true> { - typedef int32_t type; -}; -template <> -struct IntegerForSizeAndSign<4, false> { - typedef uint32_t type; -}; -template <> -struct IntegerForSizeAndSign<8, true> { - typedef int64_t type; -}; -template <> -struct IntegerForSizeAndSign<8, false> { - typedef uint64_t type; - static_assert(sizeof(uintmax_t) == 8, - "Max integer size not supported for this toolchain."); -}; +struct IntegerForDigitsAndSign; + +#define INTEGER_FOR_DIGITS_AND_SIGN(I) \ + template <> \ + struct IntegerForDigitsAndSign<IntegerBitsPlusSign<I>::value, \ + std::is_signed<I>::value> { \ + using type = I; \ + } + +INTEGER_FOR_DIGITS_AND_SIGN(int8_t); +INTEGER_FOR_DIGITS_AND_SIGN(uint8_t); +INTEGER_FOR_DIGITS_AND_SIGN(int16_t); +INTEGER_FOR_DIGITS_AND_SIGN(uint16_t); +INTEGER_FOR_DIGITS_AND_SIGN(int32_t); +INTEGER_FOR_DIGITS_AND_SIGN(uint32_t); +INTEGER_FOR_DIGITS_AND_SIGN(int64_t); +INTEGER_FOR_DIGITS_AND_SIGN(uint64_t); +#undef INTEGER_FOR_DIGITS_AND_SIGN // WARNING: We have no IntegerForSizeAndSign<16, *>. If we ever add one to // support 128-bit math, then the ArithmeticPromotion template below will need // to be updated (or more likely replaced with a decltype expression). +static_assert(IntegerBitsPlusSign<intmax_t>::value == 64, + "Max integer size not supported for this toolchain."); -template <typename Integer> -struct UnsignedIntegerForSize { - typedef typename std::enable_if< - std::numeric_limits<Integer>::is_integer, - typename IntegerForSizeAndSign<sizeof(Integer), false>::type>::type type; -}; - -template <typename Integer> -struct SignedIntegerForSize { - typedef typename std::enable_if< - std::numeric_limits<Integer>::is_integer, - typename IntegerForSizeAndSign<sizeof(Integer), true>::type>::type type; -}; - -template <typename Integer> +template <typename Integer, bool IsSigned = std::is_signed<Integer>::value> struct TwiceWiderInteger { - typedef typename std::enable_if< - std::numeric_limits<Integer>::is_integer, - typename IntegerForSizeAndSign< - sizeof(Integer) * 2, - std::numeric_limits<Integer>::is_signed>::type>::type type; + using type = + typename IntegerForDigitsAndSign<IntegerBitsPlusSign<Integer>::value * 2, + IsSigned>::type; }; template <typename Integer> struct PositionOfSignBit { - static const typename std::enable_if<std::numeric_limits<Integer>::is_integer, - size_t>::type value = - CHAR_BIT * sizeof(Integer) - 1; + static const size_t value = IntegerBitsPlusSign<Integer>::value - 1; }; enum ArithmeticPromotionCategory { @@ -382,20 +347,20 @@ }; // Determines the type that is best able to represent an arithmetic result. -template <typename Lhs, - typename Rhs = Lhs, - bool is_intmax_type = - std::is_integral< - typename MaxExponentPromotion<Lhs, Rhs>::type>::value && - sizeof(typename MaxExponentPromotion<Lhs, Rhs>::type) == - sizeof(intmax_t), - bool is_max_exponent = - StaticDstRangeRelationToSrcRange< - typename MaxExponentPromotion<Lhs, Rhs>::type, - Lhs>::value == - NUMERIC_RANGE_CONTAINED&& StaticDstRangeRelationToSrcRange< - typename MaxExponentPromotion<Lhs, Rhs>::type, - Rhs>::value == NUMERIC_RANGE_CONTAINED> +template < + typename Lhs, + typename Rhs = Lhs, + bool is_intmax_type = + std::is_integral<typename MaxExponentPromotion<Lhs, Rhs>::type>::value&& + IntegerBitsPlusSign<typename MaxExponentPromotion<Lhs, Rhs>::type>:: + value == IntegerBitsPlusSign<intmax_t>::value, + bool is_max_exponent = + StaticDstRangeRelationToSrcRange< + typename MaxExponentPromotion<Lhs, Rhs>::type, + Lhs>::value == + NUMERIC_RANGE_CONTAINED&& StaticDstRangeRelationToSrcRange< + typename MaxExponentPromotion<Lhs, Rhs>::type, + Rhs>::value == NUMERIC_RANGE_CONTAINED> struct BigEnoughPromotion; // The side with the max exponent is big enough. @@ -408,9 +373,10 @@ // We can use a twice wider type to fit. template <typename Lhs, typename Rhs> struct BigEnoughPromotion<Lhs, Rhs, false, false> { - using type = typename IntegerForSizeAndSign< - sizeof(typename MaxExponentPromotion<Lhs, Rhs>::type) * 2, - std::is_signed<Lhs>::value || std::is_signed<Rhs>::value>::type; + using type = + typename TwiceWiderInteger<typename MaxExponentPromotion<Lhs, Rhs>::type, + std::is_signed<Lhs>::value || + std::is_signed<Rhs>::value>::type; static const bool is_contained = true; }; @@ -427,13 +393,14 @@ // the source. template <typename T, typename Lhs, typename Rhs> struct IsIntegerArithmeticSafe { - static const bool value = !std::numeric_limits<T>::is_iec559 && - StaticDstRangeRelationToSrcRange<T, Lhs>::value == - NUMERIC_RANGE_CONTAINED && - sizeof(T) >= (2 * sizeof(Lhs)) && - StaticDstRangeRelationToSrcRange<T, Rhs>::value != - NUMERIC_RANGE_CONTAINED && - sizeof(T) >= (2 * sizeof(Rhs)); + static const bool value = + !std::is_floating_point<T>::value && + StaticDstRangeRelationToSrcRange<T, Lhs>::value == + NUMERIC_RANGE_CONTAINED && + IntegerBitsPlusSign<T>::value >= (2 * IntegerBitsPlusSign<Lhs>::value) && + StaticDstRangeRelationToSrcRange<T, Rhs>::value != + NUMERIC_RANGE_CONTAINED && + IntegerBitsPlusSign<T>::value >= (2 * IntegerBitsPlusSign<Rhs>::value); }; // This hacks around libstdc++ 4.6 missing stuff in type_traits.
diff --git a/base/numerics/safe_math.h b/base/numerics/safe_math.h index 9b2177f..32f0dfdd 100644 --- a/base/numerics/safe_math.h +++ b/base/numerics/safe_math.h
@@ -97,7 +97,7 @@ "CheckedNumeric<T>: T must be a numeric type."); public: - typedef T type; + using type = T; constexpr CheckedNumeric() {} @@ -114,8 +114,7 @@ template <typename Src> constexpr CheckedNumeric(Src value) // NOLINT(runtime/explicit) : state_(value) { - static_assert(std::numeric_limits<Src>::is_specialized, - "Argument must be numeric."); + static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric."); } // This is not an explicit constructor because we want a seamless conversion @@ -208,7 +207,7 @@ CheckedNumeric operator-() const { // Negation is always valid for floating point. T value = 0; - bool is_valid = (std::numeric_limits<T>::is_iec559 || IsValid()) && + bool is_valid = (std::is_floating_point<T>::value || IsValid()) && CheckedNeg(state_.value(), &value); return CheckedNumeric<T>(value, is_valid); } @@ -223,7 +222,7 @@ CheckedNumeric Abs() const { // Absolute value is always valid for floating point. T value = 0; - bool is_valid = (std::numeric_limits<T>::is_iec559 || IsValid()) && + bool is_valid = (std::is_floating_point<T>::value || IsValid()) && CheckedAbs(state_.value(), &value); return CheckedNumeric<T>(value, is_valid); } @@ -387,10 +386,8 @@ typename R, typename... Args> struct ResultType { - // The typedef was required here because MSVC fails to compile with "using". - typedef - typename ResultType<M, typename ResultType<M, L, R>::type, Args...>::type - type; + using type = + typename ResultType<M, typename ResultType<M, L, R>::type, Args...>::type; }; // Convience wrapper to return a new CheckedNumeric from the provided arithmetic
diff --git a/base/numerics/safe_math_impl.h b/base/numerics/safe_math_impl.h index 4b9877a..679cfa4 100644 --- a/base/numerics/safe_math_impl.h +++ b/base/numerics/safe_math_impl.h
@@ -28,18 +28,18 @@ // However, there is no corresponding implementation of e.g. SafeUnsignedAbs, // so the float versions will not compile. template <typename Numeric, - bool IsInteger = std::numeric_limits<Numeric>::is_integer, - bool IsFloat = std::numeric_limits<Numeric>::is_iec559> + bool IsInteger = std::is_integral<Numeric>::value, + bool IsFloat = std::is_floating_point<Numeric>::value> struct UnsignedOrFloatForSize; template <typename Numeric> struct UnsignedOrFloatForSize<Numeric, true, false> { - typedef typename UnsignedIntegerForSize<Numeric>::type type; + using type = typename std::make_unsigned<Numeric>::type; }; template <typename Numeric> struct UnsignedOrFloatForSize<Numeric, false, true> { - typedef Numeric type; + using type = Numeric; }; // Helper templates for integer manipulations. @@ -47,7 +47,7 @@ template <typename T> constexpr bool HasSignBit(T x) { // Cast to unsigned since right shift on signed is undefined. - return !!(static_cast<typename UnsignedIntegerForSize<T>::type>(x) >> + return !!(static_cast<typename std::make_unsigned<T>::type>(x) >> PositionOfSignBit<T>::value); } @@ -66,23 +66,19 @@ #define USE_OVERFLOW_BUILTINS (0) #endif -// Here are the actual portable checked integer math implementations. -// TODO(jschuh): Break this code out from the enable_if pattern and find a clean -// way to coalesce things into the CheckedNumericState specializations below. - -template <typename T> -typename std::enable_if<std::numeric_limits<T>::is_integer, bool>::type -CheckedAddImpl(T x, T y, T* result) { +template <typename T, + typename std::enable_if<std::is_integral<T>::value>::type* = nullptr> +bool CheckedAddImpl(T x, T y, T* result) { // Since the value of x+y is undefined if we have a signed type, we compute // it using the unsigned type of the same size. - typedef typename UnsignedIntegerForSize<T>::type UnsignedDst; + using UnsignedDst = typename std::make_unsigned<T>::type; UnsignedDst ux = static_cast<UnsignedDst>(x); UnsignedDst uy = static_cast<UnsignedDst>(y); UnsignedDst uresult = static_cast<UnsignedDst>(ux + uy); *result = static_cast<T>(uresult); // Addition is valid if the sign of (x + y) is equal to either that of x or // that of y. - return (std::numeric_limits<T>::is_signed) + return (std::is_signed<T>::value) ? HasSignBit(BinaryComplement( static_cast<UnsignedDst>((uresult ^ ux) & (uresult ^ uy)))) : (BinaryComplement(x) >= @@ -93,11 +89,10 @@ struct CheckedAddOp {}; template <typename T, typename U> -struct CheckedAddOp< - T, - U, - typename std::enable_if<std::numeric_limits<T>::is_integer && - std::numeric_limits<U>::is_integer>::type> { +struct CheckedAddOp<T, + U, + typename std::enable_if<std::is_integral<T>::value && + std::is_integral<U>::value>::type> { using result_type = typename MaxExponentPromotion<T, U>::type; template <typename V> static bool Do(T x, U y, V* result) { @@ -123,19 +118,19 @@ } }; -template <typename T> -typename std::enable_if<std::numeric_limits<T>::is_integer, bool>::type -CheckedSubImpl(T x, T y, T* result) { +template <typename T, + typename std::enable_if<std::is_integral<T>::value>::type* = nullptr> +bool CheckedSubImpl(T x, T y, T* result) { // Since the value of x+y is undefined if we have a signed type, we compute // it using the unsigned type of the same size. - typedef typename UnsignedIntegerForSize<T>::type UnsignedDst; + using UnsignedDst = typename std::make_unsigned<T>::type; UnsignedDst ux = static_cast<UnsignedDst>(x); UnsignedDst uy = static_cast<UnsignedDst>(y); UnsignedDst uresult = static_cast<UnsignedDst>(ux - uy); *result = static_cast<T>(uresult); // Subtraction is valid if either x and y have same sign, or (x-y) and x have // the same sign. - return (std::numeric_limits<T>::is_signed) + return (std::is_signed<T>::value) ? HasSignBit(BinaryComplement( static_cast<UnsignedDst>((uresult ^ ux) & (ux ^ uy)))) : (x >= y); @@ -145,11 +140,10 @@ struct CheckedSubOp {}; template <typename T, typename U> -struct CheckedSubOp< - T, - U, - typename std::enable_if<std::numeric_limits<T>::is_integer && - std::numeric_limits<U>::is_integer>::type> { +struct CheckedSubOp<T, + U, + typename std::enable_if<std::is_integral<T>::value && + std::is_integral<U>::value>::type> { using result_type = typename MaxExponentPromotion<T, U>::type; template <typename V> static bool Do(T x, U y, V* result) { @@ -179,36 +173,37 @@ // we just promote to a twice wider type, and range check the result. In the // slow case we need to manually check that the result won't be truncated by // checking with division against the appropriate bound. -template <typename T> -typename std::enable_if<std::numeric_limits<T>::is_integer && - sizeof(T) * 2 <= sizeof(uintmax_t), - bool>::type -CheckedMulImpl(T x, T y, T* result) { - typedef typename TwiceWiderInteger<T>::type IntermediateType; +template <typename T, + typename std::enable_if< + std::is_integral<T>::value && + ((IntegerBitsPlusSign<T>::value * 2) <= + IntegerBitsPlusSign<intmax_t>::value)>::type* = nullptr> +bool CheckedMulImpl(T x, T y, T* result) { + using IntermediateType = typename TwiceWiderInteger<T>::type; IntermediateType tmp = static_cast<IntermediateType>(x) * static_cast<IntermediateType>(y); *result = static_cast<T>(tmp); return DstRangeRelationToSrcRange<T>(tmp) == RANGE_VALID; } -template <typename T> -typename std::enable_if<std::numeric_limits<T>::is_integer && - std::numeric_limits<T>::is_signed && - (sizeof(T) * 2 > sizeof(uintmax_t)), - bool>::type -CheckedMulImpl(T x, T y, T* result) { +template <typename T, + typename std::enable_if< + std::is_integral<T>::value && std::is_signed<T>::value && + ((IntegerBitsPlusSign<T>::value * 2) > + IntegerBitsPlusSign<intmax_t>::value)>::type* = nullptr> +bool CheckedMulImpl(T x, T y, T* result) { if (x && y) { if (x > 0) { if (y > 0) { if (x > std::numeric_limits<T>::max() / y) return false; } else { - if (y < std::numeric_limits<T>::min() / x) + if (y < std::numeric_limits<T>::lowest() / x) return false; } } else { if (y > 0) { - if (x < std::numeric_limits<T>::min() / y) + if (x < std::numeric_limits<T>::lowest() / y) return false; } else { if (y < std::numeric_limits<T>::max() / x) @@ -220,12 +215,12 @@ return true; } -template <typename T> -typename std::enable_if<std::numeric_limits<T>::is_integer && - !std::numeric_limits<T>::is_signed && - (sizeof(T) * 2 > sizeof(uintmax_t)), - bool>::type -CheckedMulImpl(T x, T y, T* result) { +template <typename T, + typename std::enable_if< + std::is_integral<T>::value && !std::is_signed<T>::value && + ((IntegerBitsPlusSign<T>::value * 2) > + IntegerBitsPlusSign<uintmax_t>::value)>::type* = nullptr> +bool CheckedMulImpl(T x, T y, T* result) { *result = x * y; return (y == 0 || x <= std::numeric_limits<T>::max() / y); } @@ -234,11 +229,10 @@ struct CheckedMulOp {}; template <typename T, typename U> -struct CheckedMulOp< - T, - U, - typename std::enable_if<std::numeric_limits<T>::is_integer && - std::numeric_limits<U>::is_integer>::type> { +struct CheckedMulOp<T, + U, + typename std::enable_if<std::is_integral<T>::value && + std::is_integral<U>::value>::type> { using result_type = typename MaxExponentPromotion<T, U>::type; template <typename V> static bool Do(T x, U y, V* result) { @@ -248,8 +242,12 @@ // support full-width, mixed-sign multiply builtins. // https://crbug.com/613003 static const bool kUseMaxInt = - sizeof(__typeof__(x * y)) < sizeof(intptr_t) || - (sizeof(__typeof__(x * y)) == sizeof(intptr_t) && + // Narrower type than uintptr_t is always safe. + std::numeric_limits<__typeof__(x * y)>::digits < + std::numeric_limits<intptr_t>::digits || + // Safe for intptr_t and uintptr_t if the sign matches. + (IntegerBitsPlusSign<__typeof__(x * y)>::value == + IntegerBitsPlusSign<intptr_t>::value && std::is_signed<T>::value == std::is_signed<U>::value); #else static const bool kUseMaxInt = true; @@ -280,11 +278,11 @@ // Division just requires a check for a zero denominator or an invalid negation // on signed min/-1. -template <typename T> -typename std::enable_if<std::numeric_limits<T>::is_integer, bool>::type -CheckedDivImpl(T x, T y, T* result) { - if (y && (!std::numeric_limits<T>::is_signed || - x != std::numeric_limits<T>::min() || y != static_cast<T>(-1))) { +template <typename T, + typename std::enable_if<std::is_integral<T>::value>::type* = nullptr> +bool CheckedDivImpl(T x, T y, T* result) { + if (y && (!std::is_signed<T>::value || + x != std::numeric_limits<T>::lowest() || y != static_cast<T>(-1))) { *result = x / y; return true; } @@ -295,11 +293,10 @@ struct CheckedDivOp {}; template <typename T, typename U> -struct CheckedDivOp< - T, - U, - typename std::enable_if<std::numeric_limits<T>::is_integer && - std::numeric_limits<U>::is_integer>::type> { +struct CheckedDivOp<T, + U, + typename std::enable_if<std::is_integral<T>::value && + std::is_integral<U>::value>::type> { using result_type = typename MaxExponentPromotion<T, U>::type; template <typename V> static bool Do(T x, U y, V* result) { @@ -316,11 +313,9 @@ } }; -template <typename T> -typename std::enable_if<std::numeric_limits<T>::is_integer && - std::numeric_limits<T>::is_signed, - bool>::type -CheckedModImpl(T x, T y, T* result) { +template <typename T, + typename std::enable_if<std::is_integral<T>::value>::type* = nullptr> +bool CheckedModImpl(T x, T y, T* result) { if (y > 0) { *result = static_cast<T>(x % y); return true; @@ -328,27 +323,14 @@ return false; } -template <typename T> -typename std::enable_if<std::numeric_limits<T>::is_integer && - !std::numeric_limits<T>::is_signed, - bool>::type -CheckedModImpl(T x, T y, T* result) { - if (y != 0) { - *result = static_cast<T>(x % y); - return true; - } - return false; -} - template <typename T, typename U, class Enable = void> struct CheckedModOp {}; template <typename T, typename U> -struct CheckedModOp< - T, - U, - typename std::enable_if<std::numeric_limits<T>::is_integer && - std::numeric_limits<U>::is_integer>::type> { +struct CheckedModOp<T, + U, + typename std::enable_if<std::is_integral<T>::value && + std::is_integral<U>::value>::type> { using result_type = typename MaxExponentPromotion<T, U>::type; template <typename V> static bool Do(T x, U y, V* result) { @@ -368,16 +350,15 @@ // of bits in the promoted type are undefined. Shifts of negative values // are undefined. Otherwise it is defined when the result fits. template <typename T, typename U> -struct CheckedLshOp< - T, - U, - typename std::enable_if<std::numeric_limits<T>::is_integer && - std::numeric_limits<U>::is_integer>::type> { +struct CheckedLshOp<T, + U, + typename std::enable_if<std::is_integral<T>::value && + std::is_integral<U>::value>::type> { using result_type = T; template <typename V> static bool Do(T x, U shift, V* result) { - using ShiftType = typename UnsignedIntegerForSize<T>::type; - static const ShiftType kBitWidth = CHAR_BIT * sizeof(T); + using ShiftType = typename std::make_unsigned<T>::type; + static const ShiftType kBitWidth = IntegerBitsPlusSign<T>::value; const ShiftType real_shift = static_cast<ShiftType>(shift); // Signed shift is not legal on negative values. if (!IsValueNegative(x) && real_shift < kBitWidth) { @@ -398,17 +379,16 @@ // of bits in the promoted type are undefined. Otherwise, it is always defined, // but a right shift of a negative value is implementation-dependent. template <typename T, typename U> -struct CheckedRshOp< - T, - U, - typename std::enable_if<std::numeric_limits<T>::is_integer && - std::numeric_limits<U>::is_integer>::type> { +struct CheckedRshOp<T, + U, + typename std::enable_if<std::is_integral<T>::value && + std::is_integral<U>::value>::type> { using result_type = T; template <typename V = result_type> static bool Do(T x, U shift, V* result) { // Use the type conversion push negative values out of range. - using ShiftType = typename UnsignedIntegerForSize<T>::type; - if (static_cast<ShiftType>(shift) < (CHAR_BIT * sizeof(T))) { + using ShiftType = typename std::make_unsigned<T>::type; + if (static_cast<ShiftType>(shift) < IntegerBitsPlusSign<T>::value) { T tmp = x >> shift; *result = static_cast<V>(tmp); return IsValueInRangeForNumericType<V>(tmp); @@ -426,7 +406,7 @@ U, typename std::enable_if<std::is_integral<T>::value && std::is_integral<U>::value>::type> { - using result_type = typename UnsignedIntegerForSize< + using result_type = typename std::make_unsigned< typename MaxExponentPromotion<T, U>::type>::type; template <typename V = result_type> static bool Do(T x, U y, V* result) { @@ -445,7 +425,7 @@ U, typename std::enable_if<std::is_integral<T>::value && std::is_integral<U>::value>::type> { - using result_type = typename UnsignedIntegerForSize< + using result_type = typename std::make_unsigned< typename MaxExponentPromotion<T, U>::type>::type; template <typename V = result_type> static bool Do(T x, U y, V* result) { @@ -464,7 +444,7 @@ U, typename std::enable_if<std::is_integral<T>::value && std::is_integral<U>::value>::type> { - using result_type = typename UnsignedIntegerForSize< + using result_type = typename std::make_unsigned< typename MaxExponentPromotion<T, U>::type>::type; template <typename V = result_type> static bool Do(T x, U y, V* result) { @@ -514,99 +494,90 @@ } }; -template <typename T> -typename std::enable_if<std::numeric_limits<T>::is_integer && - std::numeric_limits<T>::is_signed, - bool>::type -CheckedNeg(T value, T* result) { +template <typename T, + typename std::enable_if<std::is_integral<T>::value && + std::is_signed<T>::value>::type* = nullptr> +bool CheckedNeg(T value, T* result) { // The negation of signed min is min, so catch that one. - if (value != std::numeric_limits<T>::min()) { + if (value != std::numeric_limits<T>::lowest()) { *result = static_cast<T>(-value); return true; } return false; } -template <typename T> -typename std::enable_if<std::numeric_limits<T>::is_integer && - !std::numeric_limits<T>::is_signed, - bool>::type -CheckedNeg(T value, T* result) { - if (!value) { // The only legal unsigned negation is zero. +template <typename T, + typename std::enable_if<std::is_integral<T>::value && + !std::is_signed<T>::value>::type* = nullptr> +bool CheckedNeg(T value, T* result) { + if (!value) { *result = static_cast<T>(0); return true; } return false; } -template <typename T> -typename std::enable_if<std::numeric_limits<T>::is_integer && - !std::numeric_limits<T>::is_signed, - bool>::type -CheckedInv(T value, T* result) { +template <typename T, + typename std::enable_if<std::is_integral<T>::value && + !std::is_signed<T>::value>::type* = nullptr> +bool CheckedInv(T value, T* result) { *result = ~value; return true; } -template <typename T> -typename std::enable_if<std::numeric_limits<T>::is_integer && - std::numeric_limits<T>::is_signed, - bool>::type -CheckedAbs(T value, T* result) { - if (value != std::numeric_limits<T>::min()) { +template <typename T, + typename std::enable_if<std::is_integral<T>::value && + std::is_signed<T>::value>::type* = nullptr> +bool CheckedAbs(T value, T* result) { + if (value != std::numeric_limits<T>::lowest()) { *result = std::abs(value); return true; } return false; } -template <typename T> -typename std::enable_if<std::numeric_limits<T>::is_integer && - !std::numeric_limits<T>::is_signed, - bool>::type -CheckedAbs(T value, T* result) { +template <typename T, + typename std::enable_if<std::is_integral<T>::value && + !std::is_signed<T>::value>::type* = nullptr> +bool CheckedAbs(T value, T* result) { // T is unsigned, so |value| must already be positive. *result = value; return true; } -template <typename T> -constexpr - typename std::enable_if<std::numeric_limits<T>::is_integer && - std::numeric_limits<T>::is_signed, - typename UnsignedIntegerForSize<T>::type>::type - SafeUnsignedAbs(T value) { - typedef typename UnsignedIntegerForSize<T>::type UnsignedT; - return value == std::numeric_limits<T>::min() +template <typename T, + typename std::enable_if<std::is_integral<T>::value && + std::is_signed<T>::value>::type* = nullptr> +constexpr typename std::make_unsigned<T>::type SafeUnsignedAbs(T value) { + using UnsignedT = typename std::make_unsigned<T>::type; + return value == std::numeric_limits<T>::lowest() ? static_cast<UnsignedT>(std::numeric_limits<T>::max()) + 1 : static_cast<UnsignedT>(std::abs(value)); } -template <typename T> -constexpr typename std::enable_if<std::numeric_limits<T>::is_integer && - !std::numeric_limits<T>::is_signed, - T>::type -SafeUnsignedAbs(T value) { +template <typename T, + typename std::enable_if<std::is_integral<T>::value && + !std::is_signed<T>::value>::type* = nullptr> +constexpr T SafeUnsignedAbs(T value) { // T is unsigned, so |value| must already be positive. return static_cast<T>(value); } // This is just boilerplate that wraps the standard floating point arithmetic. // A macro isn't the nicest solution, but it beats rewriting these repeatedly. -#define BASE_FLOAT_ARITHMETIC_OPS(NAME, OP) \ - template <typename T, typename U> \ - struct Checked##NAME##Op< \ - T, U, \ - typename std::enable_if<std::numeric_limits<T>::is_iec559 || \ - std::numeric_limits<U>::is_iec559>::type> { \ - using result_type = typename MaxExponentPromotion<T, U>::type; \ - template <typename V> \ - static bool Do(T x, U y, V* result) { \ - using Promotion = typename MaxExponentPromotion<T, U>::type; \ - Promotion presult = x OP y; \ - *result = static_cast<V>(presult); \ - return IsValueInRangeForNumericType<V>(presult); \ - } \ +#define BASE_FLOAT_ARITHMETIC_OPS(NAME, OP) \ + template <typename T, typename U> \ + struct Checked##NAME##Op< \ + T, U, typename std::enable_if<std::is_floating_point<T>::value || \ + std::is_floating_point<U>::value>::type> { \ + using result_type = typename MaxExponentPromotion<T, U>::type; \ + template <typename V> \ + static bool Do(T x, U y, V* result) { \ + using Promotion = typename MaxExponentPromotion<T, U>::type; \ + Promotion presult = x OP y; \ + *result = static_cast<V>(presult); \ + return IsValueInRangeForNumericType<V>(presult); \ + } \ }; BASE_FLOAT_ARITHMETIC_OPS(Add, +) @@ -616,16 +587,18 @@ #undef BASE_FLOAT_ARITHMETIC_OPS -template <typename T> -typename std::enable_if<std::numeric_limits<T>::is_iec559, bool>::type -CheckedNeg(T value, T* result) { +template < + typename T, + typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr> +bool CheckedNeg(T value, T* result) { *result = static_cast<T>(-value); return true; } -template <typename T> -typename std::enable_if<std::numeric_limits<T>::is_iec559, bool>::type -CheckedAbs(T value, T* result) { +template < + typename T, + typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr> +bool CheckedAbs(T value, T* result) { *result = static_cast<T>(std::abs(value)); return true; } @@ -642,10 +615,10 @@ template <typename NumericType> struct GetNumericRepresentation { static const NumericRepresentation value = - std::numeric_limits<NumericType>::is_integer + std::is_integral<NumericType>::value ? NUMERIC_INTEGER - : (std::numeric_limits<NumericType>::is_iec559 ? NUMERIC_FLOATING - : NUMERIC_UNKNOWN); + : (std::is_floating_point<NumericType>::value ? NUMERIC_FLOATING + : NUMERIC_UNKNOWN); }; template <typename T, NumericRepresentation type = @@ -672,8 +645,7 @@ constexpr CheckedNumericState(Src value, bool is_valid) : is_valid_(is_valid && IsValueInRangeForNumericType<T>(value)), value_(is_valid_ ? static_cast<T>(value) : 0) { - static_assert(std::numeric_limits<Src>::is_specialized, - "Argument must be numeric."); + static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric."); } // Copy constructor. @@ -683,10 +655,7 @@ value_(is_valid_ ? static_cast<T>(rhs.value()) : 0) {} template <typename Src> - constexpr explicit CheckedNumericState( - Src value, - typename std::enable_if<std::numeric_limits<Src>::is_specialized, - int>::type = 0) + constexpr explicit CheckedNumericState(Src value) : is_valid_(IsValueInRangeForNumericType<T>(value)), value_(is_valid_ ? static_cast<T>(value) : 0) {} @@ -707,20 +676,13 @@ constexpr CheckedNumericState() : value_(0.0) {} template <typename Src> - constexpr CheckedNumericState( - Src value, - bool is_valid, - typename std::enable_if<std::numeric_limits<Src>::is_integer, int>::type = - 0) + constexpr CheckedNumericState(Src value, bool is_valid) : value_((is_valid && IsValueInRangeForNumericType<T>(value)) ? static_cast<T>(value) : std::numeric_limits<T>::quiet_NaN()) {} template <typename Src> - constexpr explicit CheckedNumericState( - Src value, - typename std::enable_if<std::numeric_limits<Src>::is_specialized, - int>::type = 0) + constexpr explicit CheckedNumericState(Src value) : value_(static_cast<T>(value)) {} // Copy constructor.
diff --git a/base/numerics/safe_numerics_unittest.cc b/base/numerics/safe_numerics_unittest.cc index 56b07427..985a3082 100644 --- a/base/numerics/safe_numerics_unittest.cc +++ b/base/numerics/safe_numerics_unittest.cc
@@ -44,11 +44,11 @@ using base::saturated_cast; using base::strict_cast; using base::internal::MaxExponent; +using base::internal::IntegerBitsPlusSign; using base::internal::RANGE_VALID; using base::internal::RANGE_INVALID; using base::internal::RANGE_OVERFLOW; using base::internal::RANGE_UNDERFLOW; -using base::internal::SignedIntegerForSize; // These tests deliberately cause arithmetic boundary errors. If the compiler is // aggressive enough, it can const detect these errors, so we disable warnings. @@ -61,8 +61,8 @@ // wholy represented as the destination floating-point type. template <typename Dst, typename Src> Dst GetMaxConvertibleToFloat() { - typedef numeric_limits<Dst> DstLimits; - typedef numeric_limits<Src> SrcLimits; + using DstLimits = numeric_limits<Dst>; + using SrcLimits = numeric_limits<Src>; static_assert(SrcLimits::is_specialized, "Source must be numeric."); static_assert(DstLimits::is_specialized, "Destination must be numeric."); CHECK(DstLimits::is_iec559); @@ -139,35 +139,35 @@ typename std::enable_if<numeric_limits<Dst>::is_integer && numeric_limits<Dst>::is_signed, int>::type = 0) { - typedef numeric_limits<Dst> DstLimits; - TEST_EXPECTED_FAILURE(-CheckedNumeric<Dst>(DstLimits::min())); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::min()).Abs()); + using DstLimits = numeric_limits<Dst>; + TEST_EXPECTED_FAILURE(-CheckedNumeric<Dst>(DstLimits::lowest())); + TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()).Abs()); TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(-1).Abs()); TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::max()) + -1); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::min()) + -1); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(-DstLimits::max()) + - -DstLimits::max()); + TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()) + -1); + TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()) + + DstLimits::lowest()); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::min()) - 1); - TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::min()) - -1); + TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()) - 1); + TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::lowest()) - -1); TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::max()) - - -DstLimits::max()); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(-DstLimits::max()) - + DstLimits::lowest()); + TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()) - DstLimits::max()); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::min()) * 2); + TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()) * 2); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::min()) / -1); + TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()) / -1); TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(-1) / 2); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::min()) * -1); + TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()) * -1); // Modulus is legal only for integers. TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>() % 1); TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % 1); TEST_EXPECTED_VALUE(-1, CheckedNumeric<Dst>(-1) % 2); TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(-1) % -2); - TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(DstLimits::min()) % 2); + TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(DstLimits::lowest()) % 2); TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(DstLimits::max()) % 2); // Test all the different modulus combinations. TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % CheckedNumeric<Dst>(1)); @@ -180,18 +180,22 @@ // Test bit shifts. volatile Dst negative_one = -1; TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1) << negative_one); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1) << (sizeof(Dst) * CHAR_BIT - 1)); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(0) << (sizeof(Dst) * CHAR_BIT)); + TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1) + << (IntegerBitsPlusSign<Dst>::value - 1)); + TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(0) + << IntegerBitsPlusSign<Dst>::value); TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::max()) << 1); - TEST_EXPECTED_VALUE(static_cast<Dst>(1) << (sizeof(Dst) * CHAR_BIT - 2), - CheckedNumeric<Dst>(1) << (sizeof(Dst) * CHAR_BIT - 2)); + TEST_EXPECTED_VALUE( + static_cast<Dst>(1) << (IntegerBitsPlusSign<Dst>::value - 2), + CheckedNumeric<Dst>(1) << (IntegerBitsPlusSign<Dst>::value - 2)); TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(0) - << (sizeof(Dst) * CHAR_BIT - 1)); + << (IntegerBitsPlusSign<Dst>::value - 1)); TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) << 0); TEST_EXPECTED_VALUE(2, CheckedNumeric<Dst>(1) << 1); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1) >> (sizeof(Dst) * CHAR_BIT)); - TEST_EXPECTED_VALUE(0, - CheckedNumeric<Dst>(1) >> (sizeof(Dst) * CHAR_BIT - 1)); + TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1) >> + IntegerBitsPlusSign<Dst>::value); + TEST_EXPECTED_VALUE( + 0, CheckedNumeric<Dst>(1) >> (IntegerBitsPlusSign<Dst>::value - 1)); TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1) >> negative_one); TestStrictPointerMath<Dst>(); @@ -205,24 +209,24 @@ typename std::enable_if<numeric_limits<Dst>::is_integer && !numeric_limits<Dst>::is_signed, int>::type = 0) { - typedef numeric_limits<Dst> DstLimits; - TEST_EXPECTED_SUCCESS(-CheckedNumeric<Dst>(DstLimits::min())); - TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::min()).Abs()); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::min()) + -1); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::min()) - 1); - TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(DstLimits::min()) * 2); + using DstLimits = numeric_limits<Dst>; + TEST_EXPECTED_SUCCESS(-CheckedNumeric<Dst>(DstLimits::lowest())); + TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::lowest()).Abs()); + TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()) + -1); + TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()) - 1); + TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(DstLimits::lowest()) * 2); TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) / 2); - TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::min()).UnsignedAbs()); + TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::lowest()).UnsignedAbs()); TEST_EXPECTED_SUCCESS( - CheckedNumeric<typename SignedIntegerForSize<Dst>::type>( - std::numeric_limits<typename SignedIntegerForSize<Dst>::type>::min()) + CheckedNumeric<typename std::make_signed<Dst>::type>( + std::numeric_limits<typename std::make_signed<Dst>::type>::lowest()) .UnsignedAbs()); // Modulus is legal only for integers. TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>() % 1); TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % 1); TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) % 2); - TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(DstLimits::min()) % 2); + TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(DstLimits::lowest()) % 2); TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(DstLimits::max()) % 2); // Test all the different modulus combinations. TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % CheckedNumeric<Dst>(1)); @@ -232,20 +236,25 @@ TEST_EXPECTED_VALUE(0, checked_dst %= 1); // Test that div by 0 is avoided but returns invalid result. TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1) % 0); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1) << (sizeof(Dst) * CHAR_BIT)); + TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1) + << IntegerBitsPlusSign<Dst>::value); // Test bit shifts. volatile int negative_one = -1; TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1) << negative_one); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1) << (sizeof(Dst) * CHAR_BIT)); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(0) << (sizeof(Dst) * CHAR_BIT)); + TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1) + << IntegerBitsPlusSign<Dst>::value); + TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(0) + << IntegerBitsPlusSign<Dst>::value); TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::max()) << 1); - TEST_EXPECTED_VALUE(static_cast<Dst>(1) << (sizeof(Dst) * CHAR_BIT - 1), - CheckedNumeric<Dst>(1) << (sizeof(Dst) * CHAR_BIT - 1)); + TEST_EXPECTED_VALUE( + static_cast<Dst>(1) << (IntegerBitsPlusSign<Dst>::value - 1), + CheckedNumeric<Dst>(1) << (IntegerBitsPlusSign<Dst>::value - 1)); TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) << 0); TEST_EXPECTED_VALUE(2, CheckedNumeric<Dst>(1) << 1); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1) >> (sizeof(Dst) * CHAR_BIT)); - TEST_EXPECTED_VALUE(0, - CheckedNumeric<Dst>(1) >> (sizeof(Dst) * CHAR_BIT - 1)); + TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1) >> + IntegerBitsPlusSign<Dst>::value); + TEST_EXPECTED_VALUE( + 0, CheckedNumeric<Dst>(1) >> (IntegerBitsPlusSign<Dst>::value - 1)); TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(1) >> negative_one); TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) & 1); TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) & 0); @@ -276,23 +285,23 @@ const char* dst, int line, typename std::enable_if<numeric_limits<Dst>::is_iec559, int>::type = 0) { - typedef numeric_limits<Dst> DstLimits; - TEST_EXPECTED_SUCCESS(-CheckedNumeric<Dst>(DstLimits::min())); + using DstLimits = numeric_limits<Dst>; + TEST_EXPECTED_SUCCESS(-CheckedNumeric<Dst>(DstLimits::lowest())); - TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::min()).Abs()); + TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::lowest()).Abs()); TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(-1).Abs()); - TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::min()) + -1); + TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::lowest()) + -1); TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::max()) + 1); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(-DstLimits::max()) + - -DstLimits::max()); + TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()) + + DstLimits::lowest()); TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::max()) - - -DstLimits::max()); - TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(-DstLimits::max()) - + DstLimits::lowest()); + TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()) - DstLimits::max()); - TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::min()) * 2); + TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::lowest()) * 2); TEST_EXPECTED_VALUE(-0.5, CheckedNumeric<Dst>(-1.0) / 2); } @@ -300,7 +309,7 @@ // Generic arithmetic tests. template <typename Dst> static void TestArithmetic(const char* dst, int line) { - typedef numeric_limits<Dst> DstLimits; + using DstLimits = numeric_limits<Dst>; EXPECT_EQ(true, CheckedNumeric<Dst>().IsValid()); EXPECT_EQ(false, @@ -354,7 +363,7 @@ TEST_EXPECTED_VALUE(2, (CheckedNumeric<Dst>(1) + 1)); if (numeric_limits<Dst>::is_signed) TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>(-1) + 1)); - TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::min()) + 1); + TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::lowest()) + 1); TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::max()) + DstLimits::max()); @@ -387,8 +396,8 @@ // Generic division. TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>() / 1); TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) / 1); - TEST_EXPECTED_VALUE(DstLimits::min() / 2, - CheckedNumeric<Dst>(DstLimits::min()) / 2); + TEST_EXPECTED_VALUE(DstLimits::lowest() / 2, + CheckedNumeric<Dst>(DstLimits::lowest()) / 2); TEST_EXPECTED_VALUE(DstLimits::max() / 2, CheckedNumeric<Dst>(DstLimits::max()) / 2); @@ -438,8 +447,8 @@ template <typename Dst, typename Src> void TestStrictComparison() { - typedef numeric_limits<Dst> DstLimits; - typedef numeric_limits<Src> SrcLimits; + using DstLimits = numeric_limits<Dst>; + using SrcLimits = numeric_limits<Src>; static_assert(StrictNumeric<Src>(SrcLimits::lowest()) < DstLimits::max(), ""); static_assert(StrictNumeric<Src>(SrcLimits::lowest()) < SrcLimits::max(), ""); static_assert(!(StrictNumeric<Src>(SrcLimits::lowest()) >= DstLimits::max()), @@ -506,17 +515,18 @@ template <typename Dst, typename Src> struct TestNumericConversion<Dst, Src, SIGN_PRESERVING_VALUE_PRESERVING> { static void Test(const char *dst, const char *src, int line) { - typedef numeric_limits<Src> SrcLimits; - typedef numeric_limits<Dst> DstLimits; - // Integral to floating. + using SrcLimits = numeric_limits<Src>; + using DstLimits = numeric_limits<Dst>; + // Integral to floating. static_assert((DstLimits::is_iec559 && SrcLimits::is_integer) || - // Not floating to integral and... - (!(DstLimits::is_integer && SrcLimits::is_iec559) && - // Same sign, same numeric, source is narrower or same. - ((SrcLimits::is_signed == DstLimits::is_signed && - sizeof(Dst) >= sizeof(Src)) || - // Or signed destination and source is smaller - (DstLimits::is_signed && sizeof(Dst) > sizeof(Src)))), + // Not floating to integral and... + (!(DstLimits::is_integer && SrcLimits::is_iec559) && + // Same sign, same numeric, source is narrower or same. + ((SrcLimits::is_signed == DstLimits::is_signed && + MaxExponent<Dst>::value >= MaxExponent<Src>::value) || + // Or signed destination and source is smaller + (DstLimits::is_signed && + MaxExponent<Dst>::value >= MaxExponent<Src>::value))), "Comparison must be sign preserving and value preserving"); TestStrictComparison<Dst, Src>(); @@ -545,7 +555,7 @@ TEST_EXPECTED_RANGE(RANGE_INVALID, SrcLimits::quiet_NaN()); } else if (numeric_limits<Src>::is_signed) { TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(-1)); - TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::min()); + TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::lowest()); } } }; @@ -553,12 +563,11 @@ template <typename Dst, typename Src> struct TestNumericConversion<Dst, Src, SIGN_PRESERVING_NARROW> { static void Test(const char *dst, const char *src, int line) { - typedef numeric_limits<Src> SrcLimits; - typedef numeric_limits<Dst> DstLimits; + using SrcLimits = numeric_limits<Src>; + using DstLimits = numeric_limits<Dst>; static_assert(SrcLimits::is_signed == DstLimits::is_signed, "Destination and source sign must be the same"); - static_assert(sizeof(Dst) < sizeof(Src) || - (DstLimits::is_integer && SrcLimits::is_iec559), + static_assert(MaxExponent<Dst>::value <= MaxExponent<Src>::value, "Destination must be narrower than source"); TestStrictComparison<Dst, Src>(); @@ -586,15 +595,15 @@ TEST_EXPECTED_RANGE( RANGE_VALID, static_cast<Src>(GetMaxConvertibleToFloat<Src, Dst>())); - TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(DstLimits::min())); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(DstLimits::lowest())); } } else if (SrcLimits::is_signed) { TEST_EXPECTED_VALUE(-1, checked_dst - static_cast<Src>(1)); - TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::min()); + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::lowest()); TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(-1)); } else { TEST_EXPECTED_FAILURE(checked_dst - static_cast<Src>(1)); - TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::min()); + TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::lowest()); } } }; @@ -602,9 +611,9 @@ template <typename Dst, typename Src> struct TestNumericConversion<Dst, Src, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL> { static void Test(const char *dst, const char *src, int line) { - typedef numeric_limits<Src> SrcLimits; - typedef numeric_limits<Dst> DstLimits; - static_assert(sizeof(Dst) >= sizeof(Src), + using SrcLimits = numeric_limits<Src>; + using DstLimits = numeric_limits<Dst>; + static_assert(MaxExponent<Dst>::value >= MaxExponent<Src>::value, "Destination must be equal or wider than source."); static_assert(SrcLimits::is_signed, "Source must be signed"); static_assert(!DstLimits::is_signed, "Destination must be unsigned"); @@ -614,9 +623,9 @@ const CheckedNumeric<Dst> checked_dst; TEST_EXPECTED_VALUE(SrcLimits::max(), checked_dst + SrcLimits::max()); TEST_EXPECTED_FAILURE(checked_dst + static_cast<Src>(-1)); - TEST_EXPECTED_FAILURE(checked_dst + -SrcLimits::max()); + TEST_EXPECTED_FAILURE(checked_dst + SrcLimits::lowest()); - TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::min()); + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::lowest()); TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::max()); TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(1)); TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, static_cast<Src>(-1)); @@ -626,10 +635,9 @@ template <typename Dst, typename Src> struct TestNumericConversion<Dst, Src, SIGN_TO_UNSIGN_NARROW> { static void Test(const char *dst, const char *src, int line) { - typedef numeric_limits<Src> SrcLimits; - typedef numeric_limits<Dst> DstLimits; - static_assert((DstLimits::is_integer && SrcLimits::is_iec559) || - (sizeof(Dst) < sizeof(Src)), + using SrcLimits = numeric_limits<Src>; + using DstLimits = numeric_limits<Dst>; + static_assert(MaxExponent<Dst>::value < MaxExponent<Src>::value, "Destination must be narrower than source."); static_assert(SrcLimits::is_signed, "Source must be signed."); static_assert(!DstLimits::is_signed, "Destination must be unsigned."); @@ -640,7 +648,7 @@ TEST_EXPECTED_VALUE(1, checked_dst + static_cast<Src>(1)); TEST_EXPECTED_FAILURE(checked_dst + SrcLimits::max()); TEST_EXPECTED_FAILURE(checked_dst + static_cast<Src>(-1)); - TEST_EXPECTED_FAILURE(checked_dst + -SrcLimits::max()); + TEST_EXPECTED_FAILURE(checked_dst + SrcLimits::lowest()); TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::max()); TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(1)); @@ -660,10 +668,10 @@ TEST_EXPECTED_RANGE( RANGE_VALID, static_cast<Src>(GetMaxConvertibleToFloat<Src, Dst>())); - TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(DstLimits::min())); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(DstLimits::lowest())); } } else { - TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::min()); + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::lowest()); } } }; @@ -671,9 +679,9 @@ template <typename Dst, typename Src> struct TestNumericConversion<Dst, Src, UNSIGN_TO_SIGN_NARROW_OR_EQUAL> { static void Test(const char *dst, const char *src, int line) { - typedef numeric_limits<Src> SrcLimits; - typedef numeric_limits<Dst> DstLimits; - static_assert(sizeof(Dst) <= sizeof(Src), + using SrcLimits = numeric_limits<Src>; + using DstLimits = numeric_limits<Dst>; + static_assert(MaxExponent<Dst>::value <= MaxExponent<Src>::value, "Destination must be narrower or equal to source."); static_assert(!SrcLimits::is_signed, "Source must be unsigned."); static_assert(DstLimits::is_signed, "Destination must be signed."); @@ -683,9 +691,9 @@ const CheckedNumeric<Dst> checked_dst; TEST_EXPECTED_VALUE(1, checked_dst + static_cast<Src>(1)); TEST_EXPECTED_FAILURE(checked_dst + SrcLimits::max()); - TEST_EXPECTED_VALUE(SrcLimits::min(), checked_dst + SrcLimits::min()); + TEST_EXPECTED_VALUE(SrcLimits::lowest(), checked_dst + SrcLimits::lowest()); - TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::min()); + TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::lowest()); TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::max()); TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(1)); } @@ -818,7 +826,7 @@ double double_large = numeric_limits<double>::max(); double double_infinity = numeric_limits<float>::infinity(); double double_large_int = numeric_limits<int>::max(); - double double_small_int = numeric_limits<int>::min(); + double double_small_int = numeric_limits<int>::lowest(); // Just test that the casts compile, since the other tests cover logic. EXPECT_EQ(0, checked_cast<int>(static_cast<size_t>(0))); @@ -834,9 +842,9 @@ EXPECT_FALSE(CheckedNumeric<unsigned>(StrictNumeric<int>(-1)).IsValid()); EXPECT_TRUE(IsValueNegative(-1)); - EXPECT_TRUE(IsValueNegative(numeric_limits<int>::min())); - EXPECT_FALSE(IsValueNegative(numeric_limits<unsigned>::min())); - EXPECT_TRUE(IsValueNegative(-numeric_limits<double>::max())); + EXPECT_TRUE(IsValueNegative(numeric_limits<int>::lowest())); + EXPECT_FALSE(IsValueNegative(numeric_limits<unsigned>::lowest())); + EXPECT_TRUE(IsValueNegative(numeric_limits<double>::lowest())); EXPECT_FALSE(IsValueNegative(0)); EXPECT_FALSE(IsValueNegative(1)); EXPECT_FALSE(IsValueNegative(0u)); @@ -863,7 +871,8 @@ EXPECT_EQ(saturated_cast<int>(double_large), numeric_limits<int>::max()); EXPECT_EQ(saturated_cast<float>(double_large), double_infinity); EXPECT_EQ(saturated_cast<float>(-double_large), -double_infinity); - EXPECT_EQ(numeric_limits<int>::min(), saturated_cast<int>(double_small_int)); + EXPECT_EQ(numeric_limits<int>::lowest(), + saturated_cast<int>(double_small_int)); EXPECT_EQ(numeric_limits<int>::max(), saturated_cast<int>(double_large_int)); float not_a_number = std::numeric_limits<float>::infinity() - @@ -872,7 +881,7 @@ EXPECT_EQ(0, saturated_cast<int>(not_a_number)); // Test the CheckedNumeric value extractions functions. - auto int8_min = MakeCheckedNum(numeric_limits<int8_t>::min()); + auto int8_min = MakeCheckedNum(numeric_limits<int8_t>::lowest()); auto int8_max = MakeCheckedNum(numeric_limits<int8_t>::max()); auto double_max = MakeCheckedNum(numeric_limits<double>::max()); static_assert( @@ -885,7 +894,7 @@ "ValueOrDefault returning incorrect type."); EXPECT_FALSE(IsValidForType<uint8_t>(int8_min)); EXPECT_TRUE(IsValidForType<uint8_t>(int8_max)); - EXPECT_EQ(static_cast<int>(numeric_limits<int8_t>::min()), + EXPECT_EQ(static_cast<int>(numeric_limits<int8_t>::lowest()), ValueOrDieForType<int>(int8_min)); EXPECT_TRUE(IsValidForType<uint32_t>(int8_max)); EXPECT_EQ(static_cast<int>(numeric_limits<int8_t>::max()), @@ -900,7 +909,7 @@ EXPECT_TRUE(int8_max.AssignIfValid(&int16_dest)); EXPECT_EQ(static_cast<int16_t>(numeric_limits<int8_t>::max()), int16_dest); EXPECT_TRUE(int8_min.AssignIfValid(&int16_dest)); - EXPECT_EQ(static_cast<int16_t>(numeric_limits<int8_t>::min()), int16_dest); + EXPECT_EQ(static_cast<int16_t>(numeric_limits<int8_t>::lowest()), int16_dest); EXPECT_FALSE(double_max.AssignIfValid(&uint8_dest)); EXPECT_FALSE(double_max.AssignIfValid(&int16_dest)); EXPECT_TRUE(double_max.AssignIfValid(&double_dest)); @@ -929,9 +938,9 @@ EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>(UINT64_C(0x100000000))); EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>(UINT64_C(0x100000001))); EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>( - std::numeric_limits<int32_t>::min())); + std::numeric_limits<int32_t>::lowest())); EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>( - std::numeric_limits<int64_t>::min())); + std::numeric_limits<int64_t>::lowest())); EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(0)); EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(1)); @@ -945,13 +954,13 @@ EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(INT64_C(0xffffffff))); EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(INT64_C(0x100000000))); EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>( - std::numeric_limits<int32_t>::min())); + std::numeric_limits<int32_t>::lowest())); EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>( - static_cast<int64_t>(std::numeric_limits<int32_t>::min()))); + static_cast<int64_t>(std::numeric_limits<int32_t>::lowest()))); EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>( - static_cast<int64_t>(std::numeric_limits<int32_t>::min()) - 1)); + static_cast<int64_t>(std::numeric_limits<int32_t>::lowest()) - 1)); EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>( - std::numeric_limits<int64_t>::min())); + std::numeric_limits<int64_t>::lowest())); EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(0)); EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(1)); @@ -962,10 +971,10 @@ EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(UINT64_C(0x100000000))); EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(UINT64_C(0x100000001))); EXPECT_FALSE(IsValueInRangeForNumericType<uint64_t>( - std::numeric_limits<int32_t>::min())); + std::numeric_limits<int32_t>::lowest())); EXPECT_FALSE(IsValueInRangeForNumericType<uint64_t>(INT64_C(-1))); EXPECT_FALSE(IsValueInRangeForNumericType<uint64_t>( - std::numeric_limits<int64_t>::min())); + std::numeric_limits<int64_t>::lowest())); EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(0)); EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(1)); @@ -987,11 +996,11 @@ EXPECT_FALSE( IsValueInRangeForNumericType<int64_t>(UINT64_C(0xffffffffffffffff))); EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>( - std::numeric_limits<int32_t>::min())); + std::numeric_limits<int32_t>::lowest())); EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>( - static_cast<int64_t>(std::numeric_limits<int32_t>::min()))); + static_cast<int64_t>(std::numeric_limits<int32_t>::lowest()))); EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>( - std::numeric_limits<int64_t>::min())); + std::numeric_limits<int64_t>::lowest())); } TEST(SafeNumerics, CompoundNumericOperations) {
diff --git a/chrome/DEPS b/chrome/DEPS index bdec65e..ee44536 100644 --- a/chrome/DEPS +++ b/chrome/DEPS
@@ -33,8 +33,6 @@ "-webkit", "-tools", - "-crypto/third_party", - # Allow inclusion of WebKit API files. "+third_party/WebKit/public/platform", "+third_party/WebKit/public/public_features.h",
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 ea42a47c..52ab333f 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
@@ -329,9 +329,7 @@ * @return The height of the Overlay Panel Content View in pixels. */ public int getContentViewHeightPx() { - float barExpandedHeight = isFullWidthSizePanel() - ? getToolbarHeight() : mBarHeightPeeking; - return Math.round((mMaximumHeight - barExpandedHeight) / mPxToDp); + return Math.round((mMaximumHeight - getToolbarHeight()) / mPxToDp); } // ============================================================================================ @@ -686,11 +684,7 @@ * @return The maximized height of the panel in dps. */ protected float getMaximizedHeight() { - if (isFullWidthSizePanel()) { - return getTabHeight(); - } else { - return getTabHeight() - mToolbarHeight; - } + return getTabHeight(); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java index b854b8f..aa2fab2 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java
@@ -32,7 +32,6 @@ import org.chromium.chrome.browser.offlinepages.OfflinePageBridge; import java.util.ArrayList; -import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -118,10 +117,10 @@ // We use our own implementation of the dismissal animation, so we don't call the // parent implementation. (by default it changes the translation-X and elevation) - mRecyclerView.updateViewStateForDismiss(dX, viewHolder); + mRecyclerView.updateViewStateForDismiss(dX, (NewTabPageViewHolder) viewHolder); // If there is another item that should be animated at the same time, do the same to it. - ViewHolder siblingViewHolder = getDismissSibling(viewHolder); + NewTabPageViewHolder siblingViewHolder = getDismissSibling(viewHolder); if (siblingViewHolder != null) { mRecyclerView.updateViewStateForDismiss(dX, siblingViewHolder); } @@ -388,26 +387,14 @@ return RecyclerView.NO_POSITION; } - public int getSignInPromoPosition() { - return getChildPositionOffset(mSigninPromo); - } - - public int getBottomSpacerPosition() { + int getBottomSpacerPosition() { return getChildPositionOffset(mBottomSpacer); } - public int getLastContentItemPosition() { + int getLastContentItemPosition() { return getChildPositionOffset(hasAllBeenDismissed() ? mAllDismissed : mFooter); } - public int getSuggestionPosition(SnippetArticle article) { - for (int i = 0; i < mRoot.getItemCount(); i++) { - SnippetArticle articleToCheck = mRoot.getSuggestionAt(i); - if (articleToCheck != null && articleToCheck.equals(article)) return i; - } - return RecyclerView.NO_POSITION; - } - private void setSuggestions(@CategoryInt int category, List<SnippetArticle> suggestions, @CategoryStatusEnum int status) { // Count the number of suggestions before this category. @@ -560,24 +547,16 @@ /** * Returns another view holder that should be dismissed at the same time as the provided one. */ - public ViewHolder getDismissSibling(ViewHolder viewHolder) { + public NewTabPageViewHolder getDismissSibling(ViewHolder viewHolder) { int swipePos = viewHolder.getAdapterPosition(); int siblingPosDelta = mRoot.getDismissSiblingPosDelta(swipePos); if (siblingPosDelta == 0) return null; - return mRecyclerView.findViewHolderForAdapterPosition(siblingPosDelta + swipePos); + return (NewTabPageViewHolder) mRecyclerView.findViewHolderForAdapterPosition( + siblingPosDelta + swipePos); } - /** - * @return The info associated to the provided category. - * @throws NullPointerException if {@code category} isn't currently registered with the adapter. - * */ - public SuggestionsCategoryInfo getCategoryInfo(@CategoryInt int category) { - return mSections.get(category).getCategoryInfo(); - } - - @VisibleForTesting - public boolean hasAllBeenDismissed() { + private boolean hasAllBeenDismissed() { return mSections.isEmpty() && !mSigninPromo.isVisible(); } @@ -601,20 +580,13 @@ * @return Returns the {@link SuggestionsSection} that contains the item at * {@code itemPosition}, or null if the item is not part of one. */ - @VisibleForTesting - SuggestionsSection getSuggestionsSection(int itemPosition) { + private SuggestionsSection getSuggestionsSection(int itemPosition) { TreeNode child = mRoot.getChildForPosition(itemPosition); if (!(child instanceof SuggestionsSection)) return null; return (SuggestionsSection) child; } - @VisibleForTesting - List<TreeNode> getChildren() { - return Collections.unmodifiableList(mChildren); - } - - @VisibleForTesting - int getChildPositionOffset(TreeNode child) { + private int getChildPositionOffset(TreeNode child) { return mRoot.getStartingOffsetForChild(child); } @@ -632,12 +604,20 @@ return RecyclerView.NO_POSITION; } - private void announceItemRemoved(String suggestionTitle) { + SuggestionsSection getSectionForTesting(@CategoryInt int category) { + return mSections.get(category); + } + + InnerNode getRootForTesting() { + return mRoot; + } + + private void announceItemRemoved(String itemTitle) { // In tests the RecyclerView can be null. if (mRecyclerView == null) return; mRecyclerView.announceForAccessibility(mRecyclerView.getResources().getString( - R.string.ntp_accessibility_item_removed, suggestionTitle)); + R.string.ntp_accessibility_item_removed, itemTitle)); } private void announceItemRemoved(@StringRes int stringToAnnounce) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerView.java index 7501092..6ebfa32 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerView.java
@@ -185,7 +185,7 @@ * Updates the space added at the end of the list to make sure the above/below the fold * distinction can be preserved. */ - public void refreshBottomSpacing() { + private void refreshBottomSpacing() { ViewHolder bottomSpacingViewHolder = findBottomSpacer(); // It might not be in the layout yet if it's not visible or ready to be displayed. @@ -536,8 +536,8 @@ * @param dX The amount of horizontal displacement caused by user's action. * @param viewHolder The view holder containing the view to be updated. */ - public void updateViewStateForDismiss(float dX, ViewHolder viewHolder) { - if (!((NewTabPageViewHolder) viewHolder).isDismissable()) return; + public void updateViewStateForDismiss(float dX, NewTabPageViewHolder viewHolder) { + if (!viewHolder.isDismissable()) return; viewHolder.itemView.setTranslationX(dX);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java index 55c26687..4e952c4c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java
@@ -50,7 +50,7 @@ mOfflinePageBridge = offlinePageBridge; mHeader = new SectionHeader(info.getTitle()); - mSuggestionsList = new SuggestionsList(this); + mSuggestionsList = new SuggestionsList(this, info); mStatus = StatusItem.createNoSuggestionsItem(this); mMoreButton = new ActionItem(this); mProgressIndicator = new ProgressItem(this); @@ -61,9 +61,11 @@ private static class SuggestionsList extends ChildNode implements Iterable<SnippetArticle> { private final List<SnippetArticle> mSuggestions = new ArrayList<>(); + private final SuggestionsCategoryInfo mCategoryInfo; - public SuggestionsList(NodeParent parent) { + public SuggestionsList(NodeParent parent, SuggestionsCategoryInfo categoryInfo) { super(parent); + mCategoryInfo = categoryInfo; } @Override @@ -80,7 +82,8 @@ @Override public void onBindViewHolder(NewTabPageViewHolder holder, int position) { assert holder instanceof SnippetArticleViewHolder; - ((SnippetArticleViewHolder) holder).onBindViewHolder(getSuggestionAt(position)); + ((SnippetArticleViewHolder) holder) + .onBindViewHolder(getSuggestionAt(position), mCategoryInfo); } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticleViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticleViewHolder.java index 5109920..3eb3a43 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticleViewHolder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticleViewHolder.java
@@ -66,6 +66,7 @@ private FetchImageCallback mImageCallback; private SnippetArticle mArticle; + private SuggestionsCategoryInfo mCategoryInfo; private int mPublisherFaviconSizePx; private final boolean mUseFaviconService; @@ -149,10 +150,9 @@ * Updates the layout taking into account screen dimensions and the type of snippet displayed. */ private void updateLayout() { - SuggestionsCategoryInfo info = - mRecyclerView.getNewTabPageAdapter().getCategoryInfo(mArticle.mCategory); boolean narrow = mUiConfig.getCurrentDisplayStyle() == UiConfig.DISPLAY_STYLE_NARROW; - boolean minimal = info.getCardLayout() == ContentSuggestionsCardLayout.MINIMAL_CARD; + boolean minimal = + mCategoryInfo.getCardLayout() == ContentSuggestionsCardLayout.MINIMAL_CARD; // If the screen is narrow or we are using the minimal layout, hide the article snippet. boolean hideSnippet = narrow || minimal; @@ -185,13 +185,14 @@ mPublisherBar.setLayoutParams(params); } - public void onBindViewHolder(SnippetArticle article) { + public void onBindViewHolder(SnippetArticle article, SuggestionsCategoryInfo categoryInfo) { super.onBindViewHolder(); // No longer listen for offline status changes to the old article. if (mArticle != null) mArticle.setOfflineStatusChangeRunnable(null); mArticle = article; + mCategoryInfo = categoryInfo; updateLayout(); mHeadlineTextView.setText(mArticle.mTitle);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerViewTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerViewTest.java index 2c5ecad..fba2acfc 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerViewTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerViewTest.java
@@ -117,7 +117,7 @@ // Scroll the last suggestion into view and click it. SnippetArticle suggestion = suggestions.get(suggestions.size() - 1); - int suggestionPosition = getAdapter().getSuggestionPosition(suggestion); + int suggestionPosition = getSuggestionPosition(suggestion); scrollToPosition(suggestionPosition); final View suggestionView = waitForView(suggestionPosition); ChromeTabUtils.waitForTabPageLoaded(mTab, new Runnable() { @@ -135,12 +135,13 @@ public void testAllDismissed() throws InterruptedException, TimeoutException { setSuggestionsAndWaitForUpdate(3); assertEquals(3, mSource.getSuggestionsForCategory(KnownCategories.ARTICLES).size()); - assertFalse(getAdapter().hasAllBeenDismissed()); + assertEquals(RecyclerView.NO_POSITION, + getAdapter().getFirstPositionForType(ItemViewType.ALL_DISMISSED)); assertEquals(1, mSource.getCategories().length); assertEquals(KnownCategories.ARTICLES, mSource.getCategories()[0]); // Dismiss the sign in promo. - int signinPromoPosition = getAdapter().getSignInPromoPosition(); + int signinPromoPosition = getAdapter().getFirstPositionForType(ItemViewType.PROMO); scrollToPosition(signinPromoPosition); View signinPromoView = waitForView(signinPromoPosition); getAdapter().dismissItem(signinPromoPosition); @@ -155,11 +156,11 @@ waitForViewToDetach(cardView); cardPosition = getAdapter().getFirstCardPosition(); } - assertTrue(getAdapter().hasAllBeenDismissed()); assertEquals(0, mSource.getCategories().length); // Click the refresh button on the all dismissed item. - int allDismissedPosition = getAdapter().getLastContentItemPosition(); + int allDismissedPosition = getAdapter().getFirstPositionForType(ItemViewType.ALL_DISMISSED); + assertTrue(allDismissedPosition != RecyclerView.NO_POSITION); scrollToPosition(allDismissedPosition); View allDismissedView = waitForView(allDismissedPosition); singleClickView(allDismissedView.findViewById(R.id.action_button)); @@ -178,8 +179,7 @@ assertEquals(10, suggestions.size()); // Scroll a suggestion into view. - int suggestionPosition = - getAdapter().getSuggestionPosition(suggestions.get(suggestions.size() - 1)); + int suggestionPosition = getSuggestionPosition(suggestions.get(suggestions.size() - 1)); scrollToPosition(suggestionPosition); View suggestionView = waitForView(suggestionPosition); @@ -246,6 +246,15 @@ return getRecyclerView().getNewTabPageAdapter(); } + private int getSuggestionPosition(SnippetArticle article) { + NewTabPageAdapter adapter = getAdapter(); + for (int i = 0; i < adapter.getItemCount(); i++) { + SnippetArticle articleToCheck = adapter.getSuggestionAt(i); + if (articleToCheck != null && articleToCheck.equals(article)) return i; + } + return RecyclerView.NO_POSITION; + } + private void scrollToPosition(final int position) { final NewTabPageRecyclerView recyclerView = getRecyclerView();
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java index fc6b73b..6ada280c 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java
@@ -6,10 +6,10 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; @@ -74,10 +74,12 @@ private FakeSuggestionsSource mSource; private NewTabPageAdapter mAdapter; + @Mock private SigninManager mMockSigninManager; @Mock private OfflinePageBridge mOfflinePageBridge; - @Mock private NewTabPageManager mNewTabPageManager; + @Mock + private NewTabPageManager mNewTabPageManager; /** * Stores information about a section that should be present in the adapter. @@ -109,19 +111,19 @@ * expressed as a sequence of calls to the {@link #expect} methods. */ private static class ItemsMatcher { // TODO(pke): Find better name. - private final NewTabPageAdapter mAdapter; + private final TreeNode mTreeNode; private int mCurrentIndex; - public ItemsMatcher(NewTabPageAdapter adapter, int startingIndex) { - mAdapter = adapter; - mCurrentIndex = startingIndex; + public ItemsMatcher(TreeNode root) { + mTreeNode = root; } public void expect(@ItemViewType int expectedItemType) { - if (mCurrentIndex >= mAdapter.getItemCount()) { + if (mCurrentIndex >= mTreeNode.getItemCount()) { fail("Expected item of type " + expectedItemType + " but encountered end of list"); } - @ItemViewType int itemType = mAdapter.getItemViewType(mCurrentIndex); + @ItemViewType + int itemType = mTreeNode.getItemViewType(mCurrentIndex); assertEquals("Type mismatch at position " + mCurrentIndex, expectedItemType, itemType); mCurrentIndex++; } @@ -146,65 +148,11 @@ } } - public void expectPosition(int expectedPosition) { - assertEquals(expectedPosition, mCurrentIndex); + public void expectEnd() { + assertEquals(mTreeNode.getItemCount(), mCurrentIndex); } } - /** - * Asserts that the given {@link TreeNode} is a {@link SuggestionsSection} that matches the - * given {@link SectionDescriptor}. - * @param descriptor The section descriptor to match against. - * @param node The node from the adapter. - */ - private void assertMatches(SectionDescriptor descriptor, TreeNode node) { - int offset = mAdapter.getChildPositionOffset(node); - ItemsMatcher matcher = new ItemsMatcher(mAdapter, offset); - matcher.expect(descriptor); - matcher.expectPosition(offset + node.getItemCount()); - } - - /** - * Asserts that {@link #mAdapter}.{@link NewTabPageAdapter#getItemCount()} corresponds to an - * NTP with the given sections in it. - * @param descriptors A list of descriptors, each describing a section that should be present on - * the UI. - */ - private void assertItemsFor(SectionDescriptor... descriptors) { - ItemsMatcher matcher = new ItemsMatcher(mAdapter, 0); - matcher.expect(ItemViewType.ABOVE_THE_FOLD); - for (SectionDescriptor descriptor : descriptors) matcher.expect(descriptor); - if (descriptors.length == 0) { - matcher.expect(ItemViewType.ALL_DISMISSED); - } else { - matcher.expect(ItemViewType.FOOTER); - } - matcher.expect(ItemViewType.SPACING); - matcher.expectPosition(mAdapter.getItemCount()); - } - - /** - * To be used with {@link #assertItemsFor(SectionDescriptor...)}, for a section with - * {@code numSuggestions} cards in it. - * @param numSuggestions The number of suggestions in the section. If there are zero, use either - * no section at all (if it is not displayed) or - * {@link #sectionWithStatusCard()}. - * @return A descriptor for the section. - */ - private SectionDescriptor section(int numSuggestions) { - assert numSuggestions > 0; - return new SectionDescriptor(numSuggestions); - } - - /** - * To be used with {@link #assertItemsFor(SectionDescriptor...)}, for a section that has no - * suggestions, but a status card to be displayed. - * @return A descriptor for the section. - */ - private SectionDescriptor sectionWithStatusCard() { - return new SectionDescriptor(0); - } - @Before public void setUp() { MockitoAnnotations.initMocks(this); @@ -212,7 +160,6 @@ // Initialise the sign in state. We will be signed in by default in the tests. assertFalse(ChromePreferenceManager.getInstance(RuntimeEnvironment.application) .getNewTabPageSigninPromoDismissed()); - mMockSigninManager = mock(SigninManager.class); SigninManager.setInstanceForTesting(mMockSigninManager); when(mMockSigninManager.isSignedInOnNative()).thenReturn(true); when(mMockSigninManager.isSignInAllowed()).thenReturn(true); @@ -230,7 +177,7 @@ when(mNewTabPageManager.getSuggestionsSource()).thenReturn(mSource); when(mNewTabPageManager.isCurrentPage()).thenReturn(true); - mAdapter = new NewTabPageAdapter(mNewTabPageManager, null, null, mOfflinePageBridge); + reloadNtp(); } @After @@ -361,8 +308,7 @@ @Test @Feature({"Ntp"}) public void testProgressIndicatorDisplay() { - int progressPos = mAdapter.getFirstPositionForType(ItemViewType.FOOTER) - 1; - SuggestionsSection section = mAdapter.getSuggestionsSection(progressPos); + SuggestionsSection section = mAdapter.getSectionForTesting(KnownCategories.ARTICLES); ProgressItem progress = section.getProgressItemForTesting(); mSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.INITIALIZING); @@ -395,20 +341,19 @@ assertItemsFor(); // Same when loading a new NTP. - mAdapter = new NewTabPageAdapter(mNewTabPageManager, null, null, mOfflinePageBridge); + reloadNtp(); assertItemsFor(); // Same for CATEGORY_EXPLICITLY_DISABLED. mSource.setStatusForCategory(KnownCategories.ARTICLES, CategoryStatus.AVAILABLE); mSource.setSuggestionsForCategory(KnownCategories.ARTICLES, snippets); - mAdapter = new NewTabPageAdapter(mNewTabPageManager, null, null, mOfflinePageBridge); + reloadNtp(); assertItemsFor(section(5)); mSource.setStatusForCategory( KnownCategories.ARTICLES, CategoryStatus.CATEGORY_EXPLICITLY_DISABLED); assertItemsFor(); - // Same when loading a new NTP. - mAdapter = new NewTabPageAdapter(mNewTabPageManager, null, null, mOfflinePageBridge); + reloadNtp(); assertItemsFor(); } @@ -428,8 +373,7 @@ mSource.silentlyRemoveCategory(KnownCategories.ARTICLES); assertItemsFor(section(4)); - // But it disappears when loading a new NTP. - mAdapter = new NewTabPageAdapter(mNewTabPageManager, null, null, mOfflinePageBridge); + reloadNtp(); assertItemsFor(); } @@ -439,31 +383,27 @@ public void testSectionVisibleIfEmpty() { @CategoryInt final int category = 42; - final int sectionIdx = 1; // section 0 is the above-the-fold item, we test the one after. - final List<SnippetArticle> articles = - Collections.unmodifiableList(createDummySuggestions(3)); - FakeSuggestionsSource suggestionsSource; // Part 1: VisibleIfEmpty = true - suggestionsSource = new FakeSuggestionsSource(); + FakeSuggestionsSource suggestionsSource = new FakeSuggestionsSource(); suggestionsSource.setStatusForCategory(category, CategoryStatus.INITIALIZING); suggestionsSource.setInfoForCategory(category, new CategoryInfoBuilder(category).showIfEmpty().build()); // 1.1 - Initial state when(mNewTabPageManager.getSuggestionsSource()).thenReturn(suggestionsSource); - mAdapter = new NewTabPageAdapter(mNewTabPageManager, null, null, mOfflinePageBridge); + reloadNtp(); assertItemsFor(sectionWithStatusCard().withProgress()); // 1.2 - With suggestions + List<SnippetArticle> articles = Collections.unmodifiableList(createDummySuggestions(3)); suggestionsSource.setStatusForCategory(category, CategoryStatus.AVAILABLE); suggestionsSource.setSuggestionsForCategory(category, articles); assertItemsFor(section(3)); // 1.3 - When all suggestions are dismissed - assertEquals(SuggestionsSection.class, mAdapter.getChildren().get(sectionIdx).getClass()); - SuggestionsSection section42 = (SuggestionsSection) mAdapter.getChildren().get(sectionIdx); - assertMatches(section(3), section42); + SuggestionsSection section42 = mAdapter.getSectionForTesting(category); + assertSectionMatches(section(3), section42); section42.removeSuggestion(articles.get(0)); section42.removeSuggestion(articles.get(1)); section42.removeSuggestion(articles.get(2)); @@ -476,7 +416,7 @@ // 2.1 - Initial state when(mNewTabPageManager.getSuggestionsSource()).thenReturn(suggestionsSource); - mAdapter = new NewTabPageAdapter(mNewTabPageManager, null, null, mOfflinePageBridge); + reloadNtp(); assertItemsFor(); // 2.2 - With suggestions @@ -495,14 +435,9 @@ public void testMoreButton() { @CategoryInt final int category = 42; - final int sectionIdx = 1; // section 0 is the above the fold, we test the one after. - final List<SnippetArticle> articles = - Collections.unmodifiableList(createDummySuggestions(3)); - FakeSuggestionsSource suggestionsSource; - SuggestionsSection section42; // Part 1: With "View All" action - suggestionsSource = new FakeSuggestionsSource(); + FakeSuggestionsSource suggestionsSource = new FakeSuggestionsSource(); suggestionsSource.setStatusForCategory(category, CategoryStatus.INITIALIZING); suggestionsSource.setInfoForCategory(category, new CategoryInfoBuilder(category) .withViewAllAction() @@ -511,18 +446,18 @@ // 1.1 - Initial state. when(mNewTabPageManager.getSuggestionsSource()).thenReturn(suggestionsSource); - mAdapter = new NewTabPageAdapter(mNewTabPageManager, null, null, mOfflinePageBridge); + reloadNtp(); assertItemsFor(sectionWithStatusCard().withActionButton().withProgress()); // 1.2 - With suggestions. + List<SnippetArticle> articles = Collections.unmodifiableList(createDummySuggestions(3)); suggestionsSource.setStatusForCategory(category, CategoryStatus.AVAILABLE); suggestionsSource.setSuggestionsForCategory(category, articles); assertItemsFor(section(3).withActionButton()); // 1.3 - When all suggestions are dismissed. - assertEquals(SuggestionsSection.class, mAdapter.getChildren().get(sectionIdx).getClass()); - section42 = (SuggestionsSection) mAdapter.getChildren().get(sectionIdx); - assertMatches(section(3).withActionButton(), section42); + SuggestionsSection section42 = mAdapter.getSectionForTesting(category); + assertSectionMatches(section(3).withActionButton(), section42); section42.removeSuggestion(articles.get(0)); section42.removeSuggestion(articles.get(1)); section42.removeSuggestion(articles.get(2)); @@ -536,7 +471,7 @@ // 2.1 - Initial state. when(mNewTabPageManager.getSuggestionsSource()).thenReturn(suggestionsSource); - mAdapter = new NewTabPageAdapter(mNewTabPageManager, null, null, mOfflinePageBridge); + reloadNtp(); assertItemsFor(sectionWithStatusCard().withProgress()); // 2.2 - With suggestions. @@ -545,22 +480,14 @@ assertItemsFor(section(3)); // 2.3 - When all suggestions are dismissed. - assertEquals(SuggestionsSection.class, mAdapter.getChildren().get(sectionIdx).getClass()); - section42 = (SuggestionsSection) mAdapter.getChildren().get(sectionIdx); - assertMatches(section(3), section42); + section42 = mAdapter.getSectionForTesting(category); + assertSectionMatches(section(3), section42); section42.removeSuggestion(articles.get(0)); section42.removeSuggestion(articles.get(1)); section42.removeSuggestion(articles.get(2)); assertItemsFor(sectionWithStatusCard()); } - private void assertArticlesEqual(List<SnippetArticle> articles, int start, int end) { - assertThat(mAdapter.getItemCount(), greaterThanOrEqualTo(end)); - for (int i = start; i < end; i++) { - assertEquals(articles.get(i - start), mAdapter.getSuggestionAt(i)); - } - } - /** * Tests that invalidated suggestions are immediately removed. */ @@ -596,8 +523,7 @@ .build()); mSource.setStatusForCategory(dynamicCategory1, CategoryStatus.AVAILABLE); mSource.setSuggestionsForCategory(dynamicCategory1, dynamics1); - // Reload - mAdapter = new NewTabPageAdapter(mNewTabPageManager, null, null, mOfflinePageBridge); + reloadNtp(); assertItemsFor(section(3), section(5).withActionButton()); @@ -607,8 +533,7 @@ new CategoryInfoBuilder(dynamicCategory1).build()); mSource.setStatusForCategory(dynamicCategory2, CategoryStatus.AVAILABLE); mSource.setSuggestionsForCategory(dynamicCategory2, dynamics2); - // Reload - mAdapter = new NewTabPageAdapter(mNewTabPageManager, null, null, mOfflinePageBridge); + reloadNtp(); assertItemsFor(section(3), section(5).withActionButton(), section(11)); } @@ -621,16 +546,14 @@ // Above-the-fold, sign in promo, all-dismissed, footer, spacer. final int basicChildCount = 5; FakeSuggestionsSource suggestionsSource = new FakeSuggestionsSource(); + when(mNewTabPageManager.getSuggestionsSource()).thenReturn(suggestionsSource); registerCategory(suggestionsSource, KnownCategories.ARTICLES, 0); registerCategory(suggestionsSource, KnownCategories.BOOKMARKS, 0); registerCategory(suggestionsSource, KnownCategories.PHYSICAL_WEB_PAGES, 0); registerCategory(suggestionsSource, KnownCategories.DOWNLOADS, 0); + reloadNtp(); - when(mNewTabPageManager.getSuggestionsSource()).thenReturn(suggestionsSource); - NewTabPageAdapter ntpAdapter = new NewTabPageAdapter( - mNewTabPageManager, null, null, mOfflinePageBridge); - List<TreeNode> children = ntpAdapter.getChildren(); - + List<TreeNode> children = mAdapter.getRootForTesting().getChildren(); assertEquals(basicChildCount + 4, children.size()); assertEquals(AboveTheFoldItem.class, children.get(0).getClass()); assertEquals(SuggestionsSection.class, children.get(1).getClass()); @@ -644,16 +567,14 @@ // With a different order. suggestionsSource = new FakeSuggestionsSource(); + when(mNewTabPageManager.getSuggestionsSource()).thenReturn(suggestionsSource); registerCategory(suggestionsSource, KnownCategories.ARTICLES, 0); registerCategory(suggestionsSource, KnownCategories.PHYSICAL_WEB_PAGES, 0); registerCategory(suggestionsSource, KnownCategories.DOWNLOADS, 0); registerCategory(suggestionsSource, KnownCategories.BOOKMARKS, 0); + reloadNtp(); - when(mNewTabPageManager.getSuggestionsSource()).thenReturn(suggestionsSource); - ntpAdapter = new NewTabPageAdapter( - mNewTabPageManager, null, null, mOfflinePageBridge); - children = ntpAdapter.getChildren(); - + children = mAdapter.getRootForTesting().getChildren(); assertEquals(basicChildCount + 4, children.size()); assertEquals(AboveTheFoldItem.class, children.get(0).getClass()); assertEquals(SuggestionsSection.class, children.get(1).getClass()); @@ -667,19 +588,17 @@ // With unknown categories. suggestionsSource = new FakeSuggestionsSource(); + when(mNewTabPageManager.getSuggestionsSource()).thenReturn(suggestionsSource); registerCategory(suggestionsSource, KnownCategories.ARTICLES, 0); registerCategory(suggestionsSource, KnownCategories.PHYSICAL_WEB_PAGES, 0); registerCategory(suggestionsSource, KnownCategories.DOWNLOADS, 0); - - when(mNewTabPageManager.getSuggestionsSource()).thenReturn(suggestionsSource); - ntpAdapter = new NewTabPageAdapter(mNewTabPageManager, null, null, mOfflinePageBridge); + reloadNtp(); // The adapter is already initialised, it will not accept new categories anymore. registerCategory(suggestionsSource, 42, 1); registerCategory(suggestionsSource, KnownCategories.BOOKMARKS, 1); - children = ntpAdapter.getChildren(); - + children = mAdapter.getRootForTesting().getChildren(); assertEquals(basicChildCount + 3, children.size()); assertEquals(AboveTheFoldItem.class, children.get(0).getClass()); assertEquals(SuggestionsSection.class, children.get(1).getClass()); @@ -694,16 +613,12 @@ @Feature({"Ntp"}) public void testChangeNotifications() { FakeSuggestionsSource suggestionsSource = spy(new FakeSuggestionsSource()); - // Allow using dismissSuggestion() instead of throwing UnsupportedOperationException. - doNothing().when(suggestionsSource).dismissSuggestion(any(SnippetArticle.class)); - registerCategory(suggestionsSource, KnownCategories.ARTICLES, 3); when(mNewTabPageManager.getSuggestionsSource()).thenReturn(suggestionsSource); - NewTabPageAdapter adapter = new NewTabPageAdapter( - mNewTabPageManager, null, null, mOfflinePageBridge); + + reloadNtp(); AdapterDataObserver dataObserver = mock(AdapterDataObserver.class); - adapter.registerAdapterDataObserver(dataObserver); - reset(dataObserver); // reset notification changes from initialisation. + mAdapter.registerAdapterDataObserver(dataObserver); // Adapter content: // Idx | Item @@ -714,24 +629,26 @@ // 5 | Footer // 6 | Spacer - adapter.dismissItem(3); // Dismiss the second suggestion of the second section. + mAdapter.dismissItem(3); // Dismiss the second suggestion of the second section. verify(dataObserver).onItemRangeRemoved(3, 1); verify(dataObserver).onItemRangeChanged(5, 1, null); // Make sure the call with the updated position works properly. - adapter.dismissItem(3); + mAdapter.dismissItem(3); verify(dataObserver, times(2)).onItemRangeRemoved(3, 1); verify(dataObserver).onItemRangeChanged(4, 1, null); - reset(dataObserver); + verifyNoMoreInteractions(dataObserver); // Dismiss the last suggestion in the section. We should now show the status card. - adapter.dismissItem(2); + reset(dataObserver); + mAdapter.dismissItem(2); verify(dataObserver).onItemRangeRemoved(2, 1); // Suggestion removed verify(dataObserver).onItemRangeChanged(3, 1, null); // Spacer refresh verify(dataObserver).onItemRangeInserted(2, 1); // Status card added verify(dataObserver).onItemRangeChanged(4, 1, null); // Spacer refresh verify(dataObserver).onItemRangeInserted(3, 1); // Action item added verify(dataObserver).onItemRangeChanged(5, 1, null); // Spacer refresh + verifyNoMoreInteractions(dataObserver); // Adapter content: // Idx | Item @@ -748,7 +665,7 @@ reset(dataObserver); suggestionsSource.setSuggestionsForCategory( KnownCategories.ARTICLES, createDummySuggestions(newSuggestionCount)); - adapter.onNewSuggestions(KnownCategories.ARTICLES); + mAdapter.onNewSuggestions(KnownCategories.ARTICLES); verify(dataObserver).onItemRangeInserted(2, newSuggestionCount); verify(dataObserver).onItemRangeChanged(5 + newSuggestionCount, 1, null); // Spacer refresh verify(dataObserver, times(2)).onItemRangeRemoved(2 + newSuggestionCount, 1); @@ -768,13 +685,14 @@ reset(dataObserver); suggestionsSource.setSuggestionsForCategory( KnownCategories.ARTICLES, createDummySuggestions(0)); - adapter.onCategoryStatusChanged(KnownCategories.ARTICLES, CategoryStatus.SIGNED_OUT); + mAdapter.onCategoryStatusChanged(KnownCategories.ARTICLES, CategoryStatus.SIGNED_OUT); verify(dataObserver).onItemRangeRemoved(2, newSuggestionCount); verify(dataObserver).onItemRangeChanged(3, 1, null); // Spacer refresh verify(dataObserver).onItemRangeInserted(2, 1); // Status card added verify(dataObserver).onItemRangeChanged(4, 1, null); // Spacer refresh verify(dataObserver).onItemRangeInserted(3, 1); // Action item added verify(dataObserver).onItemRangeChanged(5, 1, null); // Spacer refresh + verifyNoMoreInteractions(dataObserver); } @Test @@ -787,27 +705,8 @@ doNothing().when(mNewTabPageManager).addDestructionObserver(observers.capture()); - NewTabPageAdapter adapter = - new NewTabPageAdapter(mNewTabPageManager, null, null, mOfflinePageBridge); - - TreeNode signinPromo = adapter.getChildren().get(2); - - // Adapter content: - // Idx | Item | Item Index - // ----|--------------------|------------- - // 0 | Above-the-fold | 0 - // 1 | Header | 1 - // 2 | Status | 1 - // 3 | Action | 1 - // 4 | Progress Indicator | 1 - // 5 | Sign in promo | 2 - // 6 | Footer | 3 - // 7 | Spacer | 4 - - assertEquals(1, signinPromo.getItemCount()); - assertEquals(ItemViewType.PROMO, signinPromo.getItemViewType(0)); - - // verify(mNewTabPageManager).addDestructionObserver(observers.capture()); + reloadNtp(); + assertTrue(isSignInPromoVisible()); // Note: As currently implemented, these two variables should point to the same object, a // SignInPromo.SigninObserver @@ -823,18 +722,18 @@ } signInStateObserver.onSignedIn(); - assertEquals(0, signinPromo.getItemCount()); + assertFalse(isSignInPromoVisible()); signInStateObserver.onSignedOut(); - assertEquals(1, signinPromo.getItemCount()); + assertTrue(isSignInPromoVisible()); when(mMockSigninManager.isSignInAllowed()).thenReturn(false); signInAllowedObserver.onSignInAllowedChanged(); - assertEquals(0, signinPromo.getItemCount()); + assertFalse(isSignInPromoVisible()); when(mMockSigninManager.isSignInAllowed()).thenReturn(true); signInAllowedObserver.onSignInAllowedChanged(); - assertEquals(1, signinPromo.getItemCount()); + assertTrue(isSignInPromoVisible()); } @Test @@ -844,38 +743,18 @@ when(mMockSigninManager.isSignedInOnNative()).thenReturn(false); ChromePreferenceManager.getInstance(RuntimeEnvironment.application) .setNewTabPageSigninPromoDismissed(false); + reloadNtp(); - NewTabPageAdapter adapter = - new NewTabPageAdapter(mNewTabPageManager, null, null, mOfflinePageBridge); - final int signInPromoIndex = adapter.getFirstPositionForType(ItemViewType.PROMO); + final int signInPromoPosition = mAdapter.getFirstPositionForType(ItemViewType.PROMO); + assertNotEquals(RecyclerView.NO_POSITION, signInPromoPosition); + mAdapter.dismissItem(signInPromoPosition); - assertEquals(6, adapter.getChildren().size()); - TreeNode signinPromo = adapter.getChildren().get(2); - - // Adapter content: - // Idx | Item | Item Index - // ----|--------------------|------------- - // 0 | Above-the-fold | 0 - // 1 | Header | 1 - // 2 | Status | 1 - // 3 | Action | 1 - // 4 | Progress Indicator | 1 - // 5 | Sign in promo | 2 - // 6 | All dismissed | 3 - // 7 | Footer | 4 - // 8 | Spacer | 5 - - assertEquals(ItemViewType.PROMO, signinPromo.getItemViewType(0)); - - adapter.dismissItem(signInPromoIndex); - assertEquals(0, signinPromo.getItemCount()); + assertFalse(isSignInPromoVisible()); assertTrue(ChromePreferenceManager.getInstance(RuntimeEnvironment.application) .getNewTabPageSigninPromoDismissed()); - adapter = new NewTabPageAdapter(mNewTabPageManager, null, null, mOfflinePageBridge); - assertEquals(6, adapter.getChildren().size()); - // The items below the signin promo move up, footer is now at the position of the promo. - assertEquals(ItemViewType.FOOTER, adapter.getItemViewType(signInPromoIndex)); + reloadNtp(); + assertFalse(isSignInPromoVisible()); } @Test @@ -987,6 +866,75 @@ mAdapter.getFirstPositionForType(ItemViewType.ALL_DISMISSED)); } + /** + * Asserts that the given {@link TreeNode} is a {@link SuggestionsSection} that matches the + * given {@link SectionDescriptor}. + * @param descriptor The section descriptor to match against. + * @param section The section from the adapter. + */ + private void assertSectionMatches(SectionDescriptor descriptor, SuggestionsSection section) { + ItemsMatcher matcher = new ItemsMatcher(section); + matcher.expect(descriptor); + matcher.expectEnd(); + } + + /** + * Asserts that {@link #mAdapter}.{@link NewTabPageAdapter#getItemCount()} corresponds to an NTP + * with the given sections in it. + * + * @param descriptors A list of descriptors, each describing a section that should be present on + * the UI. + */ + private void assertItemsFor(SectionDescriptor... descriptors) { + ItemsMatcher matcher = new ItemsMatcher(mAdapter.getRootForTesting()); + matcher.expect(ItemViewType.ABOVE_THE_FOLD); + for (SectionDescriptor descriptor : descriptors) matcher.expect(descriptor); + if (descriptors.length == 0) { + matcher.expect(ItemViewType.ALL_DISMISSED); + } else { + matcher.expect(ItemViewType.FOOTER); + } + matcher.expect(ItemViewType.SPACING); + matcher.expectEnd(); + } + + /** + * To be used with {@link #assertItemsFor(SectionDescriptor...)}, for a section with + * {@code numSuggestions} cards in it. + * @param numSuggestions The number of suggestions in the section. If there are zero, use either + * no section at all (if it is not displayed) or + * {@link #sectionWithStatusCard()}. + * @return A descriptor for the section. + */ + private SectionDescriptor section(int numSuggestions) { + assert numSuggestions > 0; + return new SectionDescriptor(numSuggestions); + } + + /** + * To be used with {@link #assertItemsFor(SectionDescriptor...)}, for a section that has no + * suggestions, but a status card to be displayed. + * @return A descriptor for the section. + */ + private SectionDescriptor sectionWithStatusCard() { + return new SectionDescriptor(0); + } + + private void reloadNtp() { + mAdapter = new NewTabPageAdapter(mNewTabPageManager, null, null, mOfflinePageBridge); + } + + private void assertArticlesEqual(List<SnippetArticle> articles, int start, int end) { + assertThat(mAdapter.getItemCount(), greaterThanOrEqualTo(end)); + for (int i = start; i < end; i++) { + assertEquals(articles.get(i - start), mAdapter.getSuggestionAt(i)); + } + } + + private boolean isSignInPromoVisible() { + return mAdapter.getFirstPositionForType(ItemViewType.PROMO) != RecyclerView.NO_POSITION; + } + /** Registers the category with the reload action */ private void registerCategory(FakeSuggestionsSource suggestionsSource, @CategoryInt int category, int suggestionCount) {
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/ManifestUpgradeDetectorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/ManifestUpgradeDetectorTest.java index 2fc7f262..a580c472 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/ManifestUpgradeDetectorTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/ManifestUpgradeDetectorTest.java
@@ -5,8 +5,10 @@ package org.chromium.chrome.browser.webapps; import android.content.Context; +import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Color; +import android.os.Bundle; import android.text.TextUtils; import org.junit.Assert; @@ -24,6 +26,8 @@ import org.chromium.chrome.browser.tab.Tab; import org.chromium.content_public.common.ScreenOrientationValues; import org.chromium.testing.local.LocalRobolectricTestRunner; +import org.chromium.webapk.lib.common.WebApkMetaDataKeys; +import org.chromium.webapk.test.WebApkTestHelper; import java.util.HashMap; import java.util.Map; @@ -41,8 +45,8 @@ private static final String WEBAPK_SHORT_NAME = "Short Name"; private static final String WEBAPK_BEST_ICON_URL = "/icon.png"; private static final String WEBAPK_BEST_ICON_MURMUR2_HASH = "3"; - private static final int WEBAPK_DISPLAY_MODE = WebDisplayMode.Standalone; - private static final int WEBAPK_ORIENTATION = ScreenOrientationValues.LANDSCAPE; + private static final int WEBAPK_DISPLAY_MODE = WebDisplayMode.Undefined; + private static final int WEBAPK_ORIENTATION = ScreenOrientationValues.DEFAULT; private static final long WEBAPK_THEME_COLOR = 1L; private static final long WEBAPK_BACKGROUND_COLOR = 2L; private static final String WEBAPK_MANIFEST_URL = "manifest.json"; @@ -175,43 +179,69 @@ WEBAPK_MANIFEST_URL, manifestData.startUrl, manifestData.iconUrlToMurmur2HashMap); } - private static TestManifestUpgradeDetector createDetectorWithFetchedData( - ManifestData fetchedData, TestCallback callback) { - return createDetector(defaultManifestData(), fetchedData, callback); + /** + * Checks whether the WebAPK is updated given data from the WebAPK's Android Manifest and data + * from the fetched Web Manifest. This function uses the intent version of + * {@link WebApkInfo#create()} in order to test default values set by the intent version of + * {@link WebApkInfo#create()} and how the defaults affect whether the WebAPK is updated. + */ + private boolean checkUpdateNeededForFetchedManifest( + ManifestData androidManifestData, ManifestData fetchedManifestData) { + registerWebApk(androidManifestData); + + Intent intent = new Intent(); + intent.putExtra(ShortcutHelper.EXTRA_URL, ""); + intent.putExtra( + ShortcutHelper.EXTRA_WEBAPK_PACKAGE_NAME, WebApkTestHelper.WEBAPK_PACKAGE_NAME); + WebApkInfo androidManifestInfo = WebApkInfo.create(intent); + + TestCallback callback = new TestCallback(); + TestManifestUpgradeDetector detector = + new TestManifestUpgradeDetector(androidManifestInfo, fetchedManifestData, callback); + detector.start(); + Assert.assertTrue(callback.mWasCalled); + return callback.mIsUpgraded; } /** - * Creates ManifestUpgradeDetector. - * @param oldData Data used to create WebAPK. Potentially different from Web Manifest data at - * time that the WebAPK was generated. - * @param fetchedData Data fetched by ManifestUpgradeDetector. - * @param callback Callback to call when the upgrade check is complete. + * Registers WebAPK with default package name. Overwrites previous registrations. + * @param manifestData <meta-data> values for WebAPK's Android Manifest. */ - private static TestManifestUpgradeDetector createDetector( - ManifestData oldData, ManifestData fetchedData, TestCallback callback) { - return new TestManifestUpgradeDetector( - infoFromManifestData(oldData), fetchedData, callback); + private void registerWebApk(ManifestData manifestData) { + Bundle metaData = new Bundle(); + metaData.putString(WebApkMetaDataKeys.START_URL, manifestData.startUrl); + metaData.putString(WebApkMetaDataKeys.SCOPE, manifestData.scopeUrl); + metaData.putString(WebApkMetaDataKeys.NAME, manifestData.name); + metaData.putString(WebApkMetaDataKeys.SHORT_NAME, manifestData.shortName); + metaData.putString(WebApkMetaDataKeys.THEME_COLOR, manifestData.themeColor + "L"); + metaData.putString(WebApkMetaDataKeys.BACKGROUND_COLOR, manifestData.backgroundColor + "L"); + metaData.putString(WebApkMetaDataKeys.WEB_MANIFEST_URL, WEBAPK_MANIFEST_URL); + + String iconUrlsAndIconMurmur2Hashes = ""; + for (String iconUrl : manifestData.iconUrlToMurmur2HashMap.keySet()) { + String murmur2Hash = manifestData.iconUrlToMurmur2HashMap.get(iconUrl); + if (murmur2Hash == null) { + murmur2Hash = "0"; + } + iconUrlsAndIconMurmur2Hashes += " " + iconUrl + " " + murmur2Hash; + } + iconUrlsAndIconMurmur2Hashes = iconUrlsAndIconMurmur2Hashes.trim(); + metaData.putString(WebApkMetaDataKeys.ICON_URLS_AND_ICON_MURMUR2_HASHES, + iconUrlsAndIconMurmur2Hashes); + WebApkTestHelper.registerWebApkWithMetaData(metaData); } @Test public void testManifestDoesNotUpgrade() { - TestCallback callback = new TestCallback(); - TestManifestUpgradeDetector detector = - createDetectorWithFetchedData(defaultManifestData(), callback); - detector.start(); - Assert.assertTrue(callback.mWasCalled); - Assert.assertFalse(callback.mIsUpgraded); + Assert.assertFalse( + checkUpdateNeededForFetchedManifest(defaultManifestData(), defaultManifestData())); } @Test public void testStartUrlChangeShouldUpgrade() { ManifestData fetchedData = defaultManifestData(); fetchedData.startUrl = "/changed.html"; - TestCallback callback = new TestCallback(); - TestManifestUpgradeDetector detector = createDetectorWithFetchedData(fetchedData, callback); - detector.start(); - Assert.assertTrue(callback.mWasCalled); - Assert.assertTrue(callback.mIsUpgraded); + Assert.assertTrue(checkUpdateNeededForFetchedManifest(defaultManifestData(), fetchedData)); } /** @@ -226,12 +256,7 @@ ManifestData fetchedData = defaultManifestData(); fetchedData.scopeUrl = ""; Assert.assertTrue(!oldData.scopeUrl.equals(fetchedData.scopeUrl)); - - TestCallback callback = new TestCallback(); - TestManifestUpgradeDetector detector = createDetector(oldData, fetchedData, callback); - detector.start(); - Assert.assertTrue(callback.mWasCalled); - Assert.assertFalse(callback.mIsUpgraded); + Assert.assertFalse(checkUpdateNeededForFetchedManifest(oldData, fetchedData)); } /** @@ -249,11 +274,7 @@ fetchedData.startUrl = "/fancy/scope/special/snowflake.html"; fetchedData.scopeUrl = ""; - TestCallback callback = new TestCallback(); - TestManifestUpgradeDetector detector = createDetector(oldData, fetchedData, callback); - detector.start(); - Assert.assertTrue(callback.mWasCalled); - Assert.assertTrue(callback.mIsUpgraded); + Assert.assertTrue(checkUpdateNeededForFetchedManifest(oldData, fetchedData)); } /** @@ -267,12 +288,7 @@ fetchedData.iconUrlToMurmur2HashMap.put(fetchedData.bestIconUrl, WEBAPK_BEST_ICON_MURMUR2_HASH + "1"); fetchedData.bestIcon = createBitmap(Color.BLUE); - TestCallback callback = new TestCallback(); - TestManifestUpgradeDetector detector = createDetectorWithFetchedData(fetchedData, callback); - - detector.start(); - Assert.assertTrue(callback.mWasCalled); - Assert.assertTrue(callback.mIsUpgraded); + Assert.assertTrue(checkUpdateNeededForFetchedManifest(defaultManifestData(), fetchedData)); } /** @@ -286,12 +302,7 @@ fetchedData.iconUrlToMurmur2HashMap.clear(); fetchedData.iconUrlToMurmur2HashMap.put("/icon2.png", "22"); fetchedData.bestIconUrl = "/icon2.png"; - - TestCallback callback = new TestCallback(); - TestManifestUpgradeDetector detector = createDetectorWithFetchedData(fetchedData, callback); - detector.start(); - Assert.assertTrue(callback.mWasCalled); - Assert.assertTrue(callback.mIsUpgraded); + Assert.assertTrue(checkUpdateNeededForFetchedManifest(defaultManifestData(), fetchedData)); } /** @@ -307,12 +318,7 @@ fetchedData.iconUrlToMurmur2HashMap.put( WEBAPK_BEST_ICON_URL, WEBAPK_BEST_ICON_MURMUR2_HASH); fetchedData.iconUrlToMurmur2HashMap.put("/icon2.png", null); - - TestCallback callback = new TestCallback(); - TestManifestUpgradeDetector detector = createDetectorWithFetchedData(fetchedData, callback); - detector.start(); - Assert.assertTrue(callback.mWasCalled); - Assert.assertFalse(callback.mIsUpgraded); + Assert.assertFalse(checkUpdateNeededForFetchedManifest(defaultManifestData(), fetchedData)); } /** @@ -342,10 +348,6 @@ fetchedData.iconUrlToMurmur2HashMap.put(iconUrl1, null); fetchedData.iconUrlToMurmur2HashMap.put(iconUrl2, hash2); - TestCallback callback = new TestCallback(); - TestManifestUpgradeDetector detector = createDetector(oldData, fetchedData, callback); - detector.start(); - Assert.assertTrue(callback.mWasCalled); - Assert.assertFalse(callback.mIsUpgraded); + Assert.assertFalse(checkUpdateNeededForFetchedManifest(oldData, fetchedData)); } }
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index f24005e..1862fa59 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -11249,6 +11249,7 @@ You're now signed in to Chrome </message> + <!-- "Chrome sync" is the Google Cloud Based service used for sync. Thus this string resource is set to "Chrome sync" even for Chromium builds. --> <message name="IDS_SYNC_CONFIRMATION_CHROME_SYNC_TITLE" desc="Title of the chrome sync section of the sync confirmation dialog in the tab modal signin flow" formatter_data="android_java"> Chrome Sync </message> @@ -15550,6 +15551,14 @@ Disable video tracks when the video is played in the background to optimize performance. </message> + <!-- Video fullscreen with orientation lock experiment strings. --> + <message name="IDS_FLAGS_VIDEO_FULLSCREEN_ORIENTATION_LOCK_NAME" desc="Name of the flag for enabling orientation lock for fullscreen video playback."> + Lock screen orientation when playing a video fullscreen. + </message> + <message name="IDS_FLAGS_VIDEO_FULLSCREEN_ORIENTATION_LOCK_DESCRIPTION" desc="Description of the flag for enabling orientation lock for fullscreen video playback."> + Lock the screen orientation of the device to match video orientation when a video goes fullscreen. + </message> + <if expr="is_win"> <message name="IDS_UTILITY_PROCESS_SHELL_HANDLER_NAME" desc="The name of the utility process used to handle shell operations."> Shell Handler
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 9b90b53d..5ddcfae 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -384,6 +384,8 @@ "favicon/favicon_utils.h", "favicon/large_icon_service_factory.cc", "favicon/large_icon_service_factory.h", + "features.cc", + "features.h", "file_select_helper.cc", "file_select_helper.h", "file_select_helper_mac.mm",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index d7725b1..daeeff6 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -2103,6 +2103,12 @@ IDS_FLAGS_MEDIA_REMOTING_ENCRYPTED_DESCRIPTION, kOsDesktop, FEATURE_VALUE_TYPE(features::kMediaRemotingEncrypted)}, #endif +#if defined(OS_ANDROID) + {"video-fullscreen-orientation-lock", + IDS_FLAGS_VIDEO_FULLSCREEN_ORIENTATION_LOCK_NAME, + IDS_FLAGS_VIDEO_FULLSCREEN_ORIENTATION_LOCK_DESCRIPTION, kOsAndroid, + FEATURE_VALUE_TYPE(media::kVideoFullscreenOrientationLock)}, +#endif // NOTE: Adding new command-line switches requires adding corresponding // entries to enum "LoginCustomFlags" in histograms.xml. See note in
diff --git a/chrome/browser/chrome_browser_field_trials_desktop.cc b/chrome/browser/chrome_browser_field_trials_desktop.cc index 1901825d0..6ebdc45f 100644 --- a/chrome/browser/chrome_browser_field_trials_desktop.cc +++ b/chrome/browser/chrome_browser_field_trials_desktop.cc
@@ -14,6 +14,7 @@ #include "base/metrics/field_trial.h" #include "base/metrics/histogram_macros.h" #include "base/path_service.h" +#include "chrome/browser/features.h" #include "chrome/browser/prerender/prerender_field_trial.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_switches.h" @@ -112,6 +113,12 @@ #if defined(OS_WIN) SetupStabilityDebugging(); #endif // defined(OS_WIN) + // Activate the experiment as early as possible to increase its visibility + // (e.g. the likelihood of its presence in the serialized system profile). + // This also needs to happen before the browser rendez-vous attempt + // (NotifyOtherProcessOrCreate) in PreMainMessageLoopRun so the corresponding + // metrics are tagged. + base::FeatureList::IsEnabled(features::kDesktopFastShutdown); } } // namespace chrome
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc index a9aaea8..1bcc099 100644 --- a/chrome/browser/chrome_browser_main.cc +++ b/chrome/browser/chrome_browser_main.cc
@@ -176,7 +176,9 @@ #include "chrome/browser/metrics/thread_watcher_android.h" #include "ui/base/resource/resource_bundle_android.h" #else +#include "chrome/browser/features.h" #include "chrome/browser/feedback/feedback_profile_observer.h" +#include "chrome/browser/lifetime/application_lifetime.h" #endif // defined(OS_ANDROID) #if defined(OS_LINUX) && !defined(OS_CHROMEOS) @@ -1982,6 +1984,12 @@ g_browser_process->local_state()); run_loop.Run(); + if (base::FeatureList::IsEnabled(features::kDesktopFastShutdown)) { + // Experiment to determine the impact of always taking the quick exit path. + // There is no returning from this call as it terminates the process. + chrome::SessionEnding(); + } + return true; #endif // defined(OS_ANDROID) }
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index 87584d65..aaf9540 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -207,8 +207,6 @@ "app_mode/kiosk_session_plugin_handler_delegate.h", "app_mode/startup_app_launcher.cc", "app_mode/startup_app_launcher.h", - "arc/arc_auth_code_fetcher.cc", - "arc/arc_auth_code_fetcher.h", "arc/arc_auth_context.cc", "arc/arc_auth_context.h", "arc/arc_auth_service.cc", @@ -221,8 +219,13 @@ "arc/arc_session_manager.h", "arc/arc_support_host.cc", "arc/arc_support_host.h", - "arc/auth/arc_robot_auth.cc", - "arc/auth/arc_robot_auth.h", + "arc/auth/arc_auth_code_fetcher.h", + "arc/auth/arc_background_auth_code_fetcher.cc", + "arc/auth/arc_background_auth_code_fetcher.h", + "arc/auth/arc_manual_auth_code_fetcher.cc", + "arc/auth/arc_manual_auth_code_fetcher.h", + "arc/auth/arc_robot_auth_code_fetcher.cc", + "arc/auth/arc_robot_auth_code_fetcher.h", "arc/downloads_watcher/arc_downloads_watcher_service.cc", "arc/downloads_watcher/arc_downloads_watcher_service.h", "arc/enterprise/arc_enterprise_reporting_service.cc",
diff --git a/chrome/browser/chromeos/arc/arc_auth_service.cc b/chrome/browser/chromeos/arc/arc_auth_service.cc index 3fc09a0..218497c0 100644 --- a/chrome/browser/chromeos/arc/arc_auth_service.cc +++ b/chrome/browser/chromeos/arc/arc_auth_service.cc
@@ -4,14 +4,17 @@ #include "chrome/browser/chromeos/arc/arc_auth_service.h" +#include <utility> + #include "base/command_line.h" #include "base/logging.h" #include "base/memory/ptr_util.h" -#include "chrome/browser/chromeos/arc/arc_auth_code_fetcher.h" -#include "chrome/browser/chromeos/arc/arc_optin_uma.h" #include "chrome/browser/chromeos/arc/arc_optin_uma.h" #include "chrome/browser/chromeos/arc/arc_session_manager.h" -#include "chrome/browser/chromeos/arc/auth/arc_robot_auth.h" +#include "chrome/browser/chromeos/arc/auth/arc_auth_code_fetcher.h" +#include "chrome/browser/chromeos/arc/auth/arc_background_auth_code_fetcher.h" +#include "chrome/browser/chromeos/arc/auth/arc_manual_auth_code_fetcher.h" +#include "chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher.h" #include "chrome/browser/chromeos/arc/policy/arc_policy_util.h" #include "chrome/browser/lifetime/application_lifetime.h" #include "chromeos/chromeos_switches.h" @@ -148,12 +151,8 @@ } void ArcAuthService::OnInstanceClosed() { - ArcSupportHost* support_host = ArcSessionManager::Get()->support_host(); - if (support_host) - support_host->RemoveObserver(this); + fetcher_.reset(); notifier_.reset(); - arc_robot_auth_.reset(); - auth_code_fetcher_.reset(); } void ArcAuthService::OnSignInComplete() { @@ -172,6 +171,14 @@ weak_ptr_factory_.GetWeakPtr()))); } +void ArcAuthService::OnAccountInfoReady(mojom::AccountInfoPtr account_info) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + auto* instance = arc_bridge_service()->auth()->GetInstanceForMethod( + "OnAccountInfoReady", kMinVersionForOnAccountInfoReady); + DCHECK(instance); + instance->OnAccountInfoReady(std::move(account_info)); +} + void ArcAuthService::GetAuthCodeDeprecated0( const GetAuthCodeDeprecated0Callback& callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); @@ -205,6 +212,7 @@ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); // No other auth code-related operation may be in progress. DCHECK(!notifier_); + DCHECK(!fetcher_); if (ArcSessionManager::IsOptInVerificationDisabled()) { notifier->Notify( @@ -216,80 +224,30 @@ // Hereafter asynchronous operation. Remember the notifier. notifier_ = std::move(notifier); - // In Kiosk mode, use Robot auth code fetching. if (ArcSessionManager::IsArcKioskMode()) { - arc_robot_auth_.reset(new ArcRobotAuth()); - arc_robot_auth_->FetchRobotAuthCode( - base::Bind(&ArcAuthService::OnRobotAuthCodeFetched, - weak_ptr_factory_.GetWeakPtr())); - return; - } - - // Optionally retrive auth code in silent mode. - if (base::FeatureList::IsEnabled(arc::kArcUseAuthEndpointFeature)) { - DCHECK(!auth_code_fetcher_); - auth_code_fetcher_ = base::MakeUnique<ArcAuthCodeFetcher>( + // In Kiosk mode, use Robot auth code fetching. + fetcher_ = base::MakeUnique<ArcRobotAuthCodeFetcher>(); + } else if (base::FeatureList::IsEnabled(arc::kArcUseAuthEndpointFeature)) { + // Optionally retrieve auth code in silent mode. + fetcher_ = base::MakeUnique<ArcBackgroundAuthCodeFetcher>( ArcSessionManager::Get()->profile(), ArcSessionManager::Get()->auth_context()); - auth_code_fetcher_->Fetch(base::Bind(&ArcAuthService::OnAuthCodeFetched, - weak_ptr_factory_.GetWeakPtr())); - return; - } - - // Otherwise, show LSO page to user after HTTP context preparation, and let - // them click "Sign in" button. - ArcSessionManager::Get()->auth_context()->Prepare(base::Bind( - &ArcAuthService::OnContextPrepared, weak_ptr_factory_.GetWeakPtr())); -} - -void ArcAuthService::OnContextPrepared( - net::URLRequestContextGetter* request_context_getter) { - ArcSupportHost* support_host = ArcSessionManager::Get()->support_host(); - // Here, support_host should be available always. The case support_host is - // not created is when 1) IsOptInVerificationDisabled() is true or 2) - // IsArcKioskMode() is true. Both cases are handled above. - DCHECK(support_host); - if (!support_host->HasObserver(this)) - support_host->AddObserver(this); - - if (request_context_getter) { - support_host->ShowLso(); } else { - support_host->ShowError(ArcSupportHost::Error::SIGN_IN_NETWORK_ERROR, - false); + // Otherwise, show LSO page and let user click "Sign in" button. + // Here, support_host should be available always. The case support_host is + // not created is when 1) IsOptInVerificationDisabled() is true or 2) + // IsArcKioskMode() is true. Both cases are handled above. + fetcher_ = base::MakeUnique<ArcManualAuthCodeFetcher>( + ArcSessionManager::Get()->auth_context(), + ArcSessionManager::Get()->support_host()); } -} - -void ArcAuthService::OnAccountInfoReady(mojom::AccountInfoPtr account_info) { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - auto* instance = arc_bridge_service()->auth()->GetInstanceForMethod( - "OnAccountInfoReady", kMinVersionForOnAccountInfoReady); - DCHECK(instance); - instance->OnAccountInfoReady(std::move(account_info)); -} - -void ArcAuthService::OnRobotAuthCodeFetched( - const std::string& robot_auth_code) { - // We fetching robot auth code for ARC kiosk only. - DCHECK(ArcSessionManager::IsArcKioskMode()); - - // Current instance of ArcRobotAuth became useless. - arc_robot_auth_.reset(); - - if (robot_auth_code.empty()) { - VLOG(1) << "Robot account auth code fetching error"; - // Log out the user. All the cleanup will be done in Shutdown() method. - // The callback is not called because auth code is empty. - chrome::AttemptUserExit(); - return; - } - - OnAuthCodeObtained(robot_auth_code); + fetcher_->Fetch(base::Bind(&ArcAuthService::OnAuthCodeFetched, + weak_ptr_factory_.GetWeakPtr())); } void ArcAuthService::OnAuthCodeFetched(const std::string& auth_code) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - auth_code_fetcher_.reset(); + fetcher_.reset(); if (auth_code.empty()) { ArcSessionManager::Get()->OnProvisioningFinished( @@ -297,13 +255,6 @@ return; } - OnAuthCodeObtained(auth_code); -} - -void ArcAuthService::OnAuthCodeObtained(const std::string& auth_code) { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - DCHECK(!auth_code.empty()); - notifier_->Notify( !ArcSessionManager::IsOptInVerificationDisabled(), auth_code, GetAccountType(), @@ -311,22 +262,4 @@ notifier_.reset(); } -void ArcAuthService::OnAuthSucceeded(const std::string& auth_code) { - OnAuthCodeObtained(auth_code); -} - -void ArcAuthService::OnRetryClicked() { - ArcSupportHost* support_host = ArcSessionManager::Get()->support_host(); - // This is the callback for the UI event, so support_host should be always - // available here. - DCHECK(support_host); - if (support_host->ui_page() == ArcSupportHost::UIPage::ERROR) { - // This case is handled by ArcSessionManager::OnRetryClicked(). - return; - } - - ArcSessionManager::Get()->auth_context()->Prepare(base::Bind( - &ArcAuthService::OnContextPrepared, weak_ptr_factory_.GetWeakPtr())); -} - } // namespace arc
diff --git a/chrome/browser/chromeos/arc/arc_auth_service.h b/chrome/browser/chromeos/arc/arc_auth_service.h index d008f1f..13080e1 100644 --- a/chrome/browser/chromeos/arc/arc_auth_service.h +++ b/chrome/browser/chromeos/arc/arc_auth_service.h
@@ -10,27 +10,20 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "chrome/browser/chromeos/arc/arc_support_host.h" #include "components/arc/arc_service.h" #include "components/arc/common/auth.mojom.h" #include "components/arc/instance_holder.h" #include "mojo/public/cpp/bindings/binding.h" -namespace net { -class URLRequestContextGetter; -} - namespace arc { class ArcAuthCodeFetcher; -class ArcRobotAuth; // Implementation of ARC authorization. // TODO(hidehiko): Move to c/b/c/arc/auth with adding tests. class ArcAuthService : public ArcService, public mojom::AuthHost, - public InstanceHolder<mojom::AuthInstance>::Observer, - public ArcSupportHost::Observer { + public InstanceHolder<mojom::AuthInstance>::Observer { public: explicit ArcAuthService(ArcBridgeService* bridge_service); ~ArcAuthService() override; @@ -60,10 +53,6 @@ void GetIsAccountManagedDeprecated( const GetIsAccountManagedDeprecatedCallback& callback) override; - // ArcSupportHost::Observer: - void OnAuthSucceeded(const std::string& auth_code) override; - void OnRetryClicked() override; - private: using AccountInfoCallback = base::Callback<void(mojom::AccountInfoPtr)>; class AccountInfoNotifier; @@ -72,28 +61,16 @@ void RequestAccountInfoInternal( std::unique_ptr<AccountInfoNotifier> account_info_notifier); - // Called when HTTP context is prepared. - void OnContextPrepared(net::URLRequestContextGetter* request_context_getter); - - void OnAccountInfoReady(mojom::AccountInfoPtr account_info); - - // Callback for Robot auth in Kiosk mode. - void OnRobotAuthCodeFetched(const std::string& auth_code); - - // Callback for automatic auth code fetching when --arc-user-auth-endpoint - // flag is set. + // Callback on auth_code fetched. void OnAuthCodeFetched(const std::string& auth_code); - // Common procedure across LSO auth code fetching, automatic auth code - // fetching, and Robot auth. - void OnAuthCodeObtained(const std::string& auth_code); + // Called to let ARC container know the account info. + void OnAccountInfoReady(mojom::AccountInfoPtr account_info); mojo::Binding<mojom::AuthHost> binding_; - std::unique_ptr<ArcAuthCodeFetcher> auth_code_fetcher_; - std::unique_ptr<ArcRobotAuth> arc_robot_auth_; - std::unique_ptr<AccountInfoNotifier> notifier_; + std::unique_ptr<ArcAuthCodeFetcher> fetcher_; base::WeakPtrFactory<ArcAuthService> weak_ptr_factory_;
diff --git a/chrome/browser/chromeos/arc/arc_session_manager.cc b/chrome/browser/chromeos/arc/arc_session_manager.cc index 2be4bdc2..3159554 100644 --- a/chrome/browser/chromeos/arc/arc_session_manager.cc +++ b/chrome/browser/chromeos/arc/arc_session_manager.cc
@@ -14,14 +14,14 @@ #include "base/logging.h" #include "base/strings/string16.h" #include "base/time/time.h" -#include "chrome/browser/chromeos/arc/arc_auth_code_fetcher.h" #include "chrome/browser/chromeos/arc/arc_auth_context.h" #include "chrome/browser/chromeos/arc/arc_optin_uma.h" #include "chrome/browser/chromeos/arc/arc_support_host.h" -#include "chrome/browser/chromeos/arc/auth/arc_robot_auth.h" #include "chrome/browser/chromeos/arc/optin/arc_terms_of_service_negotiator.h" #include "chrome/browser/chromeos/arc/policy/arc_android_management_checker.h" #include "chrome/browser/chromeos/arc/policy/arc_policy_util.h" +#include "chrome/browser/chromeos/login/user_flow.h" +#include "chrome/browser/chromeos/login/users/chrome_user_manager.h" #include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/lifetime/application_lifetime.h" #include "chrome/browser/policy/profile_policy_connector.h" @@ -168,6 +168,13 @@ return false; } + chromeos::UserFlow* user_flow = + chromeos::ChromeUserManager::Get()->GetUserFlow(user->GetAccountId()); + if (!user_flow || !user_flow->CanStartArc()) { + VLOG(1) << "ARC is not allowed in the current user flow."; + return false; + } + if (user_manager::UserManager::Get() ->IsCurrentUserCryptohomeDataEphemeral()) { VLOG(2) << "Users with ephemeral data are not supported in Arc."; @@ -242,6 +249,14 @@ DCHECK_EQ(state_, State::ACTIVE); if (result == ProvisioningResult::CHROME_SERVER_COMMUNICATION_ERROR) { + if (IsArcKioskMode()) { + VLOG(1) << "Robot account auth code fetching error"; + // Log out the user. All the cleanup will be done in Shutdown() method. + // The callback is not called because auth code is empty. + chrome::AttemptUserExit(); + return; + } + // For backwards compatibility, use NETWORK_ERROR for // CHROME_SERVER_COMMUNICATION_ERROR case. UpdateOptInCancelUMA(OptInCancelReason::NETWORK_ERROR);
diff --git a/chrome/browser/chromeos/arc/auth/arc_auth_code_fetcher.h b/chrome/browser/chromeos/arc/auth/arc_auth_code_fetcher.h new file mode 100644 index 0000000..7f9770e --- /dev/null +++ b/chrome/browser/chromeos/arc/auth/arc_auth_code_fetcher.h
@@ -0,0 +1,30 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_AUTH_CODE_FETCHER_H_ +#define CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_AUTH_CODE_FETCHER_H_ + +#include <string> + +#include "base/callback.h" + +namespace arc { + +// Interface to implement auth_code fetching. +class ArcAuthCodeFetcher { + public: + virtual ~ArcAuthCodeFetcher() = default; + + // Fetches the |auth_code|. On success, |callback| is called with the + // fetched |auth_code|. Otherwise, |callback| is called with empty string. + // Fetch() should be called once par instance, and it is expected that + // the inflight operation is cancelled without calling the |callback| + // when the instance is deleted. + using FetchCallback = base::Callback<void(const std::string& auth_code)>; + virtual void Fetch(const FetchCallback& callback) = 0; +}; + +} // namespace arc + +#endif // CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_AUTH_CODE_FETCHER_H_
diff --git a/chrome/browser/chromeos/arc/arc_auth_code_fetcher.cc b/chrome/browser/chromeos/arc/auth/arc_background_auth_code_fetcher.cc similarity index 87% rename from chrome/browser/chromeos/arc/arc_auth_code_fetcher.cc rename to chrome/browser/chromeos/arc/auth/arc_background_auth_code_fetcher.cc index 54e334f..d21207d7 100644 --- a/chrome/browser/chromeos/arc/arc_auth_code_fetcher.cc +++ b/chrome/browser/chromeos/arc/auth/arc_background_auth_code_fetcher.cc
@@ -2,7 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/chromeos/arc/arc_auth_code_fetcher.h" +#include "chrome/browser/chromeos/arc/auth/arc_background_auth_code_fetcher.h" + +#include <utility> #include "base/bind.h" #include "base/callback_helpers.h" @@ -45,24 +47,25 @@ } // namespace -ArcAuthCodeFetcher::ArcAuthCodeFetcher(Profile* profile, - ArcAuthContext* context) +ArcBackgroundAuthCodeFetcher::ArcBackgroundAuthCodeFetcher( + Profile* profile, + ArcAuthContext* context) : OAuth2TokenService::Consumer(kConsumerName), profile_(profile), context_(context), weak_ptr_factory_(this) {} -ArcAuthCodeFetcher::~ArcAuthCodeFetcher() = default; +ArcBackgroundAuthCodeFetcher::~ArcBackgroundAuthCodeFetcher() = default; -void ArcAuthCodeFetcher::Fetch(const FetchCallback& callback) { +void ArcBackgroundAuthCodeFetcher::Fetch(const FetchCallback& callback) { DCHECK(callback_.is_null()); callback_ = callback; - context_->Prepare(base::Bind(&ArcAuthCodeFetcher::OnPrepared, + context_->Prepare(base::Bind(&ArcBackgroundAuthCodeFetcher::OnPrepared, weak_ptr_factory_.GetWeakPtr())); } -void ArcAuthCodeFetcher::OnPrepared( +void ArcBackgroundAuthCodeFetcher::OnPrepared( net::URLRequestContextGetter* request_context_getter) { if (!request_context_getter) { base::ResetAndReturn(&callback_).Run(std::string()); @@ -82,7 +85,7 @@ login_token_request_ = token_service->StartRequest(account_id, scopes, this); } -void ArcAuthCodeFetcher::OnGetTokenSuccess( +void ArcBackgroundAuthCodeFetcher::OnGetTokenSuccess( const OAuth2TokenService::Request* request, const std::string& access_token, const base::Time& expiration_time) { @@ -111,7 +114,7 @@ auth_code_fetcher_->Start(); } -void ArcAuthCodeFetcher::OnGetTokenFailure( +void ArcBackgroundAuthCodeFetcher::OnGetTokenFailure( const OAuth2TokenService::Request* request, const GoogleServiceAuthError& error) { VLOG(2) << "Failed to get LST " << error.ToString() << "."; @@ -119,7 +122,8 @@ base::ResetAndReturn(&callback_).Run(std::string()); } -void ArcAuthCodeFetcher::OnURLFetchComplete(const net::URLFetcher* source) { +void ArcBackgroundAuthCodeFetcher::OnURLFetchComplete( + const net::URLFetcher* source) { const int response_code = source->GetResponseCode(); std::string json_string; source->GetResponseAsString(&json_string); @@ -162,7 +166,7 @@ base::ResetAndReturn(&callback_).Run(auth_code); } -void ArcAuthCodeFetcher::ResetFetchers() { +void ArcBackgroundAuthCodeFetcher::ResetFetchers() { login_token_request_.reset(); auth_code_fetcher_.reset(); }
diff --git a/chrome/browser/chromeos/arc/arc_auth_code_fetcher.h b/chrome/browser/chromeos/arc/auth/arc_background_auth_code_fetcher.h similarity index 65% rename from chrome/browser/chromeos/arc/arc_auth_code_fetcher.h rename to chrome/browser/chromeos/arc/auth/arc_background_auth_code_fetcher.h index 19a2c18f..b7d41a8 100644 --- a/chrome/browser/chromeos/arc/arc_auth_code_fetcher.h +++ b/chrome/browser/chromeos/arc/auth/arc_background_auth_code_fetcher.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_CHROMEOS_ARC_ARC_AUTH_CODE_FETCHER_H_ -#define CHROME_BROWSER_CHROMEOS_ARC_ARC_AUTH_CODE_FETCHER_H_ +#ifndef CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_BACKGROUND_AUTH_CODE_FETCHER_H_ +#define CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_BACKGROUND_AUTH_CODE_FETCHER_H_ #include <memory> #include <string> @@ -12,6 +12,7 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "chrome/browser/chromeos/arc/arc_auth_context.h" +#include "chrome/browser/chromeos/arc/auth/arc_auth_code_fetcher.h" #include "google_apis/gaia/oauth2_token_service.h" #include "net/url_request/url_fetcher_delegate.h" @@ -26,16 +27,19 @@ // The instance is not reusable, so for each Fetch(), the instance must be // re-created. Deleting the instance cancels inflight operation. -class ArcAuthCodeFetcher : public OAuth2TokenService::Consumer, - public net::URLFetcherDelegate { +class ArcBackgroundAuthCodeFetcher : public ArcAuthCodeFetcher, + public OAuth2TokenService::Consumer, + public net::URLFetcherDelegate { public: - ArcAuthCodeFetcher(Profile* profile, ArcAuthContext* context); - ~ArcAuthCodeFetcher() override; + ArcBackgroundAuthCodeFetcher(Profile* profile, ArcAuthContext* context); + ~ArcBackgroundAuthCodeFetcher() override; - // Starts to fetch the token. On success fetched |auth_token| is passed. - // On error, auth_token is empty. - using FetchCallback = base::Callback<void(const std::string& auth_token)>; - void Fetch(const FetchCallback& callback); + // ArcAuthCodeFetcher: + void Fetch(const FetchCallback& callback) override; + + private: + void ResetFetchers(); + void OnPrepared(net::URLRequestContextGetter* request_context_getter); // OAuth2TokenService::Consumer: void OnGetTokenSuccess(const OAuth2TokenService::Request* request, @@ -47,10 +51,6 @@ // net::URLFetcherDelegate: void OnURLFetchComplete(const net::URLFetcher* source) override; - private: - void ResetFetchers(); - void OnPrepared(net::URLRequestContextGetter* request_context_getter); - // Unowned pointers. Profile* const profile_; ArcAuthContext* const context_; @@ -61,11 +61,11 @@ std::unique_ptr<OAuth2TokenService::Request> login_token_request_; std::unique_ptr<net::URLFetcher> auth_code_fetcher_; - base::WeakPtrFactory<ArcAuthCodeFetcher> weak_ptr_factory_; + base::WeakPtrFactory<ArcBackgroundAuthCodeFetcher> weak_ptr_factory_; - DISALLOW_COPY_AND_ASSIGN(ArcAuthCodeFetcher); + DISALLOW_COPY_AND_ASSIGN(ArcBackgroundAuthCodeFetcher); }; } // namespace arc -#endif // CHROME_BROWSER_CHROMEOS_ARC_ARC_AUTH_CODE_FETCHER_H_ +#endif // CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_BACKGROUND_AUTH_CODE_FETCHER_H_
diff --git a/chrome/browser/chromeos/arc/auth/arc_manual_auth_code_fetcher.cc b/chrome/browser/chromeos/arc/auth/arc_manual_auth_code_fetcher.cc new file mode 100644 index 0000000..28fe5ef52 --- /dev/null +++ b/chrome/browser/chromeos/arc/auth/arc_manual_auth_code_fetcher.cc
@@ -0,0 +1,61 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/arc/auth/arc_manual_auth_code_fetcher.h" + +#include "base/bind.h" +#include "base/callback_helpers.h" +#include "base/logging.h" +#include "chrome/browser/chromeos/arc/arc_auth_context.h" + +namespace arc { + +ArcManualAuthCodeFetcher::ArcManualAuthCodeFetcher(ArcAuthContext* context, + ArcSupportHost* support_host) + : context_(context), support_host_(support_host), weak_ptr_factory_(this) { + DCHECK(context_); + DCHECK(support_host_); + support_host_->AddObserver(this); +} + +ArcManualAuthCodeFetcher::~ArcManualAuthCodeFetcher() { + support_host_->RemoveObserver(this); +} + +void ArcManualAuthCodeFetcher::Fetch(const FetchCallback& callback) { + DCHECK(pending_callback_.is_null()); + pending_callback_ = callback; + + FetchInternal(); +} + +void ArcManualAuthCodeFetcher::FetchInternal() { + DCHECK(!pending_callback_.is_null()); + context_->Prepare(base::Bind(&ArcManualAuthCodeFetcher::OnContextPrepared, + weak_ptr_factory_.GetWeakPtr())); +} + +void ArcManualAuthCodeFetcher::OnContextPrepared( + net::URLRequestContextGetter* request_context_getter) { + DCHECK(!pending_callback_.is_null()); + if (!request_context_getter) { + support_host_->ShowError(ArcSupportHost::Error::SIGN_IN_NETWORK_ERROR, + false); + return; + } + + support_host_->ShowLso(); +} + +void ArcManualAuthCodeFetcher::OnAuthSucceeded(const std::string& auth_code) { + DCHECK(!pending_callback_.is_null()); + base::ResetAndReturn(&pending_callback_).Run(auth_code); +} + +void ArcManualAuthCodeFetcher::OnRetryClicked() { + DCHECK(!pending_callback_.is_null()); + FetchInternal(); +} + +} // namespace arc
diff --git a/chrome/browser/chromeos/arc/auth/arc_manual_auth_code_fetcher.h b/chrome/browser/chromeos/arc/auth/arc_manual_auth_code_fetcher.h new file mode 100644 index 0000000..471d365 --- /dev/null +++ b/chrome/browser/chromeos/arc/auth/arc_manual_auth_code_fetcher.h
@@ -0,0 +1,57 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_MANUAL_AUTH_CODE_FETCHER_H_ +#define CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_MANUAL_AUTH_CODE_FETCHER_H_ + +#include <string> + +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "chrome/browser/chromeos/arc/arc_support_host.h" +#include "chrome/browser/chromeos/arc/auth/arc_auth_code_fetcher.h" + +namespace net { +class URLRequestContextGetter; +} + +namespace arc { + +class ArcAuthContext; + +// Implements the auth token fetching procedure with user's "SIGN IN" button +// click. +class ArcManualAuthCodeFetcher : public ArcAuthCodeFetcher, + public ArcSupportHost::Observer { + public: + ArcManualAuthCodeFetcher(ArcAuthContext* context, + ArcSupportHost* support_host); + ~ArcManualAuthCodeFetcher() override; + + // ArcAuthCodeFetcher: + void Fetch(const FetchCallback& callback) override; + + private: + void FetchInternal(); + + // Called when HTTP request gets ready. + void OnContextPrepared(net::URLRequestContextGetter* request_context_getter); + + // ArcSupportHost::Observer: + void OnAuthSucceeded(const std::string& auth_code) override; + void OnRetryClicked() override; + + ArcAuthContext* const context_; + ArcSupportHost* const support_host_; + + FetchCallback pending_callback_; + + base::WeakPtrFactory<ArcManualAuthCodeFetcher> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(ArcManualAuthCodeFetcher); +}; + +} // namespace arc + +#endif // CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_MANUAL_AUTH_CODE_FETCHER_H_
diff --git a/chrome/browser/chromeos/arc/auth/arc_robot_auth.h b/chrome/browser/chromeos/arc/auth/arc_robot_auth.h deleted file mode 100644 index dbcdbe1..0000000 --- a/chrome/browser/chromeos/arc/auth/arc_robot_auth.h +++ /dev/null
@@ -1,45 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_ROBOT_AUTH_H_ -#define CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_ROBOT_AUTH_H_ - -#include <memory> - -#include "base/callback.h" -#include "base/macros.h" -#include "components/policy/core/common/cloud/device_management_service.h" - -namespace arc { - -// This class is responsible to fetch auth code for robot account. Robot auth -// code is used for creation an account on Android side in ARC kiosk mode. -class ArcRobotAuth { - public: - using RobotAuthCodeCallback = base::Callback<void(const std::string&)>; - ArcRobotAuth(); - ~ArcRobotAuth(); - - // Fetches robot auth code. When auth code is fetched, the callback is - // invoked. Invoking callback with empty string means a fetch error. - // FetchRobotAuthCode() should not be called while another inflight operation - // is running. - void FetchRobotAuthCode(const RobotAuthCodeCallback& callback); - - private: - void OnFetchRobotAuthCodeCompleted( - RobotAuthCodeCallback callback, - policy::DeviceManagementStatus status, - int net_error, - const enterprise_management::DeviceManagementResponse& response); - - std::unique_ptr<policy::DeviceManagementRequestJob> fetch_request_job_; - base::WeakPtrFactory<ArcRobotAuth> weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(ArcRobotAuth); -}; - -} // namespace arc - -#endif // CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_ROBOT_AUTH_H_
diff --git a/chrome/browser/chromeos/arc/auth/arc_robot_auth.cc b/chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher.cc similarity index 85% rename from chrome/browser/chromeos/arc/auth/arc_robot_auth.cc rename to chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher.cc index b8c0a24..58bedb7 100644 --- a/chrome/browser/chromeos/arc/auth/arc_robot_auth.cc +++ b/chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher.cc
@@ -2,7 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/chromeos/arc/auth/arc_robot_auth.h" +#include "chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher.h" + +#include <string> #include "base/bind.h" #include "chrome/browser/browser_process.h" @@ -36,11 +38,11 @@ namespace arc { -ArcRobotAuth::ArcRobotAuth() : weak_ptr_factory_(this) {} +ArcRobotAuthCodeFetcher::ArcRobotAuthCodeFetcher() : weak_ptr_factory_(this) {} -ArcRobotAuth::~ArcRobotAuth() = default; +ArcRobotAuthCodeFetcher::~ArcRobotAuthCodeFetcher() = default; -void ArcRobotAuth::FetchRobotAuthCode(const RobotAuthCodeCallback& callback) { +void ArcRobotAuthCodeFetcher::Fetch(const FetchCallback& callback) { DCHECK(!fetch_request_job_); const policy::CloudPolicyClient* client = GetCloudPolicyClient(); @@ -58,12 +60,12 @@ request->add_auth_scope(GaiaConstants::kAnyApiOAuth2Scope); fetch_request_job_->Start( - base::Bind(&ArcRobotAuth::OnFetchRobotAuthCodeCompleted, + base::Bind(&ArcRobotAuthCodeFetcher::OnFetchRobotAuthCodeCompleted, weak_ptr_factory_.GetWeakPtr(), callback)); } -void ArcRobotAuth::OnFetchRobotAuthCodeCompleted( - RobotAuthCodeCallback callback, +void ArcRobotAuthCodeFetcher::OnFetchRobotAuthCodeCompleted( + FetchCallback callback, policy::DeviceManagementStatus status, int net_error, const enterprise_management::DeviceManagementResponse& response) {
diff --git a/chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher.h b/chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher.h new file mode 100644 index 0000000..fdf02d7 --- /dev/null +++ b/chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher.h
@@ -0,0 +1,51 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_ROBOT_AUTH_CODE_FETCHER_H_ +#define CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_ROBOT_AUTH_CODE_FETCHER_H_ + +#include <memory> + +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "chrome/browser/chromeos/arc/auth/arc_auth_code_fetcher.h" +#include "components/policy/core/common/cloud/cloud_policy_constants.h" + +namespace enterprise_management { +class DeviceManagementResponse; +} + +namespace policy { +class DeviceManagementRequestJob; +} + +namespace arc { + +// This class is responsible to fetch auth code for robot account. Robot auth +// code is used for creation an account on Android side in ARC kiosk mode. +class ArcRobotAuthCodeFetcher : public ArcAuthCodeFetcher { + public: + ArcRobotAuthCodeFetcher(); + ~ArcRobotAuthCodeFetcher() override; + + // ArcAuthCodeFetcher: + void Fetch(const FetchCallback& callback) override; + + private: + void OnFetchRobotAuthCodeCompleted( + FetchCallback callback, + policy::DeviceManagementStatus status, + int net_error, + const enterprise_management::DeviceManagementResponse& response); + + std::unique_ptr<policy::DeviceManagementRequestJob> fetch_request_job_; + base::WeakPtrFactory<ArcRobotAuthCodeFetcher> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(ArcRobotAuthCodeFetcher); +}; + +} // namespace arc + +#endif // CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_ROBOT_AUTH_CODE_FETCHER_H_
diff --git a/chrome/browser/chromeos/arc/auth/arc_robot_auth_browsertest.cc b/chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher_browsertest.cc similarity index 92% rename from chrome/browser/chromeos/arc/auth/arc_robot_auth_browsertest.cc rename to chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher_browsertest.cc index ba6ab84..1ec0c7c6 100644 --- a/chrome/browser/chromeos/arc/auth/arc_robot_auth_browsertest.cc +++ b/chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher_browsertest.cc
@@ -78,12 +78,12 @@ } // namespace -class ArcRobotAuthBrowserTest : public InProcessBrowserTest { +class ArcRobotAuthCodeFetcherBrowserTest : public InProcessBrowserTest { protected: - ArcRobotAuthBrowserTest() = default; + ArcRobotAuthCodeFetcherBrowserTest() = default; // InProcessBrowserTest: - ~ArcRobotAuthBrowserTest() override = default; + ~ArcRobotAuthCodeFetcherBrowserTest() override = default; void SetUpCommandLine(base::CommandLine* command_line) override { InProcessBrowserTest::SetUpCommandLine(command_line); @@ -144,10 +144,11 @@ private: std::unique_ptr<chromeos::ScopedUserManagerEnabler> user_manager_enabler_; - DISALLOW_COPY_AND_ASSIGN(ArcRobotAuthBrowserTest); + DISALLOW_COPY_AND_ASSIGN(ArcRobotAuthCodeFetcherBrowserTest); }; -IN_PROC_BROWSER_TEST_F(ArcRobotAuthBrowserTest, RequestAccountInfoSuccess) { +IN_PROC_BROWSER_TEST_F(ArcRobotAuthCodeFetcherBrowserTest, + RequestAccountInfoSuccess) { interceptor_->PushJobCallback(base::Bind(&ResponseJob)); auth_instance_.callback = @@ -162,13 +163,15 @@ base::RunLoop().RunUntilIdle(); } -IN_PROC_BROWSER_TEST_F(ArcRobotAuthBrowserTest, RequestAccountInfoError) { +IN_PROC_BROWSER_TEST_F(ArcRobotAuthCodeFetcherBrowserTest, + RequestAccountInfoError) { interceptor_->PushJobCallback( policy::TestRequestInterceptor::BadRequestJob()); auth_instance_.callback = base::Bind([](const mojom::AccountInfoPtr&) { FAIL(); }); + ArcSessionManager::Get()->StartArc(); ArcAuthService::GetForTest()->RequestAccountInfo(); // This MessageLoop will be stopped by AttemptUserExit(), that is called as // a result of error of auth code fetching.
diff --git a/chrome/browser/chromeos/login/easy_unlock/bootstrap_user_flow.cc b/chrome/browser/chromeos/login/easy_unlock/bootstrap_user_flow.cc index 856922b0..30b1eb0 100644 --- a/chrome/browser/chromeos/login/easy_unlock/bootstrap_user_flow.cc +++ b/chrome/browser/chromeos/login/easy_unlock/bootstrap_user_flow.cc
@@ -122,6 +122,10 @@ return false; } +bool BootstrapUserFlow::CanStartArc() { + return false; +} + bool BootstrapUserFlow::ShouldLaunchBrowser() { return finished_; }
diff --git a/chrome/browser/chromeos/login/easy_unlock/bootstrap_user_flow.h b/chrome/browser/chromeos/login/easy_unlock/bootstrap_user_flow.h index 9b6926b..4f39b2a 100644 --- a/chrome/browser/chromeos/login/easy_unlock/bootstrap_user_flow.h +++ b/chrome/browser/chromeos/login/easy_unlock/bootstrap_user_flow.h
@@ -42,6 +42,7 @@ // chromeos::ExtendedUserFlow bool CanLockScreen() override; + bool CanStartArc() override; bool ShouldLaunchBrowser() override; bool ShouldSkipPostLoginScreens() override; bool HandleLoginFailure(const chromeos::AuthFailure& failure) override;
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_user_login_flow.cc b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_user_login_flow.cc index 2ba28ad9..fea8f7f 100644 --- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_user_login_flow.cc +++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_user_login_flow.cc
@@ -16,6 +16,10 @@ return true; } +bool EasyUnlockUserLoginFlow::CanStartArc() { + return true; +} + bool EasyUnlockUserLoginFlow::ShouldLaunchBrowser() { return true; }
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_user_login_flow.h b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_user_login_flow.h index 34b1919f..65465d4 100644 --- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_user_login_flow.h +++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_user_login_flow.h
@@ -23,6 +23,7 @@ private: // chromeos::ExtendedUserFlow implementation. bool CanLockScreen() override; + bool CanStartArc() override; bool ShouldLaunchBrowser() override; bool ShouldSkipPostLoginScreens() override; bool HandleLoginFailure(const chromeos::AuthFailure& failure) override;
diff --git a/chrome/browser/chromeos/login/supervised/supervised_user_creation_flow.cc b/chrome/browser/chromeos/login/supervised/supervised_user_creation_flow.cc index a6101e6ea..394046d 100644 --- a/chrome/browser/chromeos/login/supervised/supervised_user_creation_flow.cc +++ b/chrome/browser/chromeos/login/supervised/supervised_user_creation_flow.cc
@@ -42,6 +42,10 @@ return false; } +bool SupervisedUserCreationFlow::CanStartArc() { + return false; +} + bool SupervisedUserCreationFlow::ShouldShowSettings() { return false; }
diff --git a/chrome/browser/chromeos/login/supervised/supervised_user_creation_flow.h b/chrome/browser/chromeos/login/supervised/supervised_user_creation_flow.h index 5e5da704..2c88141e 100644 --- a/chrome/browser/chromeos/login/supervised/supervised_user_creation_flow.h +++ b/chrome/browser/chromeos/login/supervised/supervised_user_creation_flow.h
@@ -23,6 +23,7 @@ ~SupervisedUserCreationFlow() override; bool CanLockScreen() override; + bool CanStartArc() override; bool ShouldShowSettings() override; bool ShouldShowNotificationTray() override; bool ShouldLaunchBrowser() override;
diff --git a/chrome/browser/chromeos/login/supervised/supervised_user_login_flow.cc b/chrome/browser/chromeos/login/supervised/supervised_user_login_flow.cc index 08e387c..4a1ae73 100644 --- a/chrome/browser/chromeos/login/supervised/supervised_user_login_flow.cc +++ b/chrome/browser/chromeos/login/supervised/supervised_user_login_flow.cc
@@ -46,6 +46,10 @@ return true; } +bool SupervisedUserLoginFlow::CanStartArc() { + return false; +} + bool SupervisedUserLoginFlow::ShouldLaunchBrowser() { return data_loaded_; }
diff --git a/chrome/browser/chromeos/login/supervised/supervised_user_login_flow.h b/chrome/browser/chromeos/login/supervised/supervised_user_login_flow.h index 9ecae8e..4f25bd0 100644 --- a/chrome/browser/chromeos/login/supervised/supervised_user_login_flow.h +++ b/chrome/browser/chromeos/login/supervised/supervised_user_login_flow.h
@@ -26,6 +26,7 @@ // ExtendedUserFlow overrides. void AppendAdditionalCommandLineSwitches() override; bool CanLockScreen() override; + bool CanStartArc() override; bool ShouldLaunchBrowser() override; bool ShouldSkipPostLoginScreens() override; bool SupportsEarlyRestartToApplyFlags() override;
diff --git a/chrome/browser/chromeos/login/user_flow.cc b/chrome/browser/chromeos/login/user_flow.cc index 6e1a6a7..f0871e8 100644 --- a/chrome/browser/chromeos/login/user_flow.cc +++ b/chrome/browser/chromeos/login/user_flow.cc
@@ -30,6 +30,10 @@ return true; } +bool DefaultUserFlow::CanStartArc() { + return true; +} + bool DefaultUserFlow::ShouldShowSettings() { return true; }
diff --git a/chrome/browser/chromeos/login/user_flow.h b/chrome/browser/chromeos/login/user_flow.h index 91578aa..23c9094ac 100644 --- a/chrome/browser/chromeos/login/user_flow.h +++ b/chrome/browser/chromeos/login/user_flow.h
@@ -28,6 +28,7 @@ // Indicates if screen locking should be enabled or disabled for a flow. virtual bool CanLockScreen() = 0; + virtual bool CanStartArc() = 0; virtual bool ShouldShowSettings() = 0; virtual bool ShouldShowNotificationTray() = 0; virtual bool ShouldLaunchBrowser() = 0; @@ -56,6 +57,7 @@ void AppendAdditionalCommandLineSwitches() override; bool CanLockScreen() override; + bool CanStartArc() override; bool ShouldShowSettings() override; bool ShouldShowNotificationTray() override; bool ShouldLaunchBrowser() override;
diff --git a/chrome/browser/features.cc b/chrome/browser/features.cc new file mode 100644 index 0000000..5b6c841 --- /dev/null +++ b/chrome/browser/features.cc
@@ -0,0 +1,12 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/features.h" + +namespace features { + +const base::Feature kDesktopFastShutdown{"DesktopFastShutdown", + base::FEATURE_DISABLED_BY_DEFAULT}; + +} // namespace features
diff --git a/chrome/browser/features.h b/chrome/browser/features.h new file mode 100644 index 0000000..edf8951 --- /dev/null +++ b/chrome/browser/features.h
@@ -0,0 +1,19 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Contains features that need inclusion from multiple files. Features used from +// a single .cc file should be declared in the file's anonymous namespace. + +#ifndef CHROME_BROWSER_FEATURES_H_ +#define CHROME_BROWSER_FEATURES_H_ + +#include "base/feature_list.h" + +namespace features { + +extern const base::Feature kDesktopFastShutdown; + +} // namespace features + +#endif // CHROME_BROWSER_FEATURES_H_
diff --git a/chrome/browser/permissions/permission_request_impl.cc b/chrome/browser/permissions/permission_request_impl.cc index 0abc8aa..a9bbd496 100644 --- a/chrome/browser/permissions/permission_request_impl.cc +++ b/chrome/browser/permissions/permission_request_impl.cc
@@ -71,7 +71,7 @@ #if defined(OS_CHROMEOS) // TODO(xhwang): fix this icon, see crrev.com/863263007 case content::PermissionType::PROTECTED_MEDIA_IDENTIFIER: - return gfx::VectorIconId::CHROME_PRODUCT; + return gfx::VectorIconId::PRODUCT; #endif case content::PermissionType::MIDI_SYSEX: return gfx::VectorIconId::MIDI;
diff --git a/chrome/browser/resources/history/other_devices.js b/chrome/browser/resources/history/other_devices.js index 2ba6f76..0a10191 100644 --- a/chrome/browser/resources/history/other_devices.js +++ b/chrome/browser/resources/history/other_devices.js
@@ -541,18 +541,12 @@ /** * Sets the menu model data. An empty list means that either there are no * foreign sessions, or tab sync is disabled for this profile. - * |isTabSyncEnabled| makes it possible to distinguish between the cases. * * @param {Array} sessionList Array of objects describing the sessions * from other devices. - * @param {boolean} isTabSyncEnabled Is tab sync enabled for this profile? */ -function setForeignSessions(sessionList, isTabSyncEnabled) { - // The other devices is shown iff tab sync is enabled. - if (isTabSyncEnabled) - devicesView.setSessionList(sessionList); - else - devicesView.clearDOM(); +function setForeignSessions(sessionList) { + devicesView.setSessionList(sessionList); } /**
diff --git a/chrome/browser/resources/md_history/app.crisper.js b/chrome/browser/resources/md_history/app.crisper.js index 04ed24c..eb0c494b 100644 --- a/chrome/browser/resources/md_history/app.crisper.js +++ b/chrome/browser/resources/md_history/app.crisper.js
@@ -83,4 +83,4 @@ // Copyright 2016 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -cr.define("md_history",function(){var lazyLoadPromise=null;function ensureLazyLoaded(){if(!lazyLoadPromise){lazyLoadPromise=new Promise(function(resolve,reject){Polymer.Base.importHref("chrome://history/lazy_load.html",resolve,reject,true)})}return lazyLoadPromise}return{ensureLazyLoaded:ensureLazyLoaded}});Polymer({is:"history-app",behaviors:[Polymer.IronScrollTargetBehavior],properties:{showSidebarFooter:Boolean,hasSyncedResults:Boolean,selectedPage_:{type:String,observer:"selectedPageChanged_"},grouped_:{type:Boolean,reflectToAttribute:true},queryState_:{type:Object,value:function(){return{incremental:false,querying:true,queryingDisabled:false,_range:HistoryRange.ALL_TIME,searchTerm:"",groupedOffset:0,set range(val){this._range=Number(val)},get range(){return this._range}}}},queryResult_:{type:Object,value:function(){return{info:null,results:null,sessionList:null}}},hasDrawer_:Boolean,isUserSignedIn_:{type:Boolean,value:loadTimeData.getBoolean("isUserSignedIn")},toolbarShadow_:{type:Boolean,reflectToAttribute:true,notify:true},showMenuPromo_:{type:Boolean,value:function(){return loadTimeData.getBoolean("showMenuPromo")}}},listeners:{"cr-toolbar-menu-promo-close":"onCrToolbarMenuPromoClose_","cr-toolbar-menu-promo-shown":"onCrToolbarMenuPromoShown_","cr-toolbar-menu-tap":"onCrToolbarMenuTap_","delete-selected":"deleteSelected","history-checkbox-select":"checkboxSelected","history-close-drawer":"closeDrawer_","history-view-changed":"historyViewChanged_","opened-changed":"onOpenedChanged_","unselect-all":"unselectAll"},boundOnCanExecute_:null,boundOnCommand_:null,attached:function(){this.grouped_=loadTimeData.getBoolean("groupByDomain");cr.ui.decorate("command",cr.ui.Command);this.boundOnCanExecute_=this.onCanExecute_.bind(this);this.boundOnCommand_=this.onCommand_.bind(this);document.addEventListener("canExecute",this.boundOnCanExecute_);document.addEventListener("command",this.boundOnCommand_)},detached:function(){document.removeEventListener("canExecute",this.boundOnCanExecute_);document.removeEventListener("command",this.boundOnCommand_)},onFirstRender:function(){setTimeout(function(){chrome.send("metricsHandler:recordTime",["History.ResultsRenderedTime",window.performance.now()])});var searchField=this.$.toolbar.searchField;if(!searchField.narrow){searchField.getSearchInput().focus()}md_history.ensureLazyLoaded().then(function(){window.requestIdleCallback(function(){document.fonts.load("bold 12px Roboto")})})},_scrollHandler:function(){if(this.scrollTarget)this.toolbarShadow_=this.scrollTarget.scrollTop!=0},onCrToolbarMenuPromoClose_:function(){this.showMenuPromo_=false},onCrToolbarMenuPromoShown_:function(){md_history.BrowserService.getInstance().menuPromoShown()},onCrToolbarMenuTap_:function(){var drawer=this.$$("#drawer");if(drawer)drawer.toggle()},onOpenedChanged_:function(e){if(e.detail.value)this.showMenuPromo_=false},checkboxSelected:function(e){var toolbar=this.$.toolbar;toolbar.count=this.$.history.getSelectedItemCount()},unselectAll:function(){var listContainer=this.$.history;var toolbar=this.$.toolbar;listContainer.unselectAllItems(toolbar.count);toolbar.count=0},deleteSelected:function(){this.$.history.deleteSelectedWithPrompt()},historyResult:function(info,results){this.set("queryState_.querying",false);this.set("queryResult_.info",info);this.set("queryResult_.results",results);var listContainer=this.$["history"];listContainer.historyResult(info,results)},focusToolbarSearchField:function(){this.$.toolbar.showSearchField()},onCanExecute_:function(e){e=e;switch(e.command.id){case"find-command":case"toggle-grouped":e.canExecute=true;break;case"slash-command":e.canExecute=!this.$.toolbar.searchField.isSearchFocused();break;case"delete-command":e.canExecute=this.$.toolbar.count>0;break}},onCommand_:function(e){if(e.command.id=="find-command"||e.command.id=="slash-command")this.focusToolbarSearchField();if(e.command.id=="delete-command")this.deleteSelected();if(e.command.id=="toggle-grouped")this.grouped_=!this.grouped_},setForeignSessions:function(sessionList,isTabSyncEnabled){if(!isTabSyncEnabled){var syncedDeviceManagerElem=this.$$("history-synced-device-manager");if(syncedDeviceManagerElem){md_history.ensureLazyLoaded().then(function(){syncedDeviceManagerElem.tabSyncDisabled()})}return}this.set("queryResult_.sessionList",sessionList)},historyDeleted:function(){this.$.history.historyDeleted()},updateSignInState:function(isUserSignedIn){this.isUserSignedIn_=isUserSignedIn},syncedTabsSelected_:function(selectedPage){return selectedPage=="syncedTabs"},shouldShowSpinner_:function(querying,incremental,searchTerm){return querying&&!incremental&&searchTerm!=""},showSyncNotice_:function(hasSyncedResults,selectedPage){return hasSyncedResults&&selectedPage!="syncedTabs"},selectedPageChanged_:function(){this.unselectAll();this.historyViewChanged_()},historyViewChanged_:function(){requestAnimationFrame(function(){md_history.ensureLazyLoaded().then(function(){if(!this.$.content.selectedItem)return;this.scrollTarget=this.$.content.selectedItem.getContentScrollTarget();this._scrollHandler()}.bind(this))}.bind(this));this.recordHistoryPageView_()},getSelectedPage_:function(selectedPage,items){return selectedPage},closeDrawer_:function(){var drawer=this.$$("#drawer");if(drawer)drawer.close()},recordHistoryPageView_:function(){var histogramValue=HistoryPageViewHistogram.END;switch(this.selectedPage_){case"syncedTabs":histogramValue=this.isUserSignedIn_?HistoryPageViewHistogram.SYNCED_TABS:HistoryPageViewHistogram.SIGNIN_PROMO;break;default:switch(this.queryState_.range){case HistoryRange.ALL_TIME:histogramValue=HistoryPageViewHistogram.HISTORY;break;case HistoryRange.WEEK:histogramValue=HistoryPageViewHistogram.GROUPED_WEEK;break;case HistoryRange.MONTH:histogramValue=HistoryPageViewHistogram.GROUPED_MONTH;break}break}md_history.BrowserService.getInstance().recordHistogram("History.HistoryPageView",histogramValue,HistoryPageViewHistogram.END)}}); \ No newline at end of file +cr.define("md_history",function(){var lazyLoadPromise=null;function ensureLazyLoaded(){if(!lazyLoadPromise){lazyLoadPromise=new Promise(function(resolve,reject){Polymer.Base.importHref("chrome://history/lazy_load.html",resolve,reject,true)})}return lazyLoadPromise}return{ensureLazyLoaded:ensureLazyLoaded}});Polymer({is:"history-app",behaviors:[Polymer.IronScrollTargetBehavior],properties:{showSidebarFooter:Boolean,hasSyncedResults:Boolean,selectedPage_:{type:String,observer:"selectedPageChanged_"},grouped_:{type:Boolean,reflectToAttribute:true},queryState_:{type:Object,value:function(){return{incremental:false,querying:true,queryingDisabled:false,_range:HistoryRange.ALL_TIME,searchTerm:"",groupedOffset:0,set range(val){this._range=Number(val)},get range(){return this._range}}}},queryResult_:{type:Object,value:function(){return{info:null,results:null,sessionList:null}}},hasDrawer_:Boolean,isUserSignedIn_:{type:Boolean,value:loadTimeData.getBoolean("isUserSignedIn")},toolbarShadow_:{type:Boolean,reflectToAttribute:true,notify:true},showMenuPromo_:{type:Boolean,value:function(){return loadTimeData.getBoolean("showMenuPromo")}}},listeners:{"cr-toolbar-menu-promo-close":"onCrToolbarMenuPromoClose_","cr-toolbar-menu-promo-shown":"onCrToolbarMenuPromoShown_","cr-toolbar-menu-tap":"onCrToolbarMenuTap_","delete-selected":"deleteSelected","history-checkbox-select":"checkboxSelected","history-close-drawer":"closeDrawer_","history-view-changed":"historyViewChanged_","opened-changed":"onOpenedChanged_","unselect-all":"unselectAll"},boundOnCanExecute_:null,boundOnCommand_:null,attached:function(){this.grouped_=loadTimeData.getBoolean("groupByDomain");cr.ui.decorate("command",cr.ui.Command);this.boundOnCanExecute_=this.onCanExecute_.bind(this);this.boundOnCommand_=this.onCommand_.bind(this);document.addEventListener("canExecute",this.boundOnCanExecute_);document.addEventListener("command",this.boundOnCommand_)},detached:function(){document.removeEventListener("canExecute",this.boundOnCanExecute_);document.removeEventListener("command",this.boundOnCommand_)},onFirstRender:function(){setTimeout(function(){chrome.send("metricsHandler:recordTime",["History.ResultsRenderedTime",window.performance.now()])});var searchField=this.$.toolbar.searchField;if(!searchField.narrow){searchField.getSearchInput().focus()}md_history.ensureLazyLoaded().then(function(){window.requestIdleCallback(function(){document.fonts.load("bold 12px Roboto")})})},_scrollHandler:function(){if(this.scrollTarget)this.toolbarShadow_=this.scrollTarget.scrollTop!=0},onCrToolbarMenuPromoClose_:function(){this.showMenuPromo_=false},onCrToolbarMenuPromoShown_:function(){md_history.BrowserService.getInstance().menuPromoShown()},onCrToolbarMenuTap_:function(){var drawer=this.$$("#drawer");if(drawer)drawer.toggle()},onOpenedChanged_:function(e){if(e.detail.value)this.showMenuPromo_=false},checkboxSelected:function(e){var toolbar=this.$.toolbar;toolbar.count=this.$.history.getSelectedItemCount()},unselectAll:function(){var listContainer=this.$.history;var toolbar=this.$.toolbar;listContainer.unselectAllItems(toolbar.count);toolbar.count=0},deleteSelected:function(){this.$.history.deleteSelectedWithPrompt()},historyResult:function(info,results){this.set("queryState_.querying",false);this.set("queryResult_.info",info);this.set("queryResult_.results",results);var listContainer=this.$["history"];listContainer.historyResult(info,results)},focusToolbarSearchField:function(){this.$.toolbar.showSearchField()},onCanExecute_:function(e){e=e;switch(e.command.id){case"find-command":case"toggle-grouped":e.canExecute=true;break;case"slash-command":e.canExecute=!this.$.toolbar.searchField.isSearchFocused();break;case"delete-command":e.canExecute=this.$.toolbar.count>0;break}},onCommand_:function(e){if(e.command.id=="find-command"||e.command.id=="slash-command")this.focusToolbarSearchField();if(e.command.id=="delete-command")this.deleteSelected();if(e.command.id=="toggle-grouped")this.grouped_=!this.grouped_},setForeignSessions:function(sessionList){this.set("queryResult_.sessionList",sessionList)},historyDeleted:function(){this.$.history.historyDeleted()},updateSignInState:function(isUserSignedIn){this.isUserSignedIn_=isUserSignedIn},syncedTabsSelected_:function(selectedPage){return selectedPage=="syncedTabs"},shouldShowSpinner_:function(querying,incremental,searchTerm){return querying&&!incremental&&searchTerm!=""},showSyncNotice_:function(hasSyncedResults,selectedPage){return hasSyncedResults&&selectedPage!="syncedTabs"},selectedPageChanged_:function(){this.unselectAll();this.historyViewChanged_()},historyViewChanged_:function(){requestAnimationFrame(function(){md_history.ensureLazyLoaded().then(function(){if(!this.$.content.selectedItem)return;this.scrollTarget=this.$.content.selectedItem.getContentScrollTarget();this._scrollHandler()}.bind(this))}.bind(this));this.recordHistoryPageView_()},getSelectedPage_:function(selectedPage,items){return selectedPage},closeDrawer_:function(){var drawer=this.$$("#drawer");if(drawer)drawer.close()},recordHistoryPageView_:function(){var histogramValue=HistoryPageViewHistogram.END;switch(this.selectedPage_){case"syncedTabs":histogramValue=this.isUserSignedIn_?HistoryPageViewHistogram.SYNCED_TABS:HistoryPageViewHistogram.SIGNIN_PROMO;break;default:switch(this.queryState_.range){case HistoryRange.ALL_TIME:histogramValue=HistoryPageViewHistogram.HISTORY;break;case HistoryRange.WEEK:histogramValue=HistoryPageViewHistogram.GROUPED_WEEK;break;case HistoryRange.MONTH:histogramValue=HistoryPageViewHistogram.GROUPED_MONTH;break}break}md_history.BrowserService.getInstance().recordHistogram("History.HistoryPageView",histogramValue,HistoryPageViewHistogram.END)}}); \ No newline at end of file
diff --git a/chrome/browser/resources/md_history/app.js b/chrome/browser/resources/md_history/app.js index 3c26c37..2a39a590 100644 --- a/chrome/browser/resources/md_history/app.js +++ b/chrome/browser/resources/md_history/app.js
@@ -266,21 +266,8 @@ /** * @param {!Array<!ForeignSession>} sessionList Array of objects describing * the sessions from other devices. - * @param {boolean} isTabSyncEnabled Is tab sync enabled for this profile? */ - setForeignSessions: function(sessionList, isTabSyncEnabled) { - if (!isTabSyncEnabled) { - var syncedDeviceManagerElem = - /** @type {HistorySyncedDeviceManagerElement} */this - .$$('history-synced-device-manager'); - if (syncedDeviceManagerElem) { - md_history.ensureLazyLoaded().then(function() { - syncedDeviceManagerElem.tabSyncDisabled(); - }); - } - return; - } - + setForeignSessions: function(sessionList) { this.set('queryResult_.sessionList', sessionList); },
diff --git a/chrome/browser/resources/md_history/history.js b/chrome/browser/resources/md_history/history.js index 522e8f9..cecf808 100644 --- a/chrome/browser/resources/md_history/history.js +++ b/chrome/browser/resources/md_history/history.js
@@ -68,16 +68,14 @@ /** * Receives the synced history data. An empty list means that either there are * no foreign sessions, or tab sync is disabled for this profile. - * |isTabSyncEnabled| makes it possible to distinguish between the cases. * * @param {!Array<!ForeignSession>} sessionList Array of objects describing the * sessions from other devices. - * @param {boolean} isTabSyncEnabled Is tab sync enabled for this profile? */ -function setForeignSessions(sessionList, isTabSyncEnabled) { +function setForeignSessions(sessionList) { waitForAppUpgrade().then(function() { /** @type {HistoryAppElement} */($('history-app')) - .setForeignSessions(sessionList, isTabSyncEnabled); + .setForeignSessions(sessionList); }); }
diff --git a/chrome/browser/resources/md_history/lazy_load.crisper.js b/chrome/browser/resources/md_history/lazy_load.crisper.js index b3f8a172e..8fc66fd 100644 --- a/chrome/browser/resources/md_history/lazy_load.crisper.js +++ b/chrome/browser/resources/md_history/lazy_load.crisper.js
@@ -19,7 +19,7 @@ // Copyright 2016 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -var ForeignDeviceInternal;Polymer({is:"history-synced-device-manager",properties:{sessionList:{type:Array,observer:"updateSyncedDevices"},searchTerm:{type:String,observer:"searchTermChanged"},syncedDevices_:{type:Array,value:function(){return[]}},signInState:{type:Boolean,observer:"signInStateChanged_"},guestSession_:{type:Boolean,value:loadTimeData.getBoolean("isGuestSession")},fetchingSyncedTabs_:{type:Boolean,value:false},hasSeenForeignData_:Boolean},listeners:{"toggle-menu":"onToggleMenu_",scroll:"onListScroll_","update-focus-grid":"updateFocusGrid_"},focusGrid_:null,attached:function(){this.focusGrid_=new cr.ui.FocusGrid;chrome.send("otherDevicesInitialized");md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOGRAM_NAME,SyncedTabsHistogram.INITIALIZED,SyncedTabsHistogram.LIMIT)},detached:function(){this.focusGrid_.destroy()},getContentScrollTarget:function(){return this},createInternalDevice_:function(session){var tabs=[];var separatorIndexes=[];for(var i=0;i<session.windows.length;i++){var windowId=session.windows[i].sessionId;var newTabs=session.windows[i].tabs;if(newTabs.length==0)continue;newTabs.forEach(function(tab){tab.windowId=windowId});var windowAdded=false;if(!this.searchTerm){tabs=tabs.concat(newTabs);windowAdded=true}else{var searchText=this.searchTerm.toLowerCase();for(var j=0;j<newTabs.length;j++){var tab=newTabs[j];if(tab.title.toLowerCase().indexOf(searchText)!=-1){tabs.push(tab);windowAdded=true}}}if(windowAdded&&i!=session.windows.length-1)separatorIndexes.push(tabs.length-1)}return{device:session.name,lastUpdateTime:"– "+session.modifiedTime,opened:true,separatorIndexes:separatorIndexes,timestamp:session.timestamp,tabs:tabs,tag:session.tag}},onSignInTap_:function(){chrome.send("startSignInFlow")},onListScroll_:function(){var menu=this.$.menu.getIfExists();if(menu)menu.closeMenu()},onToggleMenu_:function(e){var menu=this.$.menu.get();menu.toggleMenu(e.detail.target,e.detail.tag);if(menu.menuOpen){md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOGRAM_NAME,SyncedTabsHistogram.SHOW_SESSION_MENU,SyncedTabsHistogram.LIMIT)}},onOpenAllTap_:function(){var menu=assert(this.$.menu.getIfExists());var browserService=md_history.BrowserService.getInstance();browserService.recordHistogram(SYNCED_TABS_HISTOGRAM_NAME,SyncedTabsHistogram.OPEN_ALL,SyncedTabsHistogram.LIMIT);browserService.openForeignSessionAllTabs(menu.itemData);menu.closeMenu()},updateFocusGrid_:function(){if(!this.focusGrid_)return;this.focusGrid_.destroy();this.debounce("updateFocusGrid",function(){Polymer.dom(this.root).querySelectorAll("history-synced-device-card").reduce(function(prev,cur){return prev.concat(cur.createFocusRows())},[]).forEach(function(row){this.focusGrid_.addRow(row)}.bind(this));this.focusGrid_.ensureRowActive()})},onDeleteSessionTap_:function(){var menu=assert(this.$.menu.getIfExists());var browserService=md_history.BrowserService.getInstance();browserService.recordHistogram(SYNCED_TABS_HISTOGRAM_NAME,SyncedTabsHistogram.HIDE_FOR_NOW,SyncedTabsHistogram.LIMIT);browserService.deleteForeignSession(menu.itemData);menu.closeMenu()},clearDisplayedSyncedDevices_:function(){this.syncedDevices_=[]},showNoSyncedMessage:function(signInState,syncedDevicesLength,guestSession){if(guestSession)return true;return signInState&&syncedDevicesLength==0},showSignInGuide:function(signInState,guestSession){var show=!signInState&&!guestSession;if(show){md_history.BrowserService.getInstance().recordAction("Signin_Impression_FromRecentTabs")}return show},noSyncedTabsMessage:function(){var stringName=this.fetchingSyncedTabs_?"loading":"noSyncedResults";if(this.searchTerm!=="")stringName="noSearchResults";return loadTimeData.getString(stringName)},updateSyncedDevices:function(sessionList){this.fetchingSyncedTabs_=false;if(!sessionList)return;if(sessionList.length>0&&!this.hasSeenForeignData_){this.hasSeenForeignData_=true;md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOGRAM_NAME,SyncedTabsHistogram.HAS_FOREIGN_DATA,SyncedTabsHistogram.LIMIT)}var devices=[];sessionList.forEach(function(session){var device=this.createInternalDevice_(session);if(device.tabs.length!=0)devices.push(device)}.bind(this));this.syncedDevices_=devices},tabSyncDisabled:function(){this.fetchingSyncedTabs_=false;this.clearDisplayedSyncedDevices_()},signInStateChanged_:function(){this.fire("history-view-changed");if(!this.signInState){this.clearDisplayedSyncedDevices_();return}this.fetchingSyncedTabs_=true},searchTermChanged:function(searchTerm){this.clearDisplayedSyncedDevices_();this.updateSyncedDevices(this.sessionList)}}); +var ForeignDeviceInternal;Polymer({is:"history-synced-device-manager",properties:{sessionList:{type:Array,observer:"updateSyncedDevices"},searchTerm:{type:String,observer:"searchTermChanged"},syncedDevices_:{type:Array,value:function(){return[]}},signInState:{type:Boolean,observer:"signInStateChanged_"},guestSession_:{type:Boolean,value:loadTimeData.getBoolean("isGuestSession")},fetchingSyncedTabs_:{type:Boolean,value:false},hasSeenForeignData_:Boolean},listeners:{"toggle-menu":"onToggleMenu_",scroll:"onListScroll_","update-focus-grid":"updateFocusGrid_"},focusGrid_:null,attached:function(){this.focusGrid_=new cr.ui.FocusGrid;chrome.send("otherDevicesInitialized");md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOGRAM_NAME,SyncedTabsHistogram.INITIALIZED,SyncedTabsHistogram.LIMIT)},detached:function(){this.focusGrid_.destroy()},getContentScrollTarget:function(){return this},createInternalDevice_:function(session){var tabs=[];var separatorIndexes=[];for(var i=0;i<session.windows.length;i++){var windowId=session.windows[i].sessionId;var newTabs=session.windows[i].tabs;if(newTabs.length==0)continue;newTabs.forEach(function(tab){tab.windowId=windowId});var windowAdded=false;if(!this.searchTerm){tabs=tabs.concat(newTabs);windowAdded=true}else{var searchText=this.searchTerm.toLowerCase();for(var j=0;j<newTabs.length;j++){var tab=newTabs[j];if(tab.title.toLowerCase().indexOf(searchText)!=-1){tabs.push(tab);windowAdded=true}}}if(windowAdded&&i!=session.windows.length-1)separatorIndexes.push(tabs.length-1)}return{device:session.name,lastUpdateTime:"– "+session.modifiedTime,opened:true,separatorIndexes:separatorIndexes,timestamp:session.timestamp,tabs:tabs,tag:session.tag}},onSignInTap_:function(){chrome.send("startSignInFlow")},onListScroll_:function(){var menu=this.$.menu.getIfExists();if(menu)menu.closeMenu()},onToggleMenu_:function(e){var menu=this.$.menu.get();menu.toggleMenu(e.detail.target,e.detail.tag);if(menu.menuOpen){md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOGRAM_NAME,SyncedTabsHistogram.SHOW_SESSION_MENU,SyncedTabsHistogram.LIMIT)}},onOpenAllTap_:function(){var menu=assert(this.$.menu.getIfExists());var browserService=md_history.BrowserService.getInstance();browserService.recordHistogram(SYNCED_TABS_HISTOGRAM_NAME,SyncedTabsHistogram.OPEN_ALL,SyncedTabsHistogram.LIMIT);browserService.openForeignSessionAllTabs(menu.itemData);menu.closeMenu()},updateFocusGrid_:function(){if(!this.focusGrid_)return;this.focusGrid_.destroy();this.debounce("updateFocusGrid",function(){Polymer.dom(this.root).querySelectorAll("history-synced-device-card").reduce(function(prev,cur){return prev.concat(cur.createFocusRows())},[]).forEach(function(row){this.focusGrid_.addRow(row)}.bind(this));this.focusGrid_.ensureRowActive()})},onDeleteSessionTap_:function(){var menu=assert(this.$.menu.getIfExists());var browserService=md_history.BrowserService.getInstance();browserService.recordHistogram(SYNCED_TABS_HISTOGRAM_NAME,SyncedTabsHistogram.HIDE_FOR_NOW,SyncedTabsHistogram.LIMIT);browserService.deleteForeignSession(menu.itemData);menu.closeMenu()},clearDisplayedSyncedDevices_:function(){this.syncedDevices_=[]},showNoSyncedMessage:function(signInState,syncedDevicesLength,guestSession){if(guestSession)return true;return signInState&&syncedDevicesLength==0},showSignInGuide:function(signInState,guestSession){var show=!signInState&&!guestSession;if(show){md_history.BrowserService.getInstance().recordAction("Signin_Impression_FromRecentTabs")}return show},noSyncedTabsMessage:function(){var stringName=this.fetchingSyncedTabs_?"loading":"noSyncedResults";if(this.searchTerm!=="")stringName="noSearchResults";return loadTimeData.getString(stringName)},updateSyncedDevices:function(sessionList){this.fetchingSyncedTabs_=false;if(!sessionList)return;if(sessionList.length>0&&!this.hasSeenForeignData_){this.hasSeenForeignData_=true;md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOGRAM_NAME,SyncedTabsHistogram.HAS_FOREIGN_DATA,SyncedTabsHistogram.LIMIT)}var devices=[];sessionList.forEach(function(session){var device=this.createInternalDevice_(session);if(device.tabs.length!=0)devices.push(device)}.bind(this));this.syncedDevices_=devices},signInStateChanged_:function(){this.fire("history-view-changed");if(!this.signInState){this.clearDisplayedSyncedDevices_();return}this.fetchingSyncedTabs_=true},searchTermChanged:function(searchTerm){this.clearDisplayedSyncedDevices_();this.updateSyncedDevices(this.sessionList)}}); // Copyright 2016 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file.
diff --git a/chrome/browser/resources/md_history/synced_device_manager.js b/chrome/browser/resources/md_history/synced_device_manager.js index 8ad6a70..6dd7f78 100644 --- a/chrome/browser/resources/md_history/synced_device_manager.js +++ b/chrome/browser/resources/md_history/synced_device_manager.js
@@ -267,14 +267,6 @@ }, /** - * End fetching synced tabs when sync is disabled. - */ - tabSyncDisabled: function() { - this.fetchingSyncedTabs_ = false; - this.clearDisplayedSyncedDevices_(); - }, - - /** * Get called when user's sign in state changes, this will affect UI of synced * tabs page. Sign in promo gets displayed when user is signed out, and * different messages are shown when there are no synced tabs.
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_dialog.html b/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_dialog.html index ab992e5..3856ef2 100644 --- a/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_dialog.html +++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_dialog.html
@@ -91,7 +91,7 @@ scrollable> <iron-list items="[[getUnpaired_(deviceList.*)]]" selection-enabled selected-item="{{selectedItem}}" - scroll-target="container" tabindex="0"> + scroll-target="container"> <template> <bluetooth-device-list-item device="[[item]]" tabindex$="[[tabIndex]]">
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html index 4d5c64a8..5560b673e 100644 --- a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html +++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html
@@ -39,17 +39,18 @@ </style> <settings-animated-pages id="pages" section="bluetooth"> <neon-animatable route-path="default"> - <div class="settings-box first"> + <div class="settings-box first" + on-tap="toggleDeviceListExpanded_"> <iron-icon icon="settings:bluetooth"></iron-icon> <span class="middle">$i18n{bluetoothEnable}</span> <cr-expand-button id="expandListButton" alt="$i18n{bluetoothExpandA11yLabel}" - hidden$="[[!bluetoothEnabled]]" - expanded="{{deviceListExpanded}}"> + hidden$="[[!bluetoothEnabled_]]" + expanded="{{deviceListExpanded_}}"> </cr-expand-button> <paper-toggle-button id="enableBluetooth" - checked="{{bluetoothEnabled}}" - disabled="[[!adapterState.available]]" + checked="{{bluetoothEnabled_}}" + disabled="[[!adapterState_.available]]" on-change="onBluetoothEnabledChange_"> </paper-toggle-button> <cr-policy-pref-indicator @@ -57,13 +58,13 @@ hidden="[[prefs.cros.device.allow_bluetooth.value]]"> </cr-policy-pref-indicator> </div> - <iron-collapse opened="[[canShowDeviceList_(bluetoothEnabled, - deviceListExpanded)]]"> + <iron-collapse opened="[[canShowDeviceList_(bluetoothEnabled_, + deviceListExpanded_)]]"> <div id="deviceList" class="list-frame vertical-list" on-device-event="onDeviceEvent_"> <div id="container" class="layout vertical" scrollable> - <iron-list items="[[getPairedOrConnecting_(deviceList.*)]]" - selection-enabled selected-item="{{selectedItem}}" + <iron-list items="[[getPairedOrConnecting_(deviceList_.*)]]" + selection-enabled selected-item="{{selectedItem_}}" scroll-target="container"> <template> <bluetooth-device-list-item device="[[item]]" @@ -73,11 +74,11 @@ </iron-list> </div> <div class="no-devices layout horizontal center" - hidden$="[[haveDevices_(deviceList.*)]]"> + hidden$="[[haveDevices_(deviceList_.*)]]"> $i18n{bluetoothNoDevices} </div> </div> - <div class="settings-box" hidden$="[[!bluetoothEnabled]]"> + <div class="settings-box" hidden$="[[!bluetoothEnabled_]]"> <paper-button class="primary-button" on-tap="onAddDeviceTap_"> $i18n{bluetoothAddDevice} </paper-button> @@ -86,17 +87,17 @@ </neon-animatable> </settings-animated-pages> - <template is="dom-if" if="[[deviceListExpanded]]"> + <template is="dom-if" if="[[deviceListExpanded_]]"> <bluetooth-device-dialog id="deviceDialog" - adapter-state="[[adapterState]]" - device-list="[[deviceList]]" - dialog-id="[[dialogId]]" + adapter-state="[[adapterState_]]" + device-list="[[deviceList_]]" + dialog-id="[[dialogId_]]" on-close="onDialogClosed_" - error-message="[[errorMessage]]" + error-message="[[errorMessage_]]" on-device-event="onDeviceEvent_" on-response="onResponse_" - pairing-device="[[pairingDevice]]" - pairing-event="[[pairingEvent]]"> + pairing-device="[[pairingDevice_]]" + pairing-event="[[pairingEvent_]]"> </bluetooth-device-dialog> </template>
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js index e6a6e6d..3c17c62 100644 --- a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js +++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js
@@ -35,15 +35,21 @@ behaviors: [I18nBehavior, CrScrollableBehavior], properties: { - /** Whether bluetooth is enabled. */ - bluetoothEnabled: { + /** Preferences state. */ + prefs: { + type: Object, + notify: true, + }, + + /** @private */ + bluetoothEnabled_: { type: Boolean, value: false, observer: 'bluetoothEnabledChanged_', }, - /** Whether the device list is expanded. */ - deviceListExpanded: { + /** @private */ + deviceListExpanded_: { type: Boolean, value: false, }, @@ -51,14 +57,16 @@ /** * The cached bluetooth adapter state. * @type {!chrome.bluetooth.AdapterState|undefined} + * @private */ - adapterState: Object, + adapterState_: Object, /** * The ordered list of bluetooth devices. * @type {!Array<!chrome.bluetooth.Device>} + * @private */ - deviceList: { + deviceList_: { type: Array, value: function() { return []; @@ -68,8 +76,9 @@ /** * Reflects the iron-list selecteditem property. * @type {!chrome.bluetooth.Device} + * @private */ - selectedItem: { + selectedItem_: { type: Object, observer: 'selectedItemChanged_', }, @@ -80,33 +89,34 @@ * 'pairDevice', or 'connectError'. This allows a seamless transition * between dialogs. Note: This property should be set before opening the * dialog and setting the property will not itself cause the dialog to open. + * @private */ - dialogId: String, + dialogId_: String, /** * Current Pairing device. * @type {?chrome.bluetooth.Device|undefined} + * @private */ - pairingDevice: Object, + pairingDevice_: Object, /** * Current Pairing event. * @type {?chrome.bluetoothPrivate.PairingEvent|undefined} + * @private */ - pairingEvent: Object, + pairingEvent_: Object, - /** The translated error message to show when a connect error occurs. */ - errorMessage: String, - - /** Preferences state. */ - prefs: { - type: Object, - notify: true, - }, + /** + * The translated error message to show when a connect error occurs. + * @private + */ + errorMessage_: String, /** * Interface for bluetooth calls. May be overriden by tests. * @type {Bluetooth} + * @private */ bluetooth: { type: Object, @@ -116,6 +126,7 @@ /** * Interface for bluetoothPrivate calls. May be overriden by tests. * @type {BluetoothPrivate} + * @private */ bluetoothPrivate: { type: Object, @@ -203,38 +214,41 @@ /** @private */ bluetoothEnabledChanged_: function() { // When bluetooth is enabled, auto-expand the device list. - if (this.bluetoothEnabled) - this.deviceListExpanded = true; + if (this.bluetoothEnabled_) + this.deviceListExpanded_ = true; }, /** @private */ selectedItemChanged_: function() { - if (this.selectedItem) - this.connectDevice_(this.selectedItem); + if (this.selectedItem_) + this.connectDevice_(this.selectedItem_); + }, + + /** @private */ + toggleDeviceListExpanded_: function() { + this.deviceListExpanded_ = !this.deviceListExpanded_; }, /** - * @param {boolean} bluetoothEnabled - * @param {boolean} deviceListExpanded * @return {boolean} Whether the <iron-collapse> can be shown. * @private */ - canShowDeviceList_: function(bluetoothEnabled, deviceListExpanded) { - return bluetoothEnabled && deviceListExpanded; + canShowDeviceList_: function() { + return this.bluetoothEnabled_ && this.deviceListExpanded_; }, /** * If bluetooth is enabled, request the complete list of devices and update - * |deviceList|. + * this.deviceList_. * @private */ updateDeviceList_: function() { - if (!this.bluetoothEnabled) { - this.deviceList = []; + if (!this.bluetoothEnabled_) { + this.deviceList_ = []; return; } this.bluetooth.getDevices(function(devices) { - this.deviceList = devices; + this.deviceList_ = devices; this.updateScrollableContents(); }.bind(this)); }, @@ -245,7 +259,7 @@ */ onBluetoothEnabledChange_: function() { this.bluetoothPrivate.setAdapterState( - {powered: this.bluetoothEnabled}, function() { + {powered: this.bluetoothEnabled_}, function() { if (chrome.runtime.lastError) { console.error( 'Error enabling bluetooth: ' + @@ -260,8 +274,8 @@ * @private */ onBluetoothAdapterStateChanged_: function(state) { - this.adapterState = state; - this.bluetoothEnabled = state.powered; + this.adapterState_ = state; + this.bluetoothEnabled_ = state.powered; this.updateDeviceList_(); }, @@ -272,16 +286,16 @@ */ onBluetoothDeviceUpdated_: function(device) { var address = device.address; - if (this.dialogId && this.pairingDevice && - this.pairingDevice.address == address) { - this.pairingDevice = device; + if (this.dialogId_ && this.pairingDevice_ && + this.pairingDevice_.address == address) { + this.pairingDevice_ = device; } var index = this.getDeviceIndex_(address); if (index >= 0) { - this.set('deviceList.' + index, device); + this.set('deviceList_.' + index, device); return; } - this.push('deviceList', device); + this.push('deviceList_', device); }, /** @@ -294,12 +308,12 @@ var index = this.getDeviceIndex_(address); if (index < 0) return; - this.splice('deviceList', index, 1); + this.splice('deviceList_', index, 1); }, /** @private */ startDiscovery_: function() { - if (!this.adapterState || this.adapterState.discovering) + if (!this.adapterState_ || this.adapterState_.discovering) return; if (!this.bluetoothPrivateOnPairingListener_) { @@ -323,7 +337,7 @@ /** @private */ stopDiscovery_: function() { - if (!this.get('adapterState.discovering')) + if (!this.get('adapterState_.discovering')) return; if (this.bluetoothPrivateOnPairingListener_) { @@ -347,17 +361,17 @@ * @private */ onBluetoothPrivateOnPairing_: function(e) { - if (!this.dialogId || !this.pairingDevice || - e.device.address != this.pairingDevice.address) { + if (!this.dialogId_ || !this.pairingDevice_ || + e.device.address != this.pairingDevice_.address) { return; } if (e.pairing == chrome.bluetoothPrivate.PairingEventType.KEYS_ENTERED && - e.passkey === undefined && this.pairingEvent) { + e.passkey === undefined && this.pairingEvent_) { // 'keysEntered' event might not include the updated passkey so preserve // the current one. - e.passkey = this.pairingEvent.passkey; + e.passkey = this.pairingEvent_.passkey; } - this.pairingEvent = e; + this.pairingEvent_ = e; }, /** @private */ @@ -410,9 +424,9 @@ * @private */ getDeviceIndex_: function(address) { - var len = this.deviceList.length; + var len = this.deviceList_.length; for (var i = 0; i < len; ++i) { - if (this.deviceList[i].address == address) + if (this.deviceList_[i].address == address) return i; } return -1; @@ -432,18 +446,17 @@ * @private */ getPairedOrConnecting_: function() { - return this.deviceList.filter(function(device) { + return this.deviceList_.filter(function(device) { return !!device.paired || !!device.connecting; }); }, /** - * @param {Object} deviceListChanges Changes to the deviceList Array. * @return {boolean} True if deviceList contains any paired devices. * @private */ - haveDevices_: function(deviceListChanges) { - return this.deviceList.findIndex(function(d) { + haveDevices_: function() { + return this.deviceList_.findIndex(function(d) { return !!d.paired; }) != -1; }, @@ -456,8 +469,8 @@ // If the device is not paired, show the pairing dialog. if (!device.paired) { // Set the pairing device and clear any pairing event. - this.pairingDevice = device; - this.pairingEvent = null; + this.pairingDevice_ = device; + this.pairingEvent_ = null; this.openDialog_('pairDevice'); } @@ -486,9 +499,9 @@ var name = this.getDeviceName_(device); var id = 'bluetooth_connect_' + error; if (this.i18nExists(id)) { - this.errorMessage = this.i18n(id, name); + this.errorMessage_ = this.i18n(id, name); } else { - this.errorMessage = error; + this.errorMessage_ = error; console.error('Unexpected error connecting to: ' + name + ': ' + error); } this.openDialog_('connectError'); @@ -539,12 +552,12 @@ * @private */ openDialog_: function(dialogId) { - if (this.dialogId) { + if (this.dialogId_) { // Dialog already opened, just update the contents. - this.dialogId = dialogId; + this.dialogId_ = dialogId; return; } - this.dialogId = dialogId; + this.dialogId_ = dialogId; // Call flush so that the dialog gets sized correctly before it is opened. Polymer.dom.flush(); var dialog = this.$$('#deviceDialog'); @@ -555,8 +568,8 @@ /** @private */ onDialogClosed_: function() { this.stopDiscovery_(); - this.dialogId = ''; - this.pairingDevice = null; - this.pairingEvent = null; + this.dialogId_ = ''; + this.pairingDevice_ = null; + this.pairingEvent_ = null; }, });
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.js b/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.js index 8e243d3..5d3a865 100644 --- a/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.js +++ b/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.js
@@ -81,9 +81,11 @@ /** * Handles tapping on the "Add address" button. + * @param {!Event} e The polymer event. * @private */ - onAddAddressTap_: function() { + onAddAddressTap_: function(e) { + e.preventDefault(); this.activeAddress = {}; this.showAddressDialog_ = true; }, @@ -95,9 +97,11 @@ /** * Handles tapping on the "Edit" address button. + * @param {!Event} e The polymer event. * @private */ - onMenuEditAddressTap_: function() { + onMenuEditAddressTap_: function(e) { + e.preventDefault(); if (this.activeAddress.metadata.isLocal) this.showAddressDialog_ = true; else @@ -137,6 +141,7 @@ * @private */ onAddCreditCardTap_: function(e) { + e.preventDefault(); var date = new Date(); // Default to current month/year. var expirationMonth = date.getMonth() + 1; // Months are 0 based. this.activeCreditCard = { @@ -153,9 +158,11 @@ /** * Handles tapping on the "Edit" credit card button. + * @param {!Event} e The polymer event. * @private */ - onMenuEditCreditCardTap_: function() { + onMenuEditCreditCardTap_: function(e) { + e.preventDefault(); if (this.activeCreditCard.metadata.isLocal) this.showCreditCardDialog_ = true; else
diff --git a/chrome/browser/resources/settings/people_page/change_picture.html b/chrome/browser/resources/settings/people_page/change_picture.html index b9f4508..cc0ee2f 100644 --- a/chrome/browser/resources/settings/people_page/change_picture.html +++ b/chrome/browser/resources/settings/people_page/change_picture.html
@@ -18,6 +18,7 @@ #container { -webkit-margin-start: 16px; align-items: flex-start; + outline: none; padding-top: 16px; }
diff --git a/chrome/browser/resources/settings/people_page/change_picture.js b/chrome/browser/resources/settings/people_page/change_picture.js index bb3f0489..0e18c64e 100644 --- a/chrome/browser/resources/settings/people_page/change_picture.js +++ b/chrome/browser/resources/settings/people_page/change_picture.js
@@ -240,7 +240,7 @@ /** * Handler for when accessibility-specific keys are pressed. - * @param {!{detail: !{key: string}}} e + * @param {!{detail: !{key: string, keyboardEvent: Object}}} e */ onKeysPress_: function(e) { if (!this.selectedItem_) @@ -268,6 +268,7 @@ } while (this.selectedItem_.hidden); this.lastSelectedImageType_ = this.selectedItem_.dataset.type; + e.detail.keyboardEvent.preventDefault(); break; case 'down': @@ -279,6 +280,7 @@ } while (this.selectedItem_.hidden); this.lastSelectedImageType_ = this.selectedItem_.dataset.type; + e.detail.keyboardEvent.preventDefault(); break; case 'enter':
diff --git a/chrome/browser/resources/signin/sync_confirmation/sync_confirmation.html b/chrome/browser/resources/signin/sync_confirmation/sync_confirmation.html index 32517dc..ca7b87e 100644 --- a/chrome/browser/resources/signin/sync_confirmation/sync_confirmation.html +++ b/chrome/browser/resources/signin/sync_confirmation/sync_confirmation.html
@@ -49,6 +49,10 @@ </div> </div> <div class="message-container"> + <!-- + "Chrome sync" is the Google Cloud Based services used for sync. Thus + this section uses the Chrome logo even for Chromium builds. + --> <div id="chrome-logo" class="logo"></div> <div> <div class="title">$i18n{syncConfirmationChromeSyncTitle}</div> @@ -57,6 +61,10 @@ </div> </div> <div class="message-container"> + <!-- + This section uses the Google logo even for Chromium builds as the + user can personalize their Google services from this screen. + --> <div id="googleg-logo" class="logo"></div> <div> <div class="title">
diff --git a/chrome/browser/ui/search/search_ipc_router.cc b/chrome/browser/ui/search/search_ipc_router.cc index 593aed7..f57f188 100644 --- a/chrome/browser/ui/search/search_ipc_router.cc +++ b/chrome/browser/ui/search/search_ipc_router.cc
@@ -216,7 +216,9 @@ } void SearchIPCRouter::OnLogMostVisitedImpression( - int page_seq_no, int position, NTPLoggingTileSource tile_source) const { + int page_seq_no, + int position, + ntp_tiles::NTPTileSource tile_source) const { if (page_seq_no != commit_counter_) return; @@ -229,7 +231,9 @@ } void SearchIPCRouter::OnLogMostVisitedNavigation( - int page_seq_no, int position, NTPLoggingTileSource tile_source) const { + int page_seq_no, + int position, + ntp_tiles::NTPTileSource tile_source) const { if (page_seq_no != commit_counter_) return;
diff --git a/chrome/browser/ui/search/search_ipc_router.h b/chrome/browser/ui/search/search_ipc_router.h index a097dbd0..b878018 100644 --- a/chrome/browser/ui/search/search_ipc_router.h +++ b/chrome/browser/ui/search/search_ipc_router.h
@@ -13,6 +13,7 @@ #include "base/time/time.h" #include "chrome/common/search/instant_types.h" #include "chrome/common/search/ntp_logging_events.h" +#include "components/ntp_tiles/ntp_tile_source.h" #include "components/omnibox/common/omnibox_focus_state.h" #include "content/public/browser/web_contents_observer.h" #include "ui/base/window_open_disposition.h" @@ -58,12 +59,12 @@ // Called to log an impression from a given provider on the New Tab Page. virtual void OnLogMostVisitedImpression( int position, - NTPLoggingTileSource tile_source) = 0; + ntp_tiles::NTPTileSource tile_source) = 0; // Called to log a navigation from a given provider on the New Tab Page. virtual void OnLogMostVisitedNavigation( int position, - NTPLoggingTileSource tile_source) = 0; + ntp_tiles::NTPTileSource tile_source) = 0; // Called when the page wants to paste the |text| (or the clipboard contents // if the |text| is empty) into the omnibox. @@ -180,10 +181,10 @@ base::TimeDelta time) const; void OnLogMostVisitedImpression(int page_seq_no, int position, - NTPLoggingTileSource tile_source) const; + ntp_tiles::NTPTileSource tile_source) const; void OnLogMostVisitedNavigation(int page_seq_no, int position, - NTPLoggingTileSource tile_source) const; + ntp_tiles::NTPTileSource tile_source) const; void OnPasteAndOpenDropDown(int page_seq_no, const base::string16& text) const; void OnChromeIdentityCheck(int page_seq_no,
diff --git a/chrome/browser/ui/search/search_ipc_router_unittest.cc b/chrome/browser/ui/search/search_ipc_router_unittest.cc index 55cd978..6b183c0d 100644 --- a/chrome/browser/ui/search/search_ipc_router_unittest.cc +++ b/chrome/browser/ui/search/search_ipc_router_unittest.cc
@@ -56,9 +56,9 @@ MOCK_METHOD2(OnLogEvent, void(NTPLoggingEventType event, base::TimeDelta time)); MOCK_METHOD2(OnLogMostVisitedImpression, - void(int position, NTPLoggingTileSource tile_source)); + void(int position, ntp_tiles::NTPTileSource tile_source)); MOCK_METHOD2(OnLogMostVisitedNavigation, - void(int position, NTPLoggingTileSource tile_source)); + void(int position, ntp_tiles::NTPTileSource tile_source)); MOCK_METHOD1(PasteIntoOmnibox, void(const base::string16&)); MOCK_METHOD1(OnChromeIdentityCheck, void(const base::string16& identity)); MOCK_METHOD0(OnHistorySyncCheck, void()); @@ -291,14 +291,16 @@ SetupMockDelegateAndPolicy(); MockSearchIPCRouterPolicy* policy = GetSearchIPCRouterPolicy(); EXPECT_CALL(*mock_delegate(), - OnLogMostVisitedImpression(3, NTPLoggingTileSource::SERVER)).Times(1); + OnLogMostVisitedImpression( + 3, ntp_tiles::NTPTileSource::SUGGESTIONS_SERVICE)) + .Times(1); EXPECT_CALL(*policy, ShouldProcessLogEvent()).Times(1) .WillOnce(testing::Return(true)); content::WebContents* contents = web_contents(); OnMessageReceived(ChromeViewHostMsg_LogMostVisitedImpression( contents->GetRenderViewHost()->GetRoutingID(), GetSearchIPCRouterSeqNo(), - 3, NTPLoggingTileSource::SERVER)); + 3, ntp_tiles::NTPTileSource::SUGGESTIONS_SERVICE)); } TEST_F(SearchIPCRouterTest, ProcessLogMostVisitedNavigationMsg) { @@ -306,14 +308,16 @@ SetupMockDelegateAndPolicy(); MockSearchIPCRouterPolicy* policy = GetSearchIPCRouterPolicy(); EXPECT_CALL(*mock_delegate(), - OnLogMostVisitedNavigation(3, NTPLoggingTileSource::SERVER)).Times(1); + OnLogMostVisitedNavigation( + 3, ntp_tiles::NTPTileSource::SUGGESTIONS_SERVICE)) + .Times(1); EXPECT_CALL(*policy, ShouldProcessLogEvent()).Times(1) .WillOnce(testing::Return(true)); content::WebContents* contents = web_contents(); OnMessageReceived(ChromeViewHostMsg_LogMostVisitedNavigation( contents->GetRenderViewHost()->GetRoutingID(), GetSearchIPCRouterSeqNo(), - 3, NTPLoggingTileSource::SERVER)); + 3, ntp_tiles::NTPTileSource::SUGGESTIONS_SERVICE)); } TEST_F(SearchIPCRouterTest, ProcessChromeIdentityCheckMsg) {
diff --git a/chrome/browser/ui/search/search_tab_helper.cc b/chrome/browser/ui/search/search_tab_helper.cc index fde20f8..4264cbd 100644 --- a/chrome/browser/ui/search/search_tab_helper.cc +++ b/chrome/browser/ui/search/search_tab_helper.cc
@@ -387,7 +387,8 @@ } void SearchTabHelper::OnLogMostVisitedImpression( - int position, NTPLoggingTileSource tile_source) { + int position, + ntp_tiles::NTPTileSource tile_source) { // TODO(kmadhusu): Move platform specific code from here and get rid of #ifdef. #if !defined(OS_ANDROID) NTPUserDataLogger::GetOrCreateFromWebContents( @@ -396,7 +397,8 @@ } void SearchTabHelper::OnLogMostVisitedNavigation( - int position, NTPLoggingTileSource tile_source) { + int position, + ntp_tiles::NTPTileSource tile_source) { // TODO(kmadhusu): Move platform specific code from here and get rid of #ifdef. #if !defined(OS_ANDROID) NTPUserDataLogger::GetOrCreateFromWebContents(
diff --git a/chrome/browser/ui/search/search_tab_helper.h b/chrome/browser/ui/search/search_tab_helper.h index 31b363c..d1a0bede 100644 --- a/chrome/browser/ui/search/search_tab_helper.h +++ b/chrome/browser/ui/search/search_tab_helper.h
@@ -17,6 +17,7 @@ #include "chrome/browser/ui/search/search_model.h" #include "chrome/common/search/instant_types.h" #include "chrome/common/search/ntp_logging_events.h" +#include "components/ntp_tiles/ntp_tile_source.h" #include "components/omnibox/common/omnibox_focus_state.h" #include "content/public/browser/reload_type.h" #include "content/public/browser/web_contents_observer.h" @@ -146,10 +147,12 @@ void OnUndoMostVisitedDeletion(const GURL& url) override; void OnUndoAllMostVisitedDeletions() override; void OnLogEvent(NTPLoggingEventType event, base::TimeDelta time) override; - void OnLogMostVisitedImpression(int position, - NTPLoggingTileSource tile_source) override; - void OnLogMostVisitedNavigation(int position, - NTPLoggingTileSource tile_source) override; + void OnLogMostVisitedImpression( + int position, + ntp_tiles::NTPTileSource tile_source) override; + void OnLogMostVisitedNavigation( + int position, + ntp_tiles::NTPTileSource tile_source) override; void PasteIntoOmnibox(const base::string16& text) override; void OnChromeIdentityCheck(const base::string16& identity) override; void OnHistorySyncCheck() override;
diff --git a/chrome/browser/ui/search/search_tab_helper_unittest.cc b/chrome/browser/ui/search/search_tab_helper_unittest.cc index bacf1d5..63dccd3 100644 --- a/chrome/browser/ui/search/search_tab_helper_unittest.cc +++ b/chrome/browser/ui/search/search_tab_helper_unittest.cc
@@ -58,9 +58,9 @@ MOCK_METHOD2(OnLogEvent, void(NTPLoggingEventType event, base::TimeDelta time)); MOCK_METHOD2(OnLogMostVisitedImpression, - void(int position, NTPLoggingTileSource tile_source)); + void(int position, ntp_tiles::NTPTileSource tile_source)); MOCK_METHOD2(OnLogMostVisitedNavigation, - void(int position, NTPLoggingTileSource tile_source)); + void(int position, ntp_tiles::NTPTileSource tile_source)); MOCK_METHOD1(PasteIntoOmnibox, void(const base::string16&)); MOCK_METHOD1(OnChromeIdentityCheck, void(const base::string16& identity)); MOCK_METHOD0(OnHistorySyncCheck, void());
diff --git a/chrome/browser/ui/startup/default_browser_infobar_delegate.cc b/chrome/browser/ui/startup/default_browser_infobar_delegate.cc index 5bc0e8c..e2b9f575 100644 --- a/chrome/browser/ui/startup/default_browser_infobar_delegate.cc +++ b/chrome/browser/ui/startup/default_browser_infobar_delegate.cc
@@ -4,12 +4,13 @@ #include "chrome/browser/ui/startup/default_browser_infobar_delegate.h" +#include <memory> + #include "base/metrics/histogram_macros.h" #include "base/threading/thread_task_runner_handle.h" #include "chrome/browser/ui/startup/default_browser_prompt.h" #include "chrome/grit/chromium_strings.h" #include "chrome/grit/generated_resources.h" -#include "chrome/grit/theme_resources.h" #include "components/infobars/core/infobar.h" #include "content/public/browser/user_metrics.h" #include "ui/base/l10n/l10n_util.h" @@ -17,24 +18,10 @@ #if defined(OS_WIN) #include "base/win/windows_version.h" -#include "components/variations/variations_associated_data.h" -#include "ui/base/material_design/material_design_controller.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/gfx/color_palette.h" -#include "ui/gfx/paint_vector_icon.h" #endif namespace chrome { -#if defined(OS_WIN) -namespace { - -// Experiment where different styles for the default browser prompt are tested. -constexpr char kDefaultBrowserPromptStyle[] = "DefaultBrowserPromptStyle"; - -} // namespace -#endif - bool IsStickyDefaultBrowserPromptEnabled() { #if defined(OS_WIN) // The flow to set the default browser is only asynchronous on Windows 10+. @@ -83,13 +70,7 @@ infobars::InfoBarDelegate::Type DefaultBrowserInfoBarDelegate::GetInfoBarType() const { -#if defined(OS_WIN) - std::string infobar_type = variations::GetVariationParamValue( - kDefaultBrowserPromptStyle, "InfoBarType"); - return (infobar_type == "PageAction") ? PAGE_ACTION_TYPE : WARNING_TYPE; -#else return PAGE_ACTION_TYPE; -#endif } infobars::InfoBarDelegate::InfoBarIdentifier @@ -97,29 +78,10 @@ return DEFAULT_BROWSER_INFOBAR_DELEGATE; } -int DefaultBrowserInfoBarDelegate::GetIconId() const { - return IDR_PRODUCT_LOGO_32; +gfx::VectorIconId DefaultBrowserInfoBarDelegate::GetVectorIconId() const { + return gfx::VectorIconId::PRODUCT; } -#if defined(OS_WIN) -gfx::Image DefaultBrowserInfoBarDelegate::GetIcon() const { - // Experiment for the chrome product icon used on the default browser - // prompt. - std::string icon_color = variations::GetVariationParamValue( - kDefaultBrowserPromptStyle, "IconColor"); - if (icon_color == "Colored") { - return ResourceBundle::GetSharedInstance().GetNativeImageNamed( - IDR_PRODUCT_LOGO_16); - } - if ((icon_color == "Blue") && (GetInfoBarType() == WARNING_TYPE)) { - // WARNING_TYPE infobars use orange icons by default. - return gfx::Image( - gfx::CreateVectorIcon(GetVectorIconId(), 16, gfx::kGoogleBlue500)); - } - return ConfirmInfoBarDelegate::GetIcon(); -} -#endif // defined(OS_WIN) - bool DefaultBrowserInfoBarDelegate::ShouldExpire( const NavigationDetails& details) const { return should_expire_ && ConfirmInfoBarDelegate::ShouldExpire(details);
diff --git a/chrome/browser/ui/startup/default_browser_infobar_delegate.h b/chrome/browser/ui/startup/default_browser_infobar_delegate.h index 26818da..50b4c81f 100644 --- a/chrome/browser/ui/startup/default_browser_infobar_delegate.h +++ b/chrome/browser/ui/startup/default_browser_infobar_delegate.h
@@ -56,10 +56,7 @@ // ConfirmInfoBarDelegate: Type GetInfoBarType() const override; infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override; - int GetIconId() const override; -#if defined(OS_WIN) - gfx::Image GetIcon() const override; -#endif // defined(OS_WIN) + gfx::VectorIconId GetVectorIconId() const override; bool ShouldExpire(const NavigationDetails& details) const override; void InfoBarDismissed() override; base::string16 GetMessageText() const override;
diff --git a/chrome/browser/ui/webui/foreign_session_handler.cc b/chrome/browser/ui/webui/foreign_session_handler.cc index 62f33c2f..df6d257 100644 --- a/chrome/browser/ui/webui/foreign_session_handler.cc +++ b/chrome/browser/ui/webui/foreign_session_handler.cc
@@ -237,13 +237,6 @@ HandleGetForeignSessions(nullptr); } -bool ForeignSessionHandler::IsTabSyncEnabled() { - Profile* profile = Profile::FromWebUI(web_ui()); - browser_sync::ProfileSyncService* service = - ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile); - return service && service->GetActiveDataTypes().Has(syncer::PROXY_TABS); -} - base::string16 ForeignSessionHandler::FormatSessionTime( const base::Time& time) { // Return a time like "1 hour ago", "2 days ago", etc. @@ -338,9 +331,7 @@ session_list.Append(std::move(session_data)); } } - base::FundamentalValue tab_sync_enabled(IsTabSyncEnabled()); - web_ui()->CallJavascriptFunctionUnsafe("setForeignSessions", session_list, - tab_sync_enabled); + web_ui()->CallJavascriptFunctionUnsafe("setForeignSessions", session_list); } void ForeignSessionHandler::HandleOpenForeignSession(
diff --git a/chrome/browser/ui/webui/foreign_session_handler.h b/chrome/browser/ui/webui/foreign_session_handler.h index a85312769..d41d0ec37 100644 --- a/chrome/browser/ui/webui/foreign_session_handler.h +++ b/chrome/browser/ui/webui/foreign_session_handler.h
@@ -61,9 +61,6 @@ void OnSyncConfigurationCompleted() override; void OnForeignSessionUpdated() override; - // Returns true if tab sync is enabled for this profile, otherwise false. - bool IsTabSyncEnabled(); - // Returns a string used to show the user when a session was last modified. base::string16 FormatSessionTime(const base::Time& time);
diff --git a/chrome/browser/ui/webui/ntp/ntp_user_data_logger.cc b/chrome/browser/ui/webui/ntp/ntp_user_data_logger.cc index 6e43620b..fcb0b59 100644 --- a/chrome/browser/ui/webui/ntp/ntp_user_data_logger.cc +++ b/chrome/browser/ui/webui/ntp/ntp_user_data_logger.cc
@@ -40,17 +40,6 @@ sessions); } -ntp_tiles::NTPTileSource ConvertTileSource(NTPLoggingTileSource tile_source) { - switch (tile_source) { - case NTPLoggingTileSource::CLIENT: - return ntp_tiles::NTPTileSource::TOP_SITES; - case NTPLoggingTileSource::SERVER: - return ntp_tiles::NTPTileSource::SUGGESTIONS_SERVICE; - } - NOTREACHED(); - return ntp_tiles::NTPTileSource::TOP_SITES; -} - } // namespace DEFINE_WEB_CONTENTS_USER_DATA_KEY(NTPUserDataLogger); @@ -109,7 +98,8 @@ } void NTPUserDataLogger::LogMostVisitedImpression( - int position, NTPLoggingTileSource tile_source) { + int position, + ntp_tiles::NTPTileSource tile_source) { if ((position >= kNumMostVisited) || impression_was_logged_[position]) { return; } @@ -118,8 +108,9 @@ } void NTPUserDataLogger::LogMostVisitedNavigation( - int position, NTPLoggingTileSource tile_source) { - ntp_tiles::metrics::RecordTileClick(position, ConvertTileSource(tile_source), + int position, + ntp_tiles::NTPTileSource tile_source) { + ntp_tiles::metrics::RecordTileClick(position, tile_source, ntp_tiles::metrics::THUMBNAIL); // Records the action. This will be available as a time-stamped stream @@ -172,10 +163,11 @@ if (!impression_was_logged_[i]) { break; } - if (impression_tile_source_[i] == NTPLoggingTileSource::SERVER) { + if (impression_tile_source_[i] == + ntp_tiles::NTPTileSource::SUGGESTIONS_SERVICE) { has_server_side_suggestions = true; } - tiles.emplace_back(ConvertTileSource(impression_tile_source_[i]), + tiles.emplace_back(impression_tile_source_[i], ntp_tiles::metrics::THUMBNAIL); } ntp_tiles::metrics::RecordPageImpression(tiles);
diff --git a/chrome/browser/ui/webui/ntp/ntp_user_data_logger.h b/chrome/browser/ui/webui/ntp/ntp_user_data_logger.h index 17c2861..59e967c 100644 --- a/chrome/browser/ui/webui/ntp/ntp_user_data_logger.h +++ b/chrome/browser/ui/webui/ntp/ntp_user_data_logger.h
@@ -13,6 +13,7 @@ #include "base/macros.h" #include "base/time/time.h" #include "chrome/common/search/ntp_logging_events.h" +#include "components/ntp_tiles/ntp_tile_source.h" #include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_user_data.h" @@ -39,10 +40,12 @@ void LogEvent(NTPLoggingEventType event, base::TimeDelta time); // Logs an impression on one of the NTP tiles by a given source. - void LogMostVisitedImpression(int position, NTPLoggingTileSource tile_source); + void LogMostVisitedImpression(int position, + ntp_tiles::NTPTileSource tile_source); // Logs a navigation on one of the NTP tiles by a given source. - void LogMostVisitedNavigation(int position, NTPLoggingTileSource tile_source); + void LogMostVisitedNavigation(int position, + ntp_tiles::NTPTileSource tile_source); protected: explicit NTPUserDataLogger(content::WebContents* contents); @@ -80,7 +83,7 @@ // Stores the tile source for each impression. Entries are only valid if the // corresponding entry in |impression_was_logged_| is true. - std::vector<NTPLoggingTileSource> impression_tile_source_; + std::vector<ntp_tiles::NTPTileSource> impression_tile_source_; // Whether we have already emitted NTP stats for this web contents. bool has_emitted_;
diff --git a/chrome/browser/ui/webui/ntp/ntp_user_data_logger_unittest.cc b/chrome/browser/ui/webui/ntp/ntp_user_data_logger_unittest.cc index 1dab261..46a3a1b 100644 --- a/chrome/browser/ui/webui/ntp/ntp_user_data_logger_unittest.cc +++ b/chrome/browser/ui/webui/ntp/ntp_user_data_logger_unittest.cc
@@ -16,6 +16,7 @@ #include "testing/gtest/include/gtest/gtest.h" using base::Bucket; +using ntp_tiles::NTPTileSource; using testing::ElementsAre; using testing::IsEmpty; @@ -44,7 +45,7 @@ base::TimeDelta delta = base::TimeDelta::FromMilliseconds(0); for (int i = 0; i < 8; ++i) - logger.LogMostVisitedImpression(i, NTPLoggingTileSource::SERVER); + logger.LogMostVisitedImpression(i, NTPTileSource::SUGGESTIONS_SERVICE); logger.LogEvent(NTP_ALL_TILES_LOADED, delta); EXPECT_THAT(histogram_tester.GetAllSamples("NewTabPage.NumberOfTiles"), ElementsAre(Bucket(8, 1))); @@ -75,24 +76,24 @@ base::TimeDelta delta = base::TimeDelta::FromMilliseconds(0); // Impressions increment the associated bins. - logger.LogMostVisitedImpression(0, NTPLoggingTileSource::SERVER); - logger.LogMostVisitedImpression(1, NTPLoggingTileSource::SERVER); - logger.LogMostVisitedImpression(2, NTPLoggingTileSource::SERVER); - logger.LogMostVisitedImpression(3, NTPLoggingTileSource::SERVER); - logger.LogMostVisitedImpression(4, NTPLoggingTileSource::CLIENT); - logger.LogMostVisitedImpression(5, NTPLoggingTileSource::CLIENT); - logger.LogMostVisitedImpression(6, NTPLoggingTileSource::CLIENT); - logger.LogMostVisitedImpression(7, NTPLoggingTileSource::CLIENT); + logger.LogMostVisitedImpression(0, NTPTileSource::SUGGESTIONS_SERVICE); + logger.LogMostVisitedImpression(1, NTPTileSource::SUGGESTIONS_SERVICE); + logger.LogMostVisitedImpression(2, NTPTileSource::SUGGESTIONS_SERVICE); + logger.LogMostVisitedImpression(3, NTPTileSource::SUGGESTIONS_SERVICE); + logger.LogMostVisitedImpression(4, NTPTileSource::TOP_SITES); + logger.LogMostVisitedImpression(5, NTPTileSource::TOP_SITES); + logger.LogMostVisitedImpression(6, NTPTileSource::TOP_SITES); + logger.LogMostVisitedImpression(7, NTPTileSource::TOP_SITES); // Repeated impressions for the same bins are ignored. - logger.LogMostVisitedImpression(0, NTPLoggingTileSource::SERVER); - logger.LogMostVisitedImpression(1, NTPLoggingTileSource::CLIENT); - logger.LogMostVisitedImpression(2, NTPLoggingTileSource::SERVER); - logger.LogMostVisitedImpression(3, NTPLoggingTileSource::CLIENT); + logger.LogMostVisitedImpression(0, NTPTileSource::SUGGESTIONS_SERVICE); + logger.LogMostVisitedImpression(1, NTPTileSource::TOP_SITES); + logger.LogMostVisitedImpression(2, NTPTileSource::SUGGESTIONS_SERVICE); + logger.LogMostVisitedImpression(3, NTPTileSource::TOP_SITES); // Impressions are silently ignored for tiles >= 8. - logger.LogMostVisitedImpression(8, NTPLoggingTileSource::SERVER); - logger.LogMostVisitedImpression(9, NTPLoggingTileSource::CLIENT); + logger.LogMostVisitedImpression(8, NTPTileSource::SUGGESTIONS_SERVICE); + logger.LogMostVisitedImpression(9, NTPTileSource::TOP_SITES); // The actual histograms are emitted only after the ALL_TILES_LOADED event, so // at this point everything should still be empty. @@ -125,10 +126,10 @@ GURL("http://chromium.org")); logger.NavigatedFromURLToURL(GURL("http://chromium.org"), GURL("chrome://newtab/")); - logger.LogMostVisitedImpression(0, NTPLoggingTileSource::SERVER); - logger.LogMostVisitedImpression(1, NTPLoggingTileSource::CLIENT); - logger.LogMostVisitedImpression(2, NTPLoggingTileSource::SERVER); - logger.LogMostVisitedImpression(3, NTPLoggingTileSource::CLIENT); + logger.LogMostVisitedImpression(0, NTPTileSource::SUGGESTIONS_SERVICE); + logger.LogMostVisitedImpression(1, NTPTileSource::TOP_SITES); + logger.LogMostVisitedImpression(2, NTPTileSource::SUGGESTIONS_SERVICE); + logger.LogMostVisitedImpression(3, NTPTileSource::TOP_SITES); logger.LogEvent(NTP_ALL_TILES_LOADED, delta); EXPECT_THAT( @@ -151,7 +152,7 @@ TestNTPUserDataLogger logger; - logger.LogMostVisitedNavigation(0, NTPLoggingTileSource::SERVER); + logger.LogMostVisitedNavigation(0, NTPTileSource::SUGGESTIONS_SERVICE); EXPECT_THAT( histogram_tester.GetAllSamples("NewTabPage.MostVisited"), ElementsAre(Bucket(0, 1))); @@ -162,7 +163,7 @@ histogram_tester.GetAllSamples("NewTabPage.MostVisited.client"), IsEmpty()); - logger.LogMostVisitedNavigation(1, NTPLoggingTileSource::SERVER); + logger.LogMostVisitedNavigation(1, NTPTileSource::SUGGESTIONS_SERVICE); EXPECT_THAT( histogram_tester.GetAllSamples("NewTabPage.MostVisited"), ElementsAre(Bucket(0, 1), Bucket(1, 1))); @@ -173,7 +174,7 @@ histogram_tester.GetAllSamples("NewTabPage.MostVisited.client"), IsEmpty()); - logger.LogMostVisitedNavigation(2, NTPLoggingTileSource::CLIENT); + logger.LogMostVisitedNavigation(2, NTPTileSource::TOP_SITES); EXPECT_THAT( histogram_tester.GetAllSamples("NewTabPage.MostVisited"), ElementsAre(Bucket(0, 1), Bucket(1, 1), Bucket(2, 1))); @@ -184,7 +185,7 @@ histogram_tester.GetAllSamples("NewTabPage.MostVisited.client"), ElementsAre(Bucket(2, 1))); - logger.LogMostVisitedNavigation(3, NTPLoggingTileSource::CLIENT); + logger.LogMostVisitedNavigation(3, NTPTileSource::TOP_SITES); EXPECT_THAT( histogram_tester.GetAllSamples("NewTabPage.MostVisited"), ElementsAre(Bucket(0, 1), Bucket(1, 1), Bucket(2, 1), Bucket(3, 1))); @@ -196,10 +197,10 @@ ElementsAre(Bucket(2, 1), Bucket(3, 1))); // Navigations always increase. - logger.LogMostVisitedNavigation(0, NTPLoggingTileSource::SERVER); - logger.LogMostVisitedNavigation(1, NTPLoggingTileSource::CLIENT); - logger.LogMostVisitedNavigation(2, NTPLoggingTileSource::SERVER); - logger.LogMostVisitedNavigation(3, NTPLoggingTileSource::CLIENT); + logger.LogMostVisitedNavigation(0, NTPTileSource::SUGGESTIONS_SERVICE); + logger.LogMostVisitedNavigation(1, NTPTileSource::TOP_SITES); + logger.LogMostVisitedNavigation(2, NTPTileSource::SUGGESTIONS_SERVICE); + logger.LogMostVisitedNavigation(3, NTPTileSource::TOP_SITES); EXPECT_THAT( histogram_tester.GetAllSamples("NewTabPage.MostVisited"), ElementsAre(Bucket(0, 2), Bucket(1, 2), Bucket(2, 2), Bucket(3, 2)));
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn index 4b762851..de6f3b74 100644 --- a/chrome/common/BUILD.gn +++ b/chrome/common/BUILD.gn
@@ -192,6 +192,7 @@ "//components/metrics:net", "//components/nacl/common:process_type", "//components/nacl/common:switches", + "//components/ntp_tiles", "//components/offline_pages:switches", "//components/omnibox/common", "//components/password_manager/content/common:mojo_interfaces",
diff --git a/chrome/common/DEPS b/chrome/common/DEPS index fe9e090..1a6e250a 100644 --- a/chrome/common/DEPS +++ b/chrome/common/DEPS
@@ -17,6 +17,7 @@ "+components/metrics/client_info.h", "+components/metrics/metrics_pref_names.h", "+components/nacl/common", + "+components/ntp_tiles", "+components/offline_pages/offline_page_feature.h", "+components/password_manager/core/common", "+components/policy/core/common",
diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h index 40cfebb..ff49fe9 100644 --- a/chrome/common/render_messages.h +++ b/chrome/common/render_messages.h
@@ -18,6 +18,7 @@ #include "components/content_settings/core/common/content_settings.h" #include "components/content_settings/core/common/content_settings_pattern.h" #include "components/content_settings/core/common/content_settings_types.h" +#include "components/ntp_tiles/ntp_tile_source.h" #include "components/omnibox/common/omnibox_focus_state.h" #include "content/public/common/browser_controls_state.h" #include "content/public/common/webplugininfo.h" @@ -171,8 +172,8 @@ IPC_ENUM_TRAITS_MAX_VALUE(NTPLoggingEventType, NTP_EVENT_TYPE_LAST) -IPC_ENUM_TRAITS_MAX_VALUE(NTPLoggingTileSource, - NTPLoggingTileSource::LAST) +IPC_ENUM_TRAITS_MAX_VALUE(ntp_tiles::NTPTileSource, + ntp_tiles::NTPTileSource::LAST) IPC_ENUM_TRAITS_MAX_VALUE(WebApplicationInfo::MobileCapable, WebApplicationInfo::MOBILE_CAPABLE_APPLE) @@ -537,14 +538,14 @@ IPC_MESSAGE_ROUTED3(ChromeViewHostMsg_LogMostVisitedImpression, int /* page_seq_no */, int /* position */, - NTPLoggingTileSource /* tile_source */) + ntp_tiles::NTPTileSource /* tile_source */) // Logs a navigation on one of the Most Visited tile on the InstantExtended // New Tab Page. IPC_MESSAGE_ROUTED3(ChromeViewHostMsg_LogMostVisitedNavigation, int /* page_seq_no */, int /* position */, - NTPLoggingTileSource /* tile_source */) + ntp_tiles::NTPTileSource /* tile_source */) // The Instant page asks whether the user syncs its history. IPC_MESSAGE_ROUTED1(ChromeViewHostMsg_HistorySyncCheck,
diff --git a/chrome/common/search/ntp_logging_events.h b/chrome/common/search/ntp_logging_events.h index cbb1100..51893222 100644 --- a/chrome/common/search/ntp_logging_events.h +++ b/chrome/common/search/ntp_logging_events.h
@@ -53,13 +53,4 @@ NTP_EVENT_TYPE_LAST = NTP_ALL_TILES_LOADED }; -// The source of an NTP tile. -// Note: Keep in sync with browser/resources/local_ntp/most_visited_single.js. -// TODO(treib): Merge this into MostVisitedSource from components/ntp_tiles. -enum class NTPLoggingTileSource { - CLIENT = 0, - SERVER = 1, - LAST = SERVER -}; - #endif // CHROME_COMMON_SEARCH_NTP_LOGGING_EVENTS_H_
diff --git a/chrome/renderer/searchbox/DEPS b/chrome/renderer/searchbox/DEPS index 3daf8ae6..0309349 100644 --- a/chrome/renderer/searchbox/DEPS +++ b/chrome/renderer/searchbox/DEPS
@@ -1,3 +1,4 @@ include_rules = [ "+components/favicon_base", + "+components/ntp_tiles", ]
diff --git a/chrome/renderer/searchbox/searchbox.cc b/chrome/renderer/searchbox/searchbox.cc index 53d21e9..6262ed56 100644 --- a/chrome/renderer/searchbox/searchbox.cc +++ b/chrome/renderer/searchbox/searchbox.cc
@@ -267,13 +267,13 @@ } void SearchBox::LogMostVisitedImpression(int position, - NTPLoggingTileSource tile_source) { + ntp_tiles::NTPTileSource tile_source) { render_view()->Send(new ChromeViewHostMsg_LogMostVisitedImpression( render_view()->GetRoutingID(), page_seq_no_, position, tile_source)); } void SearchBox::LogMostVisitedNavigation(int position, - NTPLoggingTileSource tile_source) { + ntp_tiles::NTPTileSource tile_source) { render_view()->Send(new ChromeViewHostMsg_LogMostVisitedNavigation( render_view()->GetRoutingID(), page_seq_no_, position, tile_source)); }
diff --git a/chrome/renderer/searchbox/searchbox.h b/chrome/renderer/searchbox/searchbox.h index 51ea59b..50e89ec 100644 --- a/chrome/renderer/searchbox/searchbox.h +++ b/chrome/renderer/searchbox/searchbox.h
@@ -13,6 +13,7 @@ #include "chrome/common/search/instant_types.h" #include "chrome/common/search/ntp_logging_events.h" #include "chrome/renderer/instant_restricted_id_cache.h" +#include "components/ntp_tiles/ntp_tile_source.h" #include "components/omnibox/common/omnibox_focus_state.h" #include "content/public/renderer/render_view_observer.h" #include "content/public/renderer/render_view_observer_tracker.h" @@ -54,10 +55,12 @@ void LogEvent(NTPLoggingEventType event); // Sends ChromeViewHostMsg_LogMostVisitedImpression to the browser. - void LogMostVisitedImpression(int position, NTPLoggingTileSource tile_source); + void LogMostVisitedImpression(int position, + ntp_tiles::NTPTileSource tile_source); // Sends ChromeViewHostMsg_LogMostVisitedNavigation to the browser. - void LogMostVisitedNavigation(int position, NTPLoggingTileSource tile_source); + void LogMostVisitedNavigation(int position, + ntp_tiles::NTPTileSource tile_source); // Sends ChromeViewHostMsg_ChromeIdentityCheck to the browser. void CheckIsUserSignedInToChromeAs(const base::string16& identity);
diff --git a/chrome/renderer/searchbox/searchbox_extension.cc b/chrome/renderer/searchbox/searchbox_extension.cc index 38ad0f9..fe57fb3 100644 --- a/chrome/renderer/searchbox/searchbox_extension.cc +++ b/chrome/renderer/searchbox/searchbox_extension.cc
@@ -22,6 +22,7 @@ #include "chrome/grit/renderer_resources.h" #include "chrome/renderer/searchbox/searchbox.h" #include "components/crx_file/id_util.h" +#include "components/ntp_tiles/ntp_tile_source.h" #include "content/public/renderer/render_view.h" #include "third_party/WebKit/public/platform/WebURLRequest.h" #include "third_party/WebKit/public/web/WebDocument.h" @@ -1019,9 +1020,10 @@ DVLOG(1) << render_view << " LogMostVisitedImpression"; - if (args[1]->Uint32Value() <= static_cast<int>(NTPLoggingTileSource::LAST)) { - NTPLoggingTileSource tile_source = - static_cast<NTPLoggingTileSource>(args[1]->Uint32Value()); + if (args[1]->Uint32Value() <= + static_cast<int>(ntp_tiles::NTPTileSource::LAST)) { + ntp_tiles::NTPTileSource tile_source = + static_cast<ntp_tiles::NTPTileSource>(args[1]->Uint32Value()); SearchBox::Get(render_view)->LogMostVisitedImpression( args[0]->IntegerValue(), tile_source); } @@ -1041,9 +1043,10 @@ DVLOG(1) << render_view << " LogMostVisitedNavigation"; - if (args[1]->Uint32Value() <= static_cast<int>(NTPLoggingTileSource::LAST)) { - NTPLoggingTileSource tile_source = - static_cast<NTPLoggingTileSource>(args[1]->Uint32Value()); + if (args[1]->Uint32Value() <= + static_cast<int>(ntp_tiles::NTPTileSource::LAST)) { + ntp_tiles::NTPTileSource tile_source = + static_cast<ntp_tiles::NTPTileSource>(args[1]->Uint32Value()); SearchBox::Get(render_view)->LogMostVisitedNavigation( args[0]->IntegerValue(), tile_source); }
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index c68c0e2..af7bdf0e 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -2165,7 +2165,7 @@ "../browser/chromeos/app_mode/kiosk_app_update_service_browsertest.cc", "../browser/chromeos/app_mode/kiosk_crash_restore_browsertest.cc", "../browser/chromeos/arc/arc_session_manager_browsertest.cc", - "../browser/chromeos/arc/auth/arc_robot_auth_browsertest.cc", + "../browser/chromeos/arc/auth/arc_robot_auth_code_fetcher_browsertest.cc", "../browser/chromeos/arc/intent_helper/arc_settings_service_browsertest.cc", "../browser/chromeos/attestation/attestation_policy_browsertest.cc", "../browser/chromeos/customization/customization_document_browsertest.cc",
diff --git a/chrome/test/chromedriver/VERSION b/chrome/test/chromedriver/VERSION index 8bd2249..e90e35f 100644 --- a/chrome/test/chromedriver/VERSION +++ b/chrome/test/chromedriver/VERSION
@@ -1 +1 @@ -2.25 +2.26
diff --git a/chrome/test/data/webui/md_history/history_metrics_test.js b/chrome/test/data/webui/md_history/history_metrics_test.js index 1f30a10..c9c6e80 100644 --- a/chrome/test/data/webui/md_history/history_metrics_test.js +++ b/chrome/test/data/webui/md_history/history_metrics_test.js
@@ -168,7 +168,7 @@ ] ), ]; - setForeignSessions(sessionList, true); + setForeignSessions(sessionList); return PolymerTest.flushTasks(); }).then(() => { assertEquals(1, histogram[SyncedTabsHistogram.HAS_FOREIGN_DATA]);
diff --git a/chrome/test/data/webui/md_history/history_synced_tabs_test.js b/chrome/test/data/webui/md_history/history_synced_tabs_test.js index c4dcdda..e7949b0 100644 --- a/chrome/test/data/webui/md_history/history_synced_tabs_test.js +++ b/chrome/test/data/webui/md_history/history_synced_tabs_test.js
@@ -420,48 +420,3 @@ registerMessageCallback('deleteForeignSession', this, undefined); }); }); - -suite('<history-synced-device-manager> integration', function() { - var element; - - setup(function() { - var app = replaceApp(); - // Not rendered until selected. - assertEquals(null, app.$$('#synced-devices')); - - app.selectedPage_ = 'syncedTabs'; - assertEquals('syncedTabs', app.$['content-side-bar'].$.menu.selected); - return PolymerTest.flushTasks().then(function() { - element = app.$$('#synced-devices'); - assertTrue(!!element); - }); - }); - - test('enable and disable tab sync', function() { - updateSignInState(true); - var sessionList = [ - createSession( - 'Nexus 5', - [createWindow(['http://www.google.com', 'http://example.com'])] - ) - ]; - // Open tabs sync is enabled. - setForeignSessions(sessionList, true); - - return PolymerTest.flushTasks().then(function() { - var cards = getCards(element); - assertEquals(1, cards.length); - assertTrue(element.$['no-synced-tabs'].hidden); - - // Open tabs sync is disabled. - setForeignSessions(sessionList, false); - - return PolymerTest.flushTasks(); - }).then(function() { - cards = getCards(element); - assertEquals(0, cards.length); - // If tab sync is disabled, show 'no synced tabs'. - assertNoSyncedTabsMessageShown(element, 'noSyncedResults'); - }); - }); -});
diff --git a/chrome/test/data/webui/settings/bluetooth_page_browsertest_chromeos.js b/chrome/test/data/webui/settings/bluetooth_page_browsertest_chromeos.js index ba47f20..9bc4ec64 100644 --- a/chrome/test/data/webui/settings/bluetooth_page_browsertest_chromeos.js +++ b/chrome/test/data/webui/settings/bluetooth_page_browsertest_chromeos.js
@@ -99,7 +99,7 @@ var bluetooth = bluetoothSection.querySelector('settings-bluetooth-page'); assertTrue(!!bluetooth); - expectFalse(bluetooth.bluetoothEnabled); + expectFalse(bluetooth.bluetoothEnabled_); var enable = bluetooth.$.enableBluetooth; assertTrue(!!enable); expectFalse(enable.checked); @@ -110,10 +110,10 @@ expectTrue(enable.checked); expectTrue(self.bluetoothApi_.adapterState.powered); // Confirm that 'bluetoothEnabled' remains set to true. - expectTrue(bluetooth.bluetoothEnabled); + expectTrue(bluetooth.bluetoothEnabled_); // Set 'bluetoothEnabled' directly and confirm that the checkbox // toggles. - bluetooth.bluetoothEnabled = false; + bluetooth.bluetoothEnabled_ = false; Polymer.dom.flush(); expectFalse(enable.checked); }); @@ -137,7 +137,7 @@ // should be hidden. self.bluetoothApi_.setDevicesForTest(fakeDevices_); Polymer.dom.flush(); - assertEquals(bluetooth.deviceList.length, 4); + assertEquals(bluetooth.deviceList_.length, 4); var devicesIronList = bluetooth.$$('#deviceList iron-list'); assertTrue(!!devicesIronList); devicesIronList.notifyResize();
diff --git a/chromecast/base/pref_names.cc b/chromecast/base/pref_names.cc index 1b679dbb..237f1336 100644 --- a/chromecast/base/pref_names.cc +++ b/chromecast/base/pref_names.cc
@@ -4,6 +4,7 @@ #include "chromecast/base/pref_names.h" +namespace chromecast { namespace prefs { // Boolean which specifies if remote debugging is enabled @@ -48,3 +49,4 @@ "user_experience_metrics.stability.system_unclean_shutdowns"; } // namespace prefs +} // namespace chromecast
diff --git a/chromecast/base/pref_names.h b/chromecast/base/pref_names.h index 2959717..7454885d 100644 --- a/chromecast/base/pref_names.h +++ b/chromecast/base/pref_names.h
@@ -5,6 +5,7 @@ #ifndef CHROMECAST_BASE_PREF_NAMES_H_ #define CHROMECAST_BASE_PREF_NAMES_H_ +namespace chromecast { namespace prefs { extern const char kEnableRemoteDebugging[]; @@ -19,5 +20,6 @@ extern const char kStabilitySystemUncleanShutdownCount[]; } // namespace prefs +} // namespace chromecast #endif // CHROMECAST_BASE_PREF_NAMES_H_
diff --git a/chromeos/audio/audio_devices_pref_handler.h b/chromeos/audio/audio_devices_pref_handler.h index deba1e6..09bb787 100644 --- a/chromeos/audio/audio_devices_pref_handler.h +++ b/chromeos/audio/audio_devices_pref_handler.h
@@ -9,8 +9,6 @@ #include "chromeos/audio/audio_pref_observer.h" #include "chromeos/chromeos_export.h" -class PrefService; - namespace chromeos { struct AudioDevice;
diff --git a/chromeos/audio/audio_pref_observer.h b/chromeos/audio/audio_pref_observer.h index b183ebfe..f701fcdd 100644 --- a/chromeos/audio/audio_pref_observer.h +++ b/chromeos/audio/audio_pref_observer.h
@@ -8,8 +8,6 @@ #include "base/memory/ref_counted.h" #include "chromeos/chromeos_export.h" -class PrefRegistrySimple; - namespace chromeos { // Interface for observing audio preference changes.
diff --git a/chromeos/audio/cras_audio_handler.h b/chromeos/audio/cras_audio_handler.h index 8383e9d1..a4f9cc3 100644 --- a/chromeos/audio/cras_audio_handler.h +++ b/chromeos/audio/cras_audio_handler.h
@@ -22,9 +22,6 @@ #include "chromeos/dbus/session_manager_client.h" #include "chromeos/dbus/volume_state.h" -class PrefRegistrySimple; -class PrefService; - namespace chromeos { class AudioDevicesPrefHandler;
diff --git a/chromeos/dbus/cros_disks_client.h b/chromeos/dbus/cros_disks_client.h index 9af1d86..f6d9ce2 100644 --- a/chromeos/dbus/cros_disks_client.h +++ b/chromeos/dbus/cros_disks_client.h
@@ -21,7 +21,6 @@ } namespace dbus { -class MessageReader; class Response; }
diff --git a/chromeos/dbus/dbus_clients_browser.h b/chromeos/dbus/dbus_clients_browser.h index 4824d85..380bdec4 100644 --- a/chromeos/dbus/dbus_clients_browser.h +++ b/chromeos/dbus/dbus_clients_browser.h
@@ -19,7 +19,6 @@ class ArcObbMounterClient; class AuthPolicyClient; class CrosDisksClient; -class CryptohomeClient; class DebugDaemonClient; class EasyUnlockClient; class ImageBurnerClient;
diff --git a/chromeos/dbus/dbus_thread_manager.h b/chromeos/dbus/dbus_thread_manager.h index ea0c69ba..e8b1287 100644 --- a/chromeos/dbus/dbus_thread_manager.h +++ b/chromeos/dbus/dbus_thread_manager.h
@@ -19,7 +19,6 @@ namespace dbus { class Bus; -class ObjectPath; } // namespace dbus namespace chromeos {
diff --git a/chromeos/dbus/fake_cras_audio_client.h b/chromeos/dbus/fake_cras_audio_client.h index 4430853..0dc3c4e 100644 --- a/chromeos/dbus/fake_cras_audio_client.h +++ b/chromeos/dbus/fake_cras_audio_client.h
@@ -13,8 +13,6 @@ namespace chromeos { -class CrasAudioHandlerTest; - // The CrasAudioClient implementation used on Linux desktop. class CHROMEOS_EXPORT FakeCrasAudioClient : public CrasAudioClient { public:
diff --git a/chromeos/dbus/fake_shill_manager_client.h b/chromeos/dbus/fake_shill_manager_client.h index 9bda9f1e..57b3a75 100644 --- a/chromeos/dbus/fake_shill_manager_client.h +++ b/chromeos/dbus/fake_shill_manager_client.h
@@ -12,10 +12,6 @@ #include "chromeos/chromeos_export.h" #include "chromeos/dbus/shill_manager_client.h" -namespace net { -class IPEndPoint; -} - namespace chromeos { // A fake implementation of ShillManagerClient. This works in close coordination
diff --git a/chromeos/dbus/mock_permission_broker_client.h b/chromeos/dbus/mock_permission_broker_client.h index 2380a21..a7e22f10 100644 --- a/chromeos/dbus/mock_permission_broker_client.h +++ b/chromeos/dbus/mock_permission_broker_client.h
@@ -10,10 +10,6 @@ #include "chromeos/dbus/permission_broker_client.h" #include "testing/gmock/include/gmock/gmock.h" -namespace dbus { -class FileDescriptor; -} // namespace dbus - namespace chromeos { class MockPermissionBrokerClient : public PermissionBrokerClient {
diff --git a/chromeos/dbus/services/liveness_service_provider.h b/chromeos/dbus/services/liveness_service_provider.h index bfde7702..75092a3 100644 --- a/chromeos/dbus/services/liveness_service_provider.h +++ b/chromeos/dbus/services/liveness_service_provider.h
@@ -17,7 +17,6 @@ namespace dbus { class MethodCall; -class Response; } namespace chromeos {
diff --git a/chromeos/dbus/shill_client_helper.h b/chromeos/dbus/shill_client_helper.h index 50766df..8ab8f54 100644 --- a/chromeos/dbus/shill_client_helper.h +++ b/chromeos/dbus/shill_client_helper.h
@@ -25,13 +25,9 @@ namespace dbus { -class Bus; -class ErrorResponse; class MessageWriter; class MethodCall; -class ObjectPath; class ObjectProxy; -class Response; class Signal; } // namespace dbus
diff --git a/chromeos/dbus/shill_device_client.h b/chromeos/dbus/shill_device_client.h index 272e9a7..fccb376c8 100644 --- a/chromeos/dbus/shill_device_client.h +++ b/chromeos/dbus/shill_device_client.h
@@ -16,7 +16,6 @@ namespace base { class Value; -class DictionaryValue; } // namespace base
diff --git a/chromeos/dbus/shill_manager_client.h b/chromeos/dbus/shill_manager_client.h index abe5135..2d012c4 100644 --- a/chromeos/dbus/shill_manager_client.h +++ b/chromeos/dbus/shill_manager_client.h
@@ -17,10 +17,6 @@ class ObjectPath; } -namespace net { -class IPEndPoint; -} - namespace chromeos { class ShillPropertyChangedObserver;
diff --git a/chromeos/dbus/shill_profile_client.h b/chromeos/dbus/shill_profile_client.h index dba383c..5f60d7e 100644 --- a/chromeos/dbus/shill_profile_client.h +++ b/chromeos/dbus/shill_profile_client.h
@@ -15,7 +15,6 @@ namespace base { -class Value; class DictionaryValue; } // namespace base
diff --git a/chromeos/login/auth/login_performer.h b/chromeos/login/auth/login_performer.h index d9f16ef..633f540 100644 --- a/chromeos/login/auth/login_performer.h +++ b/chromeos/login/auth/login_performer.h
@@ -24,10 +24,6 @@ class URLRequestContextGetter; } -namespace policy { -class WildcardLoginChecker; -} - namespace content { class BrowserContext; }
diff --git a/chromeos/network/network_configuration_observer.h b/chromeos/network/network_configuration_observer.h index f9e94694..5605a47 100644 --- a/chromeos/network/network_configuration_observer.h +++ b/chromeos/network/network_configuration_observer.h
@@ -15,8 +15,6 @@ namespace chromeos { -struct NetworkConfiguration; - // Observer class for network configuration events. class NetworkConfigurationObserver { public:
diff --git a/chromeos/network/network_profile_handler.h b/chromeos/network/network_profile_handler.h index f7c70c7..773bdac 100644 --- a/chromeos/network/network_profile_handler.h +++ b/chromeos/network/network_profile_handler.h
@@ -26,7 +26,6 @@ namespace chromeos { class NetworkProfileObserver; -class NetworkStateHandler; class CHROMEOS_EXPORT NetworkProfileHandler : public ShillPropertyChangedObserver {
diff --git a/chromeos/network/onc/onc_certificate_importer_impl.h b/chromeos/network/onc/onc_certificate_importer_impl.h index 0a81e4d..15f39e5 100644 --- a/chromeos/network/onc/onc_certificate_importer_impl.h +++ b/chromeos/network/onc/onc_certificate_importer_impl.h
@@ -21,7 +21,6 @@ class DictionaryValue; class ListValue; class SequencedTaskRunner; -class SingleThreadTaskRunner; } namespace net {
diff --git a/chromeos/network/proxy/proxy_config_handler.h b/chromeos/network/proxy/proxy_config_handler.h index 124c1ba..d387d2d 100644 --- a/chromeos/network/proxy/proxy_config_handler.h +++ b/chromeos/network/proxy/proxy_config_handler.h
@@ -10,14 +10,9 @@ #include "chromeos/chromeos_export.h" #include "components/onc/onc_constants.h" -class PrefRegistrySimple; class PrefService; class ProxyConfigDictionary; -namespace user_prefs { -class PrefRegistrySyncable; -} - namespace chromeos { class NetworkState;
diff --git a/cloud_print/BRANDING b/cloud_print/BRANDING new file mode 100644 index 0000000..0ab41da --- /dev/null +++ b/cloud_print/BRANDING
@@ -0,0 +1,3 @@ +PRODUCT_FULLNAME=Google Cloud Print +PRODUCT_SHORTNAME=GCP +PRODUCT_DESCRIPTION=Google Cloud Print (GCP) enables any app on any device to print to any cloud-connected printer.
diff --git a/cloud_print/BUILD.gn b/cloud_print/BUILD.gn new file mode 100644 index 0000000..75ed5e0 --- /dev/null +++ b/cloud_print/BUILD.gn
@@ -0,0 +1,36 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//testing/test.gni") + +group("cloud_print") { + if (is_win) { + public_deps = [ + "//cloud_print/virtual_driver/win/install:virtual_driver_setup", + "//cloud_print/virtual_driver/win/port_monitor", + ] + + # When compiling 32-bit, also reference the 64-bit driver for installing on + # 64-bit systems. + if (target_cpu == "x86" && current_cpu == "x86") { + public_deps += [ "//cloud_print/virtual_driver/win/port_monitor(//build/toolchain/win:x64)" ] + } + } +} + +test("cloud_print_unittests") { + sources = [ + "virtual_driver/win/port_monitor/port_monitor_unittest.cc", + ] + + deps = [ + "//base", + "//base/test:run_all_unittests", + "//cloud_print/virtual_driver/win/port_monitor:lib", + "//testing/gmock", + "//testing/gtest", + ] + + libs = [ "secur32.lib" ] +}
diff --git a/cloud_print/DEPS b/cloud_print/DEPS new file mode 100644 index 0000000..0f0c1a6 --- /dev/null +++ b/cloud_print/DEPS
@@ -0,0 +1,5 @@ +include_rules = [ + "+chrome/common", + "+chrome/installer/launcher_support", + "+grit", +]
diff --git a/cloud_print/OWNERS b/cloud_print/OWNERS new file mode 100644 index 0000000..8a47a27 --- /dev/null +++ b/cloud_print/OWNERS
@@ -0,0 +1,7 @@ +# vitalybuka and pastarmovj are only temporary owneres until the new Cloud Print +# team decides who will own this code and where its final repository will be. +pastarmovj@chromium.org + +# vitalybuka is not on the Chrome project use only as a last resort! +vitalybuka@chromium.org +
diff --git a/cloud_print/common/BUILD.gn b/cloud_print/common/BUILD.gn new file mode 100644 index 0000000..ca0b546d --- /dev/null +++ b/cloud_print/common/BUILD.gn
@@ -0,0 +1,26 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +source_set("common") { + sources = [ + "win/cloud_print_utils.cc", + "win/cloud_print_utils.h", + ] + + deps = [ + "//base", + ] +} + +source_set("install_utils") { + sources = [ + "win/install_utils.cc", + "win/install_utils.h", + ] + + deps = [ + ":common", + "//base", + ] +}
diff --git a/cloud_print/common/win/cloud_print_utils.cc b/cloud_print/common/win/cloud_print_utils.cc new file mode 100644 index 0000000..5a8574c1 --- /dev/null +++ b/cloud_print/common/win/cloud_print_utils.cc
@@ -0,0 +1,61 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "cloud_print/common/win/cloud_print_utils.h" + +#include <windows.h> + +#include "base/win/registry.h" + +namespace cloud_print { + +namespace { + +// Google Update related constants. +const wchar_t kClientStateKey[] = L"SOFTWARE\\Google\\Update\\ClientState\\"; +const wchar_t* kUsageKey = L"dr"; + +} // namespace + +HRESULT GetLastHResult() { + DWORD error_code = GetLastError(); + return error_code ? HRESULT_FROM_WIN32(error_code) : E_FAIL; +} + +base::string16 LoadLocalString(DWORD id) { + static wchar_t dummy = L'\0'; + HMODULE module = NULL; + ::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT | + GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, + &dummy, &module); + LPCWSTR buffer = NULL; + // If the last parameter is 0, LoadString assume that 3rd parameter type is + // LPCWSTR* and assign pointer to read-only memory with resource. + int count = ::LoadString(module, id, reinterpret_cast<LPWSTR>(&buffer), 0); + if (!buffer) + return base::string16(); + return base::string16(buffer, buffer + count); +} + +base::string16 GetErrorMessage(HRESULT hr) { + LPWSTR buffer = NULL; + ::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | + FORMAT_MESSAGE_ALLOCATE_BUFFER, + 0, hr, 0, reinterpret_cast<LPWSTR>(&buffer), 0, NULL); + base::string16 result(buffer); + ::LocalFree(buffer); + return result; +} + +void SetGoogleUpdateUsage(const base::string16& product_id) { + // Set appropriate key to 1 to let Omaha record usage. + base::win::RegKey key; + if (key.Create(HKEY_CURRENT_USER, (kClientStateKey + product_id).c_str(), + KEY_SET_VALUE) != ERROR_SUCCESS || + key.WriteValue(kUsageKey, L"1") != ERROR_SUCCESS) { + LOG(ERROR) << "Unable to set usage key"; + } +} + +} // namespace cloud_print
diff --git a/cloud_print/common/win/cloud_print_utils.h b/cloud_print/common/win/cloud_print_utils.h new file mode 100644 index 0000000..39fe017b --- /dev/null +++ b/cloud_print/common/win/cloud_print_utils.h
@@ -0,0 +1,29 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CLOUD_PRINT_COMMON_CLOUD_PRINT_UTILS_H_ +#define CLOUD_PRINT_COMMON_CLOUD_PRINT_UTILS_H_ + +#include <wtypes.h> + +#include "base/strings/string16.h" + +namespace cloud_print { + +// Similar to the Windows API call GetLastError but returns an HRESULT. +HRESULT GetLastHResult(); + +// Convert an HRESULT to a localized string. +base::string16 GetErrorMessage(HRESULT hr); + +// Retrieves a string from the string table of the module that contains the +// calling code. +base::string16 LoadLocalString(DWORD id); + +// Sets registry value to notify Google Update that product was used. +void SetGoogleUpdateUsage(const base::string16& product_id); + +} // namespace cloud_print + +#endif // CLOUD_PRINT_COMMON_CLOUD_PRINT_UTILS_H_
diff --git a/cloud_print/common/win/install_utils.cc b/cloud_print/common/win/install_utils.cc new file mode 100644 index 0000000..955b3ebc --- /dev/null +++ b/cloud_print/common/win/install_utils.cc
@@ -0,0 +1,214 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "cloud_print/common/win/install_utils.h" + +#include <windows.h> + +#include "base/command_line.h" +#include "base/file_version_info_win.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/path_service.h" +#include "base/process/launch.h" +#include "base/win/current_module.h" +#include "base/win/registry.h" +#include "cloud_print/common/win/cloud_print_utils.h" + +namespace cloud_print { + +namespace { + +// Google Update related constants. +const wchar_t kClientsKey[] = L"SOFTWARE\\Google\\Update\\Clients\\"; +const wchar_t kClientStateKey[] = L"SOFTWARE\\Google\\Update\\ClientState\\"; +const wchar_t kVersionKey[] = L"pv"; +const wchar_t kNameKey[] = L"name"; + +enum InstallerResult { + INSTALLER_RESULT_FAILED_CUSTOM_ERROR = 1, + INSTALLER_RESULT_FAILED_SYSTEM_ERROR = 3, +}; + +const wchar_t kRegValueInstallerResult[] = L"InstallerResult"; +const wchar_t kRegValueInstallerResultUIString[] = L"InstallerResultUIString"; +const wchar_t kRegValueInstallerError[] = L"InstallerError"; + +// Uninstall related constants. +const wchar_t kUninstallKey[] = + L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\"; +const wchar_t kInstallLocation[] = L"InstallLocation"; +const wchar_t kUninstallString[] = L"UninstallString"; +const wchar_t kDisplayVersion[] = L"DisplayVersion"; +const wchar_t kDisplayIcon[] = L"DisplayIcon"; +const wchar_t kDisplayName[] = L"DisplayName"; +const wchar_t kPublisher[] = L"Publisher"; +const wchar_t kNoModify[] = L"NoModify"; +const wchar_t kNoRepair[] = L"NoRepair"; + +} // namespace + +void SetGoogleUpdateKeys(const base::string16& product_id, + const base::string16& product_name) { + base::win::RegKey key; + if (key.Create(HKEY_LOCAL_MACHINE, + (cloud_print::kClientsKey + product_id).c_str(), + KEY_SET_VALUE) != ERROR_SUCCESS) { + LOG(ERROR) << "Unable to open key"; + } + + // Get the version from the resource file. + base::string16 version_string; + std::unique_ptr<FileVersionInfo> version_info( + FileVersionInfo::CreateFileVersionInfoForModule(CURRENT_MODULE())); + if (version_info.get()) { + FileVersionInfoWin* version_info_win = + static_cast<FileVersionInfoWin*>(version_info.get()); + version_string = version_info_win->product_version(); + } else { + LOG(ERROR) << "Unable to get version string"; + // Use a random version string so that Google Update has something to go by. + version_string = L"0.0.0.99"; + } + + if (key.WriteValue(kVersionKey, version_string.c_str()) != ERROR_SUCCESS || + key.WriteValue(kNameKey, product_name.c_str()) != ERROR_SUCCESS) { + LOG(ERROR) << "Unable to set registry keys"; + } +} + +void SetGoogleUpdateError(const base::string16& product_id, + const base::string16& message) { + LOG(ERROR) << message; + base::win::RegKey key; + if (key.Create(HKEY_LOCAL_MACHINE, + (cloud_print::kClientStateKey + product_id).c_str(), + KEY_SET_VALUE) != ERROR_SUCCESS) { + LOG(ERROR) << "Unable to open key"; + } + + if (key.WriteValue(kRegValueInstallerResult, + INSTALLER_RESULT_FAILED_CUSTOM_ERROR) != ERROR_SUCCESS || + key.WriteValue(kRegValueInstallerResultUIString, message.c_str()) != + ERROR_SUCCESS) { + LOG(ERROR) << "Unable to set registry keys"; + } +} + +void SetGoogleUpdateError(const base::string16& product_id, HRESULT hr) { + LOG(ERROR) << cloud_print::GetErrorMessage(hr); + base::win::RegKey key; + if (key.Create(HKEY_LOCAL_MACHINE, + (cloud_print::kClientStateKey + product_id).c_str(), + KEY_SET_VALUE) != ERROR_SUCCESS) { + LOG(ERROR) << "Unable to open key"; + } + + if (key.WriteValue(kRegValueInstallerResult, + INSTALLER_RESULT_FAILED_SYSTEM_ERROR) != ERROR_SUCCESS || + key.WriteValue(kRegValueInstallerError, hr) != ERROR_SUCCESS) { + LOG(ERROR) << "Unable to set registry keys"; + } +} + +void DeleteGoogleUpdateKeys(const base::string16& product_id) { + base::win::RegKey key; + if (key.Open(HKEY_LOCAL_MACHINE, + (cloud_print::kClientsKey + product_id).c_str(), + DELETE) != ERROR_SUCCESS) { + LOG(ERROR) << "Unable to open key to delete"; + return; + } + if (key.DeleteKey(L"") != ERROR_SUCCESS) { + LOG(ERROR) << "Unable to delete key"; + } +} + +void CreateUninstallKey(const base::string16& uninstall_id, + const base::string16& product_name, + const std::string& uninstall_switch) { + // Now write the Windows Uninstall entries + // Minimal error checking here since the install can continue + // if this fails. + base::win::RegKey key; + if (key.Create(HKEY_LOCAL_MACHINE, + (cloud_print::kUninstallKey + uninstall_id).c_str(), + KEY_SET_VALUE) != ERROR_SUCCESS) { + LOG(ERROR) << "Unable to open key"; + return; + } + + base::FilePath unstall_binary; + CHECK(PathService::Get(base::FILE_EXE, &unstall_binary)); + + base::CommandLine uninstall_command(unstall_binary); + uninstall_command.AppendSwitch(uninstall_switch); + key.WriteValue(kUninstallString, + uninstall_command.GetCommandLineString().c_str()); + key.WriteValue(kInstallLocation, unstall_binary.DirName().value().c_str()); + + // Get the version resource. + std::unique_ptr<FileVersionInfo> version_info( + FileVersionInfo::CreateFileVersionInfoForModule(CURRENT_MODULE())); + + if (version_info.get()) { + FileVersionInfoWin* version_info_win = + static_cast<FileVersionInfoWin*>(version_info.get()); + key.WriteValue(kDisplayVersion, version_info_win->file_version().c_str()); + key.WriteValue(kPublisher, version_info_win->company_name().c_str()); + } else { + LOG(ERROR) << "Unable to get version string"; + } + key.WriteValue(kDisplayName, product_name.c_str()); + key.WriteValue(kDisplayIcon, unstall_binary.value().c_str()); + key.WriteValue(kNoModify, 1); + key.WriteValue(kNoRepair, 1); +} + +void DeleteUninstallKey(const base::string16& uninstall_id) { + ::RegDeleteKey(HKEY_LOCAL_MACHINE, + (cloud_print::kUninstallKey + uninstall_id).c_str()); +} + +base::FilePath GetInstallLocation(const base::string16& uninstall_id) { + base::win::RegKey key; + if (key.Open(HKEY_LOCAL_MACHINE, + (cloud_print::kUninstallKey + uninstall_id).c_str(), + KEY_QUERY_VALUE) != ERROR_SUCCESS) { + // Not installed. + return base::FilePath(); + } + base::string16 install_path_value; + key.ReadValue(kInstallLocation, &install_path_value); + return base::FilePath(install_path_value); +} + +void DeleteProgramDir(const std::string& delete_switch) { + base::FilePath installer_source; + if (!PathService::Get(base::FILE_EXE, &installer_source)) + return; + // Deletes only subdirs of program files. + if (!IsProgramsFilesParent(installer_source)) + return; + base::FilePath temp_path; + if (!base::CreateTemporaryFile(&temp_path)) + return; + base::CopyFile(installer_source, temp_path); + base::DeleteFileAfterReboot(temp_path); + base::CommandLine command_line(temp_path); + command_line.AppendSwitchPath(delete_switch, installer_source.DirName()); + base::LaunchOptions options; + if (!base::LaunchProcess(command_line, options).IsValid()) { + LOG(ERROR) << "Unable to launch child uninstall."; + } +} + +bool IsProgramsFilesParent(const base::FilePath& path) { + base::FilePath program_files; + if (!PathService::Get(base::DIR_PROGRAM_FILESX86, &program_files)) + return false; + return program_files.IsParent(path); +} + +} // namespace cloud_print
diff --git a/cloud_print/common/win/install_utils.h b/cloud_print/common/win/install_utils.h new file mode 100644 index 0000000..92b8fd87 --- /dev/null +++ b/cloud_print/common/win/install_utils.h
@@ -0,0 +1,49 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CLOUD_PRINT_COMMON_INSTALL_UTILS_H_ +#define CLOUD_PRINT_COMMON_INSTALL_UTILS_H_ + +#include <wtypes.h> +#include <string> + +#include "base/files/file_path.h" +#include "base/strings/string16.h" + +namespace cloud_print { + +// Sets Google Update registry keys after install or update. +void SetGoogleUpdateKeys(const base::string16& product_id, + const base::string16& product_name); + +// Sets custom error message to show by Google Update installer +void SetGoogleUpdateError(const base::string16& product_id, + const base::string16& message); + +// Sets custom system error code to show by Google Update installer +void SetGoogleUpdateError(const base::string16& product_id, HRESULT hr); + +// Deletes Google Update reg keys on product uninstall. +void DeleteGoogleUpdateKeys(const base::string16& product_id); + +// Creates control panel uninstall item. +void CreateUninstallKey(const base::string16& uninstall_id, + const base::string16& product_name, + const std::string& uninstall_switch); + +// Deletes control panel uninstall item. +void DeleteUninstallKey(const base::string16& uninstall_id); + +// Returns install location retrieved from control panel uninstall key. +base::FilePath GetInstallLocation(const base::string16& uninstall_id); + +// Returns install location retrieved from control panel uninstall key. +void DeleteProgramDir(const std::string& delete_switch); + +// Returns true if path is part of program files. +bool IsProgramsFilesParent(const base::FilePath& path); + +} // namespace cloud_print + +#endif // CLOUD_PRINT_COMMON_INSTALL_UTILS_H_
diff --git a/cloud_print/virtual_driver/win/BUILD.gn b/cloud_print/virtual_driver/win/BUILD.gn new file mode 100644 index 0000000..110b5a36 --- /dev/null +++ b/cloud_print/virtual_driver/win/BUILD.gn
@@ -0,0 +1,19 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +assert(is_win) + +source_set("win") { + sources = [ + "virtual_driver_consts.cc", + "virtual_driver_consts.h", + "virtual_driver_helpers.cc", + "virtual_driver_helpers.h", + ] + + deps = [ + "//base", + "//cloud_print/common", + ] +}
diff --git a/cloud_print/virtual_driver/win/gcp_portmon_dll.ver b/cloud_print/virtual_driver/win/gcp_portmon_dll.ver new file mode 100644 index 0000000..dd75a0f1 --- /dev/null +++ b/cloud_print/virtual_driver/win/gcp_portmon_dll.ver
@@ -0,0 +1,3 @@ +INTERNAL_NAME=gcp_portmon.dll +ORIGINAL_FILENAME=gcp_portmon.dll +FILETYPE=0x2L
diff --git a/cloud_print/virtual_driver/win/install/BUILD.gn b/cloud_print/virtual_driver/win/install/BUILD.gn new file mode 100644 index 0000000..3018a21 --- /dev/null +++ b/cloud_print/virtual_driver/win/install/BUILD.gn
@@ -0,0 +1,120 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//chrome/process_version_rc_template.gni") +import("//tools/grit/grit_rule.gni") + +assert(is_win) + +executable("virtual_driver_setup") { + sources = [ + "setup.cc", + ] + + configs -= [ "//build/config/win:console" ] + configs += [ "//build/config/win:windowed" ] + + deps = [ + ":copy_gcp_driver_gpd", + ":copy_gcp_driver_inf", + ":resources", + ":setup_version", + "//base", + "//cloud_print/common", + "//cloud_print/common:install_utils", + "//cloud_print/virtual_driver/win", + ] + + libs = [ "setupapi.lib" ] + ldflags = [ "/DELAYLOAD:winspool.drv" ] +} + +copy("copy_gcp_driver_gpd") { + sources = [ + "inf/gcp_driver.gpd", + ] + outputs = [ + "$root_build_dir/gcp_driver.gpd", + ] +} + +copy("copy_gcp_driver_inf") { + sources = [ + "inf/gcp_driver.inf", + ] + outputs = [ + "$root_build_dir/gcp_driver.inf", + ] +} + +process_version_rc_template("setup_version") { + sources = [ + "virtual_driver_setup_exe.ver", + ] + output = "$target_gen_dir/virtual_driver_setup.rc" +} + +grit("resources") { + visibility = [ ":*" ] + + source = "virtual_driver_setup_resources.grd" + + output_dir = "$root_gen_dir/virtual_driver_setup_resources" + + outputs = [ + "grit/virtual_driver_setup_resources.h", + "virtual_driver_setup_resources_ar.rc", + "virtual_driver_setup_resources_bg.rc", + "virtual_driver_setup_resources_bn.rc", + "virtual_driver_setup_resources_ca.rc", + "virtual_driver_setup_resources_cs.rc", + "virtual_driver_setup_resources_da.rc", + "virtual_driver_setup_resources_de.rc", + "virtual_driver_setup_resources_el.rc", + "virtual_driver_setup_resources_en.rc", + "virtual_driver_setup_resources_en-GB.rc", + "virtual_driver_setup_resources_es.rc", + "virtual_driver_setup_resources_es-419.rc", + "virtual_driver_setup_resources_et.rc", + "virtual_driver_setup_resources_fa.rc", + "virtual_driver_setup_resources_fi.rc", + "virtual_driver_setup_resources_fil.rc", + "virtual_driver_setup_resources_fr.rc", + "virtual_driver_setup_resources_gu.rc", + "virtual_driver_setup_resources_he.rc", + "virtual_driver_setup_resources_hi.rc", + "virtual_driver_setup_resources_hr.rc", + "virtual_driver_setup_resources_hu.rc", + "virtual_driver_setup_resources_id.rc", + "virtual_driver_setup_resources_it.rc", + "virtual_driver_setup_resources_ja.rc", + "virtual_driver_setup_resources_kn.rc", + "virtual_driver_setup_resources_ko.rc", + "virtual_driver_setup_resources_lt.rc", + "virtual_driver_setup_resources_lv.rc", + "virtual_driver_setup_resources_ml.rc", + "virtual_driver_setup_resources_mr.rc", + "virtual_driver_setup_resources_ms.rc", + "virtual_driver_setup_resources_nl.rc", + "virtual_driver_setup_resources_nb.rc", + "virtual_driver_setup_resources_pl.rc", + "virtual_driver_setup_resources_pt-BR.rc", + "virtual_driver_setup_resources_pt-PT.rc", + "virtual_driver_setup_resources_ro.rc", + "virtual_driver_setup_resources_ru.rc", + "virtual_driver_setup_resources_sk.rc", + "virtual_driver_setup_resources_sl.rc", + "virtual_driver_setup_resources_sr.rc", + "virtual_driver_setup_resources_sv.rc", + "virtual_driver_setup_resources_sw.rc", + "virtual_driver_setup_resources_ta.rc", + "virtual_driver_setup_resources_te.rc", + "virtual_driver_setup_resources_th.rc", + "virtual_driver_setup_resources_tr.rc", + "virtual_driver_setup_resources_uk.rc", + "virtual_driver_setup_resources_vi.rc", + "virtual_driver_setup_resources_zh-CN.rc", + "virtual_driver_setup_resources_zh-TW.rc", + ] +}
diff --git a/cloud_print/virtual_driver/win/install/inf/gcp_driver.gpd b/cloud_print/virtual_driver/win/install/inf/gcp_driver.gpd new file mode 100644 index 0000000..3e853d6 --- /dev/null +++ b/cloud_print/virtual_driver/win/install/inf/gcp_driver.gpd
@@ -0,0 +1,1034 @@ +*% Copyright (c) 2012 The Chromium Authors. All rights reserved. +*% Use of this source code is governed by a BSD-style license that can be +*% found in the LICENSE file. + +*GPDFileVersion: "1.0" +*GPDSpecVersion: "1.0" +*Include: "StdNames.gpd" +*ResourceDLL: "unires.dll" +*ModelName: "Google Cloud Printer" +*MasterUnits: PAIR(1200, 1200) +*MaxCopies: 1 +*PrintRatePPM: 200 +*PrinterType: PAGE +*IsXPSDriver?: TRUE + +*Feature: ColorMode { + *rcNameID: =COLOR_PRINTING_MODE_DISPLAY + *DefaultOption: 24bpp + *ConcealFromUI?: TRUE + *Option: 24bpp { + *rcNameID: =24BPP_DISPLAY + *DevNumOfPlanes: 1 + *DevBPP: 24 + *DrvBPP: 24 + } +} + +*Feature: Memory { + *rcNameID: =PRINTER_MEMORY_DISPLAY + *DefaultOption: 65536KB + *Option: 16384KB { + *Name: "16MB" + *MemoryConfigKB: PAIR(16384, 16384) + } + *Option: 65536KB { + *Name: "64MB" + *MemoryConfigKB: PAIR(65536, 65536) + } +} + +*Feature: Orientation { + *rcNameID: =ORIENTATION_DISPLAY + *DefaultOption: PORTRAIT + *Option: PORTRAIT { + *rcNameID: =PORTRAIT_DISPLAY + } + *Option: LANDSCAPE_CC270 { + *rcNameID: =LANDSCAPE_DISPLAY + } +} + +*Feature: PaperSize { + *rcNameID: =PAPER_SIZE_DISPLAY + *DefaultOption: LETTER + + *Option: A2 { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(19842, 28062) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(28062, 19842) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: A3 { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(14031, 19842) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(19842, 14031) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: A4 { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(9921, 14031) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(14031, 9921) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: A5 { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(6992, 9921) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(9921, 6992) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: A6 { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(4960, 6992) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(6992, 4960) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: A4_PLUS { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(9921, 15590) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(15590, 9921) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: A3_EXTRA { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(15212, 21023) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(21023, 15212) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: A4_EXTRA { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(11102, 15212) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(15212, 11102) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: A5_EXTRA { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(8220, 11102) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(11102, 8220) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: B4 { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(12141, 17196) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(17196, 12141) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: B5 { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(8598, 12141) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(12141, 8598) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: ENV_B4 { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(11811, 16677) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(16677, 11811) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: ENV_B5 { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(8314, 11811) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(11811, 8314) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: ENV_B6 { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(5905, 8314) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(8314, 5905) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: B6_JIS { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(6047, 8598) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(8598, 6047) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: B5_EXTRA { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(9496, 13039) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(13039, 9496) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: ENV_C3 { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(15307, 21637) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(21637, 15307) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: ENV_C4 { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(10818, 15307) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(15307, 10818) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: ENV_C5 { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(7653, 10818) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(10818, 7653) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: ENV_C6 { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(5385, 7653) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(7653, 5385) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: ENV_C65 { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(5385, 10818) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(10818, 5385) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: ENV_DL { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(5196, 10393) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(10393, 5196) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: JENV_CHOU3 { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(5669, 11102) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(11102, 5669) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: JENV_CHOU4 { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(4251, 9685) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(9685, 4251) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: JAPANESE_POSTCARD { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(4724, 6992) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(6992, 4724) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: JENV_KAKU2 { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(11338, 15685) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(15685, 11338) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: DBL_JAPANESE_POSTCARD { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(6992, 9448) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(9448, 6992) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: JENV_YOU4 { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(4960, 11102) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(11102, 4960) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: 10X11 { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(12000, 13200) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(13200, 12000) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: 10X14 { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(12000, 16800) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(16800, 12000) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: 9X11 { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(10800, 13200) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(13200, 10800) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: CSHEET { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(20400, 26400) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(26400, 20400) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: DSHEET { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(26400, 40800) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(40800, 26400) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: ESHEET { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(40800, 52800) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(52800, 40800) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: EXECUTIVE { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(8700, 12600) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(12600, 8700) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: FANFOLD_STD_GERMAN { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(10200, 14400) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(14400, 10200) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: FANFOLD_US { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(13200, 17850) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(17850, 13200) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: FOLIO { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(10200, 15600) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(15600, 10200) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: STATEMENT { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(6600, 10200) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(10200, 6600) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: TABLOID { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(13200, 20400) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(20400, 13200) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: LEGAL { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(10200, 16800) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(16800, 10200) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: LEGAL_EXTRA { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(11400, 18000) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(18000, 11400) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: LETTER { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(10200, 13200) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(13200, 10200) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: LETTER_EXTRA { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(11400, 14400) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(14400, 11400) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: LETTER_PLUS { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(10200, 15228) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(15228, 10200) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: ENV_MONARCH { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(4650, 9000) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(9000, 4650) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: ENV_9 { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(4650, 10650) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(10650, 4650) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: ENV_10 { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(4950, 11400) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(11400, 4950) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: ENV_11 { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(5400, 12450) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(12450, 5400) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: ENV_12 { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(5700, 13200) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(13200, 5700) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: ENV_14 { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(6000, 13800) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(13800, 6000) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: ENV_INVITE { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(10393, 10393) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(10393, 10393) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: PENV_1 { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(4818, 7795) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(7795, 4818) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: PENV_3 { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(5905, 8314) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(8314, 5905) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: PENV_4 { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(5196, 9826) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(9826, 5196) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: PENV_5 { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(5196, 10393) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(10393, 5196) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: PENV_6 { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(5669, 10866) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(10866, 5669) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: PENV_7 { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(7559, 10866) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(10866, 7559) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: PENV_8 { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(5669, 14598) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(14598, 5669) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } + + *Option: PENV_10 { + *rcNameID: =RCID_DMPAPER_SYSTEM_NAME + *switch: Orientation { + *case: PORTRAIT { + *PrintableArea: PAIR(15307, 21637) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + *case: LANDSCAPE_CC270 { + *PrintableArea: PAIR(21637, 15307) + *PrintableOrigin: PAIR(0, 0) + *CursorOrigin: PAIR(0, 0) + } + } + } +} + +*Feature: Resolution { + *rcNameID: =RESOLUTION_DISPLAY + *DefaultOption: 600dpi + + *Option: 600dpi { + *Name: "600 x 600 " =DOTS_PER_INCH + *DPI: PAIR(600, 600) + *TextDPI: PAIR(600, 600) + *SpotDiameter: 100 + *Command: CmdBeginRaster { *Cmd: "<1B>*v7S<1B>*r1A" } + *Command: CmdEndRaster { *Cmd: "<1B>*rC" } + *Command: CmdSendBlockData { *Cmd: "<1B>*b" %d {NumOfDataBytes}"W" } + } +} + +*Command: CmdCR { *Cmd: "<0D>" } +*Command: CmdLF { *Cmd: "<0A>" } +*Command: CmdFF { *Cmd: "<0C>" }
diff --git a/cloud_print/virtual_driver/win/install/inf/gcp_driver.inf b/cloud_print/virtual_driver/win/install/inf/gcp_driver.inf new file mode 100644 index 0000000..8d780245 --- /dev/null +++ b/cloud_print/virtual_driver/win/install/inf/gcp_driver.inf Binary files differ
diff --git a/cloud_print/virtual_driver/win/install/resources/cloudprint.ico b/cloud_print/virtual_driver/win/install/resources/cloudprint.ico new file mode 100644 index 0000000..e362c72 --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/cloudprint.ico Binary files differ
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_ar.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_ar.xtb new file mode 100644 index 0000000..280740c --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_ar.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="ar"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631"><ph name="XPS_URL"/>برنامج تشغيل XPS<ph name="XPS_URL_END"/> غير مثبّت.</translation> +<translation id="4983496916481712098">طابعة متوافقة مع خدمة طباعة في السحاب من Google</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_bg.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_bg.xtb new file mode 100644 index 0000000..c5eeb0b --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_bg.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="bg"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631"><ph name="XPS_URL"/>Драйверът XPS<ph name="XPS_URL_END"/> не е инсталиран.</translation> +<translation id="4983496916481712098">Google Cloud Printer</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_bn.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_bn.xtb new file mode 100644 index 0000000..92c00281 --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_bn.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="bn"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631"><ph name="XPS_URL"/>XPS ড্রাইভার<ph name="XPS_URL_END"/> ইনস্টল করা নেই৷</translation> +<translation id="4983496916481712098">Google মেঘ মুদ্রণ</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_ca.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_ca.xtb new file mode 100644 index 0000000..06c9597 --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_ca.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="ca"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631">El <ph name="XPS_URL"/>controlador XPS<ph name="XPS_URL_END"/> no està instal·lat.</translation> +<translation id="4983496916481712098">Impressora de Google Cloud</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_cs.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_cs.xtb new file mode 100644 index 0000000..49281b001 --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_cs.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="cs"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631">Není nainstalován <ph name="XPS_URL"/>ovladač XPS<ph name="XPS_URL_END"/>.</translation> +<translation id="4983496916481712098">Tiskárna v cloudu Google</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_da.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_da.xtb new file mode 100644 index 0000000..fa7f7d21 --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_da.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="da"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631"><ph name="XPS_URL"/>XPS-driver<ph name="XPS_URL_END"/> er ikke installeret.</translation> +<translation id="4983496916481712098">Google Cloudprinter</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_de.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_de.xtb new file mode 100644 index 0000000..0e298c4 --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_de.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="de"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631"><ph name="XPS_URL"/>XPS-Treiber<ph name="XPS_URL_END"/> ist nicht installiert.</translation> +<translation id="4983496916481712098">Google Cloud Printer</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_el.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_el.xtb new file mode 100644 index 0000000..a54377b --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_el.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="el"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631"><ph name="XPS_URL"/>Το πρόγραμμα οδήγησης XPS<ph name="XPS_URL_END"/> δεν είναι εγκατεστημένο.</translation> +<translation id="4983496916481712098">Εκτυπωτής Google Cloud</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_en-GB.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_en-GB.xtb new file mode 100644 index 0000000..83f468e --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_en-GB.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="en-GB"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631"><ph name="XPS_URL"/>XPS driver<ph name="XPS_URL_END"/> is not installed.</translation> +<translation id="4983496916481712098">Google Cloud Printer</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_es-419.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_es-419.xtb new file mode 100644 index 0000000..96ac8039 --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_es-419.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="es-419"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631">El <ph name="XPS_URL"/>controlador XPS<ph name="XPS_URL_END"/> no está instalado.</translation> +<translation id="4983496916481712098">Impresora de Google Cloud</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_es.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_es.xtb new file mode 100644 index 0000000..75d1a247 --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_es.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="es"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631">El <ph name="XPS_URL"/>controlador XPS<ph name="XPS_URL_END"/> no está instalado.</translation> +<translation id="4983496916481712098">Impresora en la nube de Google</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_et.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_et.xtb new file mode 100644 index 0000000..d023313 --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_et.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="et"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631"><ph name="XPS_URL"/>XPS-draiver<ph name="XPS_URL_END"/> on installimata.</translation> +<translation id="4983496916481712098">Google'i pilvprinter</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_fa.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_fa.xtb new file mode 100644 index 0000000..28944fd --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_fa.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="fa"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631"><ph name="XPS_URL"/>راهانداز XPS<ph name="XPS_URL_END"/> نصب نشده است.</translation> +<translation id="4983496916481712098">Google Cloud Printer</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_fi.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_fi.xtb new file mode 100644 index 0000000..5ecb49d --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_fi.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="fi"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631"><ph name="XPS_URL"/>XPS-ajuria<ph name="XPS_URL_END"/> ei ole asennettu.</translation> +<translation id="4983496916481712098">Google Cloud -tulostin</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_fil.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_fil.xtb new file mode 100644 index 0000000..4423db92 --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_fil.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="fil"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631">Hindi naka-install ang <ph name="XPS_URL"/>XPS driver<ph name="XPS_URL_END"/>.</translation> +<translation id="4983496916481712098">Google Cloud Printer</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_fr.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_fr.xtb new file mode 100644 index 0000000..8479057 --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_fr.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="fr"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631">Le <ph name="XPS_URL"/>pilote XPS<ph name="XPS_URL_END"/> n'est pas installé.</translation> +<translation id="4983496916481712098">Google Cloud Printer</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_gu.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_gu.xtb new file mode 100644 index 0000000..372d6ca --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_gu.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="gu"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631"><ph name="XPS_URL"/>XPS ડ્રાઇવર<ph name="XPS_URL_END"/> ઇન્સ્ટોલ કરેલું નથી.</translation> +<translation id="4983496916481712098">Google મેઘ મુદ્રણ</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_he.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_he.xtb new file mode 100644 index 0000000..d284b854 --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_he.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="he"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631"><ph name="XPS_URL"/> מנהל ההתקן של XPS<ph name="XPS_URL_END"/> לא מותקן.</translation> +<translation id="4983496916481712098">מדפסת Google Cloud Print</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_hi.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_hi.xtb new file mode 100644 index 0000000..0ca331d --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_hi.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="hi"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631"><ph name="XPS_URL"/>XPS ड्राइवर<ph name="XPS_URL_END"/> इंस्टॉल नहीं है.</translation> +<translation id="4983496916481712098">Google क्लाउड प्रिंटर</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_hr.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_hr.xtb new file mode 100644 index 0000000..3a23556 --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_hr.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="hr"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631"><ph name="XPS_URL"/>Upravljački program za XPS<ph name="XPS_URL_END"/> nije instaliran.</translation> +<translation id="4983496916481712098">Google pisač u oblaku</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_hu.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_hu.xtb new file mode 100644 index 0000000..6a8f56e --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_hu.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="hu"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631">Nincs telepítve <ph name="XPS_URL"/>XPS illesztőprogram<ph name="XPS_URL_END"/>.</translation> +<translation id="4983496916481712098">Google Cloud Printer</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_id.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_id.xtb new file mode 100644 index 0000000..a29c270 --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_id.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="id"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631"><ph name="XPS_URL"/>Driver XPS<ph name="XPS_URL_END"/> tidak terpasang.</translation> +<translation id="4983496916481712098">Google Cloud Printer</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_it.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_it.xtb new file mode 100644 index 0000000..ee07dc3 --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_it.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="it"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631"><ph name="XPS_URL"/>Il driver XPS<ph name="XPS_URL_END"/> non è installato.</translation> +<translation id="4983496916481712098">Google Cloud Print</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_ja.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_ja.xtb new file mode 100644 index 0000000..1cf9c1b --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_ja.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="ja"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631"><ph name="XPS_URL"/>XPS ドライバ<ph name="XPS_URL_END"/>がインストールされていません。</translation> +<translation id="4983496916481712098">Google クラウド プリンタ</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_kn.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_kn.xtb new file mode 100644 index 0000000..e64a2fea --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_kn.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="kn"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631"><ph name="XPS_URL"/>XPS ಡ್ರೈವರ್<ph name="XPS_URL_END"/> ಅನ್ನು ಸ್ಥಾಪಿಸಲಾಗಿಲ್ಲ.</translation> +<translation id="4983496916481712098">Google ಮೇಘ ಮುದ್ರಕ</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_ko.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_ko.xtb new file mode 100644 index 0000000..a73deef --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_ko.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="ko"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631"><ph name="XPS_URL"/>XPS 드라이버<ph name="XPS_URL_END"/>가 설치되지 않았습니다.</translation> +<translation id="4983496916481712098">Google 클라우드 프린터</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_lt.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_lt.xtb new file mode 100644 index 0000000..712778f6 --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_lt.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="lt"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631"><ph name="XPS_URL"/>XPS tvarkyklė<ph name="XPS_URL_END"/> neįdiegta.</translation> +<translation id="4983496916481712098">„Google“ spausdinimo iš debesies programa</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_lv.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_lv.xtb new file mode 100644 index 0000000..c4499a4 --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_lv.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="lv"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631"><ph name="XPS_URL"/>XPS dzinis<ph name="XPS_URL_END"/> nav instalēts.</translation> +<translation id="4983496916481712098">Google mākoņprinteris</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_ml.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_ml.xtb new file mode 100644 index 0000000..7fad033 --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_ml.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="ml"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631"><ph name="XPS_URL"/>XPS ഡ്രൈവർ<ph name="XPS_URL_END"/> ഇൻസ്റ്റാളുചെയ്തിട്ടില്ല.</translation> +<translation id="4983496916481712098">Google ക്ലൗഡ് പ്രിന്റർ</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_mr.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_mr.xtb new file mode 100644 index 0000000..9cc832bd --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_mr.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="mr"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631"><ph name="XPS_URL"/>XPS ड्राइव्हर<ph name="XPS_URL_END"/> स्थापित केलेला नाही.</translation> +<translation id="4983496916481712098">Google मेघ प्रिंटर</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_ms.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_ms.xtb new file mode 100644 index 0000000..63c3567 --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_ms.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="ms"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631"><ph name="XPS_URL"/>Pemacu XPS<ph name="XPS_URL_END"/> tidak dipasang.</translation> +<translation id="4983496916481712098">Pencetak Awan Google</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_nl.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_nl.xtb new file mode 100644 index 0000000..76f87ad --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_nl.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="nl"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631"><ph name="XPS_URL"/>XPS-stuurprogramma<ph name="XPS_URL_END"/> is niet geïnstalleerd.</translation> +<translation id="4983496916481712098">Google Cloudprinter</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_no.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_no.xtb new file mode 100644 index 0000000..ddadb1c --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_no.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="no"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631"><ph name="XPS_URL"/>XPS-driveren<ph name="XPS_URL_END"/> er ikke installert.</translation> +<translation id="4983496916481712098">Google Cloud Printer</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_pl.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_pl.xtb new file mode 100644 index 0000000..07ee486 --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_pl.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="pl"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631"><ph name="XPS_URL"/>Sterownik XPS<ph name="XPS_URL_END"/> nie jest zainstalowany.</translation> +<translation id="4983496916481712098">Drukarka Google Cloud</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_pt-BR.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_pt-BR.xtb new file mode 100644 index 0000000..9d7aff02 --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_pt-BR.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="pt-BR"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631">O <ph name="XPS_URL"/>driver XPS<ph name="XPS_URL_END"/> não está instalado.</translation> +<translation id="4983496916481712098">Google Cloud Printer</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_pt-PT.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_pt-PT.xtb new file mode 100644 index 0000000..128896c --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_pt-PT.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="pt-PT"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631">O <ph name="XPS_URL"/>controlador XPS<ph name="XPS_URL_END"/> não está instalado.</translation> +<translation id="4983496916481712098">Impressora do Google Cloud Print</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_ro.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_ro.xtb new file mode 100644 index 0000000..7afd35a --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_ro.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="ro"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631"><ph name="XPS_URL"/>Driverul XPS<ph name="XPS_URL_END"/> nu este instalat.</translation> +<translation id="4983496916481712098">Imprimanta Google Cloud Print</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_ru.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_ru.xtb new file mode 100644 index 0000000..6828c60 --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_ru.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="ru"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631"><ph name="XPS_URL"/>Драйвер XPS<ph name="XPS_URL_END"/> не установлен.</translation> +<translation id="4983496916481712098">Виртуальный принтер Google</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_sk.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_sk.xtb new file mode 100644 index 0000000..f50b627 --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_sk.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="sk"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631"><ph name="XPS_URL"/>Ovládač XPS<ph name="XPS_URL_END"/> nie je nainštalovaný.</translation> +<translation id="4983496916481712098">Google Cloud Printer</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_sl.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_sl.xtb new file mode 100644 index 0000000..1eba0bd --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_sl.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="sl"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631">Gonilnik <ph name="XPS_URL"/>XPS<ph name="XPS_URL_END"/> ni nameščen.</translation> +<translation id="4983496916481712098">Tiskalnik za Google Tiskanje v oblaku</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_sr.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_sr.xtb new file mode 100644 index 0000000..5861cb7 --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_sr.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="sr"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631"><ph name="XPS_URL"/>Управљачки програм за XPS<ph name="XPS_URL_END"/> није инсталиран.</translation> +<translation id="4983496916481712098">Google Cloud штампач</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_sv.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_sv.xtb new file mode 100644 index 0000000..07a9e93 --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_sv.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="sv"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631">Ingen <ph name="XPS_URL"/>XPS-drivrutin<ph name="XPS_URL_END"/> är installerad.</translation> +<translation id="4983496916481712098">Google Cloud Printer</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_sw.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_sw.xtb new file mode 100644 index 0000000..7106d22 --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_sw.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="sw"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631"><ph name="XPS_URL"/>XPS driver<ph name="XPS_URL_END"/> is not installed.</translation> +<translation id="4983496916481712098">Google Cloud Printer</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_ta.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_ta.xtb new file mode 100644 index 0000000..612c1908 --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_ta.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="ta"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631"><ph name="XPS_URL"/>XPS இயக்கி<ph name="XPS_URL_END"/> நிறுவப்படவில்லை.</translation> +<translation id="4983496916481712098">Google மேகக்கணி அச்சுப்பொறி</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_te.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_te.xtb new file mode 100644 index 0000000..0323475 --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_te.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="te"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631"><ph name="XPS_URL"/>XPS డ్రైవర్<ph name="XPS_URL_END"/> ఇన్స్టాల్ చేయబడలేదు.</translation> +<translation id="4983496916481712098">Google మేఘ ప్రింటర్</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_th.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_th.xtb new file mode 100644 index 0000000..67bf8ce --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_th.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="th"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631">ไม่ได้ติดตั้ง<ph name="XPS_URL"/>ไดรเวอร์ XPS<ph name="XPS_URL_END"/></translation> +<translation id="4983496916481712098">Google เครื่องพิมพ์ระบบคลาวด์</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_tr.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_tr.xtb new file mode 100644 index 0000000..7748a61 --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_tr.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="tr"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631"><ph name="XPS_URL"/>XPS sürücüsü<ph name="XPS_URL_END"/> yüklü değil.</translation> +<translation id="4983496916481712098">Google Cloud Printer</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_uk.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_uk.xtb new file mode 100644 index 0000000..fff693c5 --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_uk.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="uk"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631"><ph name="XPS_URL"/>Драйвер XPS<ph name="XPS_URL_END"/> не встановлено.</translation> +<translation id="4983496916481712098">Веб-доступний принтер Google</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_vi.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_vi.xtb new file mode 100644 index 0000000..93186dc --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_vi.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="vi"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631"><ph name="XPS_URL"/>Trình điều khiển XPS<ph name="XPS_URL_END"/> chưa được cài đặt.</translation> +<translation id="4983496916481712098">Google Cloud Printer</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_zh-CN.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_zh-CN.xtb new file mode 100644 index 0000000..d9eface2 --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_zh-CN.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="zh-CN"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631">未安装 <ph name="XPS_URL"/>XPS 驱动程序<ph name="XPS_URL_END"/>。</translation> +<translation id="4983496916481712098">Google 云端打印机</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_zh-HK.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_zh-HK.xtb new file mode 100644 index 0000000..68d7922 --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_zh-HK.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="zh-HK"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631">未安裝 <ph name="XPS_URL"/>XPS 驅動程式<ph name="XPS_URL_END"/>。</translation> +<translation id="4983496916481712098">Google 雲端印表機</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_zh-TW.xtb b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_zh-TW.xtb new file mode 100644 index 0000000..87f03685 --- /dev/null +++ b/cloud_print/virtual_driver/win/install/resources/virtual_driver_setup_resources_zh-TW.xtb
@@ -0,0 +1,5 @@ +<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="zh-TW"> +<translation id="2424268526671779403">Google</translation> +<translation id="4659506378548526631">未安裝 <ph name="XPS_URL"/>XPS 驅動程式<ph name="XPS_URL_END"/>。</translation> +<translation id="4983496916481712098">Google 雲端印表機</translation> +</translationbundle> \ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/install/setup.cc b/cloud_print/virtual_driver/win/install/setup.cc new file mode 100644 index 0000000..3c4bcad2 --- /dev/null +++ b/cloud_print/virtual_driver/win/install/setup.cc
@@ -0,0 +1,409 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <windows.h> +#include <setupapi.h> // Must be included after windows.h +#include <winspool.h> +#include <stddef.h> + +#include <iomanip> + +#include "base/at_exit.h" +#include "base/command_line.h" +#include "base/files/file_util.h" +#include "base/logging.h" +#include "base/path_service.h" +#include "base/process/launch.h" +#include "base/process/process.h" +#include "base/strings/string16.h" +#include "base/strings/string_util.h" +#include "base/win/windows_version.h" +#include "cloud_print/common/win/cloud_print_utils.h" +#include "cloud_print/common/win/install_utils.h" +#include "cloud_print/virtual_driver/win/virtual_driver_consts.h" +#include "cloud_print/virtual_driver/win/virtual_driver_helpers.h" +#include "grit/virtual_driver_setup_resources.h" + +#include <strsafe.h> // Must be after base headers to avoid deprecation + // warnings. + +namespace cloud_print { + +namespace { + +const wchar_t kNameValue[] = L"GCP Virtual Driver"; +const wchar_t kUninstallId[] = L"{74AA24E0-AC50-4B28-BA46-9CF05467C9B7}"; +const wchar_t kGcpUrl[] = L"https://www.google.com/cloudprint"; + +const wchar_t kInfFileName[] = L"gcp_driver.inf"; + +const char kDelete[] = "delete"; +const char kInstallSwitch[] = "install"; +const char kRegisterSwitch[] = "register"; +const char kUninstallSwitch[] = "uninstall"; +const char kUnregisterSwitch[] = "unregister"; + +base::FilePath GetSystemPath(const base::string16& binary) { + base::FilePath path; + if (!PathService::Get(base::DIR_SYSTEM, &path)) { + LOG(ERROR) << "Unable to get system path."; + return path; + } + return path.Append(binary); +} + +void SpoolerServiceCommand(const char* command) { + base::FilePath net_path = GetSystemPath(L"net"); + if (net_path.empty()) + return; + base::CommandLine command_line(net_path); + command_line.AppendArg(command); + command_line.AppendArg("spooler"); + command_line.AppendArg("/y"); + + base::LaunchOptions options; + options.wait = true; + options.start_hidden = true; + VLOG(0) << command_line.GetCommandLineString(); + base::LaunchProcess(command_line, options); +} + +HRESULT RegisterPortMonitor(bool install, const base::FilePath& install_path) { + DCHECK(install || install_path.empty()); + base::FilePath target_path = GetSystemPath(L"gcp_portmon.dll"); + if (target_path.empty()) { + LOG(ERROR) << "Unable to get port monitor target path."; + return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND); + } + if (install) { + base::FilePath source_path = install_path.Append(L"gcp_portmon.dll"); + if (!base::CopyFile(source_path, target_path)) { + LOG(ERROR) << "Unable copy port monitor dll from " << source_path.value() + << " to " << target_path.value(); + return GetLastHResult(); + } + } else if (!base::PathExists(target_path)) { + // Already removed. Just "succeed" silently. + return S_OK; + } + + base::FilePath regsvr32_path = GetSystemPath(L"regsvr32.exe"); + if (regsvr32_path.empty()) { + LOG(ERROR) << "Can't find regsvr32.exe."; + return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND); + } + + base::CommandLine command_line(regsvr32_path); + command_line.AppendArg("/s"); + if (!install) { + command_line.AppendArg("/u"); + } + + // Use system32 path here because otherwise ::AddMonitor would fail. + command_line.AppendArgPath(GetSystemPath(L"gcp_portmon.dll")); + + base::LaunchOptions options; + options.wait = true; + + base::Process regsvr32_process = + base::LaunchProcess(command_line.GetCommandLineString(), options); + if (!regsvr32_process.IsValid()) { + LOG(ERROR) << "Unable to launch regsvr32.exe."; + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + } + + DWORD exit_code = S_OK; + if (install) { + if (!GetExitCodeProcess(regsvr32_process.Handle(), &exit_code)) { + LOG(ERROR) << "Unable to get regsvr32.exe exit code."; + return GetLastHResult(); + } + if (exit_code != 0) { + LOG(ERROR) << "Regsvr32.exe failed with " << exit_code; + return HRESULT_FROM_WIN32(exit_code); + } + } else { + if (!base::DeleteFile(target_path, false)) { + SpoolerServiceCommand("stop"); + bool deleted = base::DeleteFile(target_path, false); + SpoolerServiceCommand("start"); + + if (!deleted) { + LOG(ERROR) << "Unable to delete " << target_path.value(); + return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED); + } + } + } + return S_OK; +} + +HRESULT InstallDriver(const base::FilePath& install_path) { + DWORD size = MAX_PATH * 10; + wchar_t package_path[MAX_PATH * 10] = {0}; + + base::FilePath inf_file = install_path.Append(kInfFileName); + base::string16 driver_name = LoadLocalString(IDS_DRIVER_NAME); + + HRESULT result = UploadPrinterDriverPackage( + NULL, inf_file.value().c_str(), NULL, + UPDP_SILENT_UPLOAD | UPDP_UPLOAD_ALWAYS, NULL, package_path, &size); + if (FAILED(result)) { + LOG(ERROR) + << "Uploading the printer driver package to the driver cache failed."; + return result; + } + + result = InstallPrinterDriverFromPackage( + NULL, package_path, driver_name.c_str(), NULL, IPDFP_COPY_ALL_FILES); + if (FAILED(result)) { + LOG(ERROR) << "Installing the printer driver failed."; + } + return result; +} + +HRESULT UninstallDriver(const base::FilePath& install_path) { + base::FilePath inf_file = install_path.Append(kInfFileName); + int tries = 3; + + while (!DeletePrinterDriverPackage(NULL, inf_file.value().c_str(), NULL)) { + if (GetLastError() == ERROR_UNKNOWN_PRINTER_DRIVER) { + LOG(WARNING) << "Print driver is already uninstalled."; + return S_OK; + } + // After deleting the printer it can take a few seconds before + // the driver is free for deletion. Retry a few times before giving up. + LOG(WARNING) << "Attempt to delete printer driver failed. Retrying."; + tries--; + Sleep(2000); + } + if (tries <= 0) { + HRESULT result = GetLastHResult(); + LOG(ERROR) << "Unable to delete printer driver."; + return result; + } + return S_OK; +} + +HRESULT InstallPrinter(void) { + PRINTER_INFO_2 printer_info = {0}; + + // None of the print API structures likes constant strings even though they + // don't modify the string. const_casting is the cleanest option. + base::string16 driver_name = LoadLocalString(IDS_DRIVER_NAME); + printer_info.pDriverName = const_cast<LPWSTR>(driver_name.c_str()); + printer_info.pPrinterName = const_cast<LPWSTR>(driver_name.c_str()); + printer_info.pComment = const_cast<LPWSTR>(driver_name.c_str()); + printer_info.pLocation = const_cast<LPWSTR>(kGcpUrl); + base::string16 port_name; + printer_info.pPortName = const_cast<LPWSTR>(kPortName); + printer_info.Attributes = PRINTER_ATTRIBUTE_DIRECT | PRINTER_ATTRIBUTE_LOCAL; + printer_info.pPrintProcessor = const_cast<LPWSTR>(L"winprint"); + HANDLE handle = AddPrinter(NULL, 2, reinterpret_cast<BYTE*>(&printer_info)); + if (handle == NULL) { + HRESULT result = GetLastHResult(); + LOG(ERROR) << "Unable to add printer"; + return result; + } + ClosePrinter(handle); + return S_OK; +} + +HRESULT UninstallPrinter(void) { + HANDLE handle = NULL; + PRINTER_DEFAULTS printer_defaults = {0}; + printer_defaults.DesiredAccess = PRINTER_ALL_ACCESS; + base::string16 driver_name = LoadLocalString(IDS_DRIVER_NAME); + if (!OpenPrinter(const_cast<LPWSTR>(driver_name.c_str()), &handle, + &printer_defaults)) { + // If we can't open the printer, it was probably already removed. + LOG(WARNING) << "Unable to open printer"; + return S_OK; + } + if (!DeletePrinter(handle)) { + HRESULT result = GetLastHResult(); + LOG(ERROR) << "Unable to delete printer"; + ClosePrinter(handle); + return result; + } + ClosePrinter(handle); + return S_OK; +} + +bool IsOSSupported() { + // We don't support Vista or older. + base::win::Version version = base::win::GetVersion(); + return (version >= base::win::VERSION_WIN7); +} + +HRESULT RegisterVirtualDriver(const base::FilePath& install_path) { + HRESULT result = S_OK; + + DCHECK(base::DirectoryExists(install_path)); + if (!IsOSSupported()) { + LOG(ERROR) << "Requires Windows 7 or later."; + return HRESULT_FROM_WIN32(ERROR_OLD_WIN_VERSION); + } + + result = InstallDriver(install_path); + if (FAILED(result)) { + LOG(ERROR) << "Unable to install driver."; + return result; + } + + result = RegisterPortMonitor(true, install_path); + if (FAILED(result)) { + LOG(ERROR) << "Unable to register port monitor."; + return result; + } + + result = InstallPrinter(); + if (FAILED(result) && + result != HRESULT_FROM_WIN32(ERROR_PRINTER_ALREADY_EXISTS)) { + LOG(ERROR) << "Unable to install printer."; + return result; + } + return S_OK; +} + +HRESULT TryUnregisterVirtualDriver(const base::FilePath& install_path) { + HRESULT result = S_OK; + result = UninstallPrinter(); + if (FAILED(result)) { + LOG(ERROR) << "Unable to delete printer."; + return result; + } + result = UninstallDriver(install_path); + if (FAILED(result)) { + LOG(ERROR) << "Unable to remove driver."; + return result; + } + // The second argument is ignored if the first is false. + result = RegisterPortMonitor(false, base::FilePath()); + if (FAILED(result)) { + LOG(ERROR) << "Unable to remove port monitor."; + return result; + } + return S_OK; +} + +HRESULT UnregisterVirtualDriver(const base::FilePath& install_path) { + HRESULT hr = S_FALSE; + for (int i = 0; i < 2; ++i) { + hr = TryUnregisterVirtualDriver(install_path); + if (SUCCEEDED(hr)) { + break; + } + // Restart spooler and try again. + SpoolerServiceCommand("stop"); + SpoolerServiceCommand("start"); + } + return hr; +} + +HRESULT DoUninstall(const base::FilePath& install_path) { + DeleteGoogleUpdateKeys(kGoogleUpdateProductId); + HRESULT result = UnregisterVirtualDriver(install_path); + if (FAILED(result)) + return result; + DeleteUninstallKey(kUninstallId); + DeleteProgramDir(kDelete); + return S_OK; +} + +HRESULT DoUnregister(const base::FilePath& install_path) { + return UnregisterVirtualDriver(install_path); +} + +HRESULT DoRegister(const base::FilePath& install_path) { + HRESULT result = UnregisterVirtualDriver(install_path); + if (FAILED(result)) + return result; + return RegisterVirtualDriver(install_path); +} + +HRESULT DoDelete(const base::FilePath& install_path) { + if (install_path.value().empty()) + return E_INVALIDARG; + if (!base::DirectoryExists(install_path)) + return S_FALSE; + Sleep(5000); // Give parent some time to exit. + return base::DeleteFile(install_path, true) ? S_OK : E_FAIL; +} + +HRESULT DoInstall(const base::FilePath& install_path) { + HRESULT result = UnregisterVirtualDriver(install_path); + if (FAILED(result)) { + LOG(ERROR) << "Unable to unregister."; + return result; + } + base::FilePath old_install_path = GetInstallLocation(kUninstallId); + if (!old_install_path.value().empty() && install_path != old_install_path) { + if (base::DirectoryExists(old_install_path)) + base::DeleteFile(old_install_path, true); + } + CreateUninstallKey(kUninstallId, LoadLocalString(IDS_DRIVER_NAME), + kUninstallSwitch); + result = RegisterVirtualDriver(install_path); + if (FAILED(result)) + return result; + SetGoogleUpdateKeys(kGoogleUpdateProductId, kNameValue); + return result; +} + +HRESULT ExecuteCommands() { + const base::CommandLine& command_line = + *base::CommandLine::ForCurrentProcess(); + + base::FilePath exe_path; + if (!PathService::Get(base::DIR_EXE, &exe_path) || + !base::DirectoryExists(exe_path)) { + return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND); + } + + if (command_line.HasSwitch(kDelete)) { + return DoDelete(command_line.GetSwitchValuePath(kDelete)); + } else if (command_line.HasSwitch(kUninstallSwitch)) { + return DoUninstall(exe_path); + } else if (command_line.HasSwitch(kInstallSwitch)) { + return DoInstall(exe_path); + } else if (command_line.HasSwitch(kUnregisterSwitch)) { + return DoUnregister(exe_path); + } else if (command_line.HasSwitch(kRegisterSwitch)) { + return DoRegister(exe_path); + } + + return E_INVALIDARG; +} + +} // namespace + +} // namespace cloud_print + +int WINAPI WinMain(__in HINSTANCE hInstance, + __in HINSTANCE hPrevInstance, + __in LPSTR lpCmdLine, + __in int nCmdShow) { + using namespace cloud_print; + + base::AtExitManager at_exit_manager; + base::CommandLine::Init(0, NULL); + + HRESULT retval = ExecuteCommands(); + + if (retval == HRESULT_FROM_WIN32(ERROR_BAD_DRIVER)) { + SetGoogleUpdateError(kGoogleUpdateProductId, + LoadLocalString(IDS_ERROR_NO_XPS)); + } else if (FAILED(retval)) { + SetGoogleUpdateError(kGoogleUpdateProductId, retval); + } + + VLOG(0) << GetErrorMessage(retval) << " HRESULT=0x" << std::setbase(16) + << retval; + + // Installer is silent by default as required by Google Update. + if (base::CommandLine::ForCurrentProcess()->HasSwitch("verbose")) { + DisplayWindowsMessage(NULL, retval, LoadLocalString(IDS_DRIVER_NAME)); + } + return retval; +}
diff --git a/cloud_print/virtual_driver/win/install/virtual_driver_setup_exe.ver b/cloud_print/virtual_driver/win/install/virtual_driver_setup_exe.ver new file mode 100644 index 0000000..1667c07 --- /dev/null +++ b/cloud_print/virtual_driver/win/install/virtual_driver_setup_exe.ver
@@ -0,0 +1,3 @@ +INTERNAL_NAME=virtual_driver_setup.exe +ORIGINAL_FILENAME=virtual_driver_setup.exe +FILETYPE=0x1L
diff --git a/cloud_print/virtual_driver/win/install/virtual_driver_setup_resources.grd b/cloud_print/virtual_driver/win/install/virtual_driver_setup_resources.grd new file mode 100644 index 0000000..e9f9713 --- /dev/null +++ b/cloud_print/virtual_driver/win/install/virtual_driver_setup_resources.grd
@@ -0,0 +1,143 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- +Copyright (c) 2012 The Chromium Authors. All rights reserved. Use of this +source code is governed by a BSD-style license that can be found in the LICENSE +file. +--> + + +<grit latest_public_release="0" current_release="1"> + <outputs> + <output filename="grit/virtual_driver_setup_resources.h" type="rc_header"> + <emit emit_type='prepend'></emit> + </output> + <output filename="virtual_driver_setup_resources_ar.rc" type="rc_all" lang="ar" language_section="lang"/> + <output filename="virtual_driver_setup_resources_bg.rc" type="rc_all" lang="bg" language_section="lang"/> + <output filename="virtual_driver_setup_resources_bn.rc" type="rc_all" lang="bn" language_section="lang"/> + <output filename="virtual_driver_setup_resources_ca.rc" type="rc_all" lang="ca" language_section="lang"/> + <output filename="virtual_driver_setup_resources_cs.rc" type="rc_all" lang="cs" language_section="lang"/> + <output filename="virtual_driver_setup_resources_da.rc" type="rc_all" lang="da" language_section="lang"/> + <output filename="virtual_driver_setup_resources_de.rc" type="rc_all" lang="de" language_section="lang"/> + <output filename="virtual_driver_setup_resources_el.rc" type="rc_all" lang="el" language_section="lang"/> + <output filename="virtual_driver_setup_resources_en.rc" type="rc_all" lang="en" language_section="lang"/> + <output filename="virtual_driver_setup_resources_en-GB.rc" type="rc_all" lang="en-GB" language_section="lang"/> + <output filename="virtual_driver_setup_resources_es.rc" type="rc_all" lang="es" language_section="lang"/> + <output filename="virtual_driver_setup_resources_es-419.rc" type="rc_all" lang="es-419" language_section="lang"/> + <output filename="virtual_driver_setup_resources_et.rc" type="rc_all" lang="et" language_section="lang"/> + <output filename="virtual_driver_setup_resources_fa.rc" type="rc_all" lang="fa" language_section="lang"/> + <output filename="virtual_driver_setup_resources_fi.rc" type="rc_all" lang="fi" language_section="lang"/> + <output filename="virtual_driver_setup_resources_fil.rc" type="rc_all" lang="fil" language_section="lang"/> + <output filename="virtual_driver_setup_resources_fr.rc" type="rc_all" lang="fr" language_section="lang"/> + <output filename="virtual_driver_setup_resources_gu.rc" type="rc_all" lang="gu" language_section="lang"/> + <output filename="virtual_driver_setup_resources_he.rc" type="rc_all" lang="he" language_section="lang"/> + <output filename="virtual_driver_setup_resources_hi.rc" type="rc_all" lang="hi" language_section="lang"/> + <output filename="virtual_driver_setup_resources_hr.rc" type="rc_all" lang="hr" language_section="lang"/> + <output filename="virtual_driver_setup_resources_hu.rc" type="rc_all" lang="hu" language_section="lang"/> + <output filename="virtual_driver_setup_resources_id.rc" type="rc_all" lang="id" language_section="lang"/> + <output filename="virtual_driver_setup_resources_it.rc" type="rc_all" lang="it" language_section="lang"/> + <output filename="virtual_driver_setup_resources_ja.rc" type="rc_all" lang="ja" language_section="lang"/> + <output filename="virtual_driver_setup_resources_kn.rc" type="rc_all" lang="kn" language_section="lang"/> + <output filename="virtual_driver_setup_resources_ko.rc" type="rc_all" lang="ko" language_section="lang"/> + <output filename="virtual_driver_setup_resources_lt.rc" type="rc_all" lang="lt" language_section="lang"/> + <output filename="virtual_driver_setup_resources_lv.rc" type="rc_all" lang="lv" language_section="lang"/> + <output filename="virtual_driver_setup_resources_ml.rc" type="rc_all" lang="ml" language_section="lang"/> + <output filename="virtual_driver_setup_resources_mr.rc" type="rc_all" lang="mr" language_section="lang"/> + <output filename="virtual_driver_setup_resources_ms.rc" type="rc_all" lang="ms" language_section="lang"/> + <output filename="virtual_driver_setup_resources_nl.rc" type="rc_all" lang="nl" language_section="lang"/> + <!-- The translation console uses 'no' for Norwegian Bokmål. It should be 'nb'. --> + <output filename="virtual_driver_setup_resources_nb.rc" type="rc_all" lang="no" language_section="lang"/> + <output filename="virtual_driver_setup_resources_pl.rc" type="rc_all" lang="pl" language_section="lang"/> + <output filename="virtual_driver_setup_resources_pt-BR.rc" type="rc_all" lang="pt-BR" language_section="lang"/> + <output filename="virtual_driver_setup_resources_pt-PT.rc" type="rc_all" lang="pt-PT" language_section="lang"/> + <output filename="virtual_driver_setup_resources_ro.rc" type="rc_all" lang="ro" language_section="lang"/> + <output filename="virtual_driver_setup_resources_ru.rc" type="rc_all" lang="ru" language_section="lang"/> + <output filename="virtual_driver_setup_resources_sk.rc" type="rc_all" lang="sk" language_section="lang"/> + <output filename="virtual_driver_setup_resources_sl.rc" type="rc_all" lang="sl" language_section="lang"/> + <output filename="virtual_driver_setup_resources_sr.rc" type="rc_all" lang="sr" language_section="lang"/> + <output filename="virtual_driver_setup_resources_sv.rc" type="rc_all" lang="sv" language_section="lang"/> + <output filename="virtual_driver_setup_resources_sw.rc" type="rc_all" lang="sw" language_section="lang"/> + <output filename="virtual_driver_setup_resources_ta.rc" type="rc_all" lang="ta" language_section="lang"/> + <output filename="virtual_driver_setup_resources_te.rc" type="rc_all" lang="te" language_section="lang"/> + <output filename="virtual_driver_setup_resources_th.rc" type="rc_all" lang="th" language_section="lang"/> + <output filename="virtual_driver_setup_resources_tr.rc" type="rc_all" lang="tr" language_section="lang"/> + <output filename="virtual_driver_setup_resources_uk.rc" type="rc_all" lang="uk" language_section="lang"/> + <output filename="virtual_driver_setup_resources_vi.rc" type="rc_all" lang="vi" language_section="lang"/> + <output filename="virtual_driver_setup_resources_zh-CN.rc" type="rc_all" lang="zh-CN" language_section="lang"/> + <output filename="virtual_driver_setup_resources_zh-TW.rc" type="rc_all" lang="zh-TW" language_section="lang"/> + </outputs> + <translations> + <file path="resources/virtual_driver_setup_resources_ar.xtb" lang="ar"/> + <file path="resources/virtual_driver_setup_resources_bg.xtb" lang="bg"/> + <file path="resources/virtual_driver_setup_resources_bn.xtb" lang="bn"/> + <file path="resources/virtual_driver_setup_resources_ca.xtb" lang="ca"/> + <file path="resources/virtual_driver_setup_resources_cs.xtb" lang="cs"/> + <file path="resources/virtual_driver_setup_resources_da.xtb" lang="da"/> + <file path="resources/virtual_driver_setup_resources_de.xtb" lang="de"/> + <file path="resources/virtual_driver_setup_resources_el.xtb" lang="el"/> + <file path="resources/virtual_driver_setup_resources_en-GB.xtb" lang="en-GB"/> + <file path="resources/virtual_driver_setup_resources_es.xtb" lang="es"/> + <file path="resources/virtual_driver_setup_resources_es-419.xtb" lang="es-419"/> + <file path="resources/virtual_driver_setup_resources_et.xtb" lang="et"/> + <file path="resources/virtual_driver_setup_resources_fa.xtb" lang="fa"/> + <file path="resources/virtual_driver_setup_resources_fi.xtb" lang="fi"/> + <file path="resources/virtual_driver_setup_resources_fil.xtb" lang="fil" /> + <file path="resources/virtual_driver_setup_resources_fr.xtb" lang="fr" /> + <file path="resources/virtual_driver_setup_resources_gu.xtb" lang="gu" /> + <file path="resources/virtual_driver_setup_resources_he.xtb" lang="he" /> + <file path="resources/virtual_driver_setup_resources_hi.xtb" lang="hi" /> + <file path="resources/virtual_driver_setup_resources_hr.xtb" lang="hr" /> + <file path="resources/virtual_driver_setup_resources_hu.xtb" lang="hu" /> + <file path="resources/virtual_driver_setup_resources_id.xtb" lang="id" /> + <file path="resources/virtual_driver_setup_resources_it.xtb" lang="it" /> + <file path="resources/virtual_driver_setup_resources_ja.xtb" lang="ja" /> + <file path="resources/virtual_driver_setup_resources_kn.xtb" lang="kn" /> + <file path="resources/virtual_driver_setup_resources_ko.xtb" lang="ko" /> + <file path="resources/virtual_driver_setup_resources_lt.xtb" lang="lt" /> + <file path="resources/virtual_driver_setup_resources_lv.xtb" lang="lv" /> + <file path="resources/virtual_driver_setup_resources_ml.xtb" lang="ml" /> + <file path="resources/virtual_driver_setup_resources_mr.xtb" lang="mr" /> + <file path="resources/virtual_driver_setup_resources_ms.xtb" lang="ms" /> + <file path="resources/virtual_driver_setup_resources_nl.xtb" lang="nl" /> + <file path="resources/virtual_driver_setup_resources_no.xtb" lang="no" /> + <file path="resources/virtual_driver_setup_resources_pl.xtb" lang="pl" /> + <file path="resources/virtual_driver_setup_resources_pt-BR.xtb" lang="pt-BR" /> + <file path="resources/virtual_driver_setup_resources_pt-PT.xtb" lang="pt-PT" /> + <file path="resources/virtual_driver_setup_resources_ro.xtb" lang="ro" /> + <file path="resources/virtual_driver_setup_resources_ru.xtb" lang="ru" /> + <file path="resources/virtual_driver_setup_resources_sk.xtb" lang="sk" /> + <file path="resources/virtual_driver_setup_resources_sl.xtb" lang="sl" /> + <file path="resources/virtual_driver_setup_resources_sr.xtb" lang="sr" /> + <file path="resources/virtual_driver_setup_resources_sv.xtb" lang="sv" /> + <file path="resources/virtual_driver_setup_resources_sw.xtb" lang="sw" /> + <file path="resources/virtual_driver_setup_resources_ta.xtb" lang="ta" /> + <file path="resources/virtual_driver_setup_resources_te.xtb" lang="te" /> + <file path="resources/virtual_driver_setup_resources_th.xtb" lang="th" /> + <file path="resources/virtual_driver_setup_resources_tr.xtb" lang="tr" /> + <file path="resources/virtual_driver_setup_resources_uk.xtb" lang="uk" /> + <file path="resources/virtual_driver_setup_resources_vi.xtb" lang="vi" /> + <file path="resources/virtual_driver_setup_resources_zh-CN.xtb" lang="zh-CN" /> + <file path="resources/virtual_driver_setup_resources_zh-TW.xtb" lang="zh-TW" /> + </translations> + <release seq="1"> + <messages> + <message name="IDS_GOOGLE" + meaning="Google" desc="The name of the company that built this."> + Google + </message> + <message name="IDS_DRIVER_NAME" + meaning="Driver Name" desc="The user visible name of the printer we create and its associated driver."> + Google Cloud Printer + </message> + <message name="IDS_ERROR_NO_XPS" + meaning="Error message" desc="XPS driver is not installed."> + <ph name="xps_url"><a href="https://www.microsoft.com/download/details.aspx?id=11816"><ex><a href="https://www.microsoft.com/download/details.aspx?id=11816"></ex></ph>XPS driver<ph name="xps_url_end"></a><ex></a></ex></ph> is not installed. + </message> + </messages> + <includes> + <if expr="lang == 'en'"> + <include name="IDI_ICON" file="resources/cloudprint.ico" type="ICON" translateable="false" /> + </if> + </includes> + </release> +</grit>
diff --git a/cloud_print/virtual_driver/win/port_monitor/BUILD.gn b/cloud_print/virtual_driver/win/port_monitor/BUILD.gn new file mode 100644 index 0000000..43c92f2 --- /dev/null +++ b/cloud_print/virtual_driver/win/port_monitor/BUILD.gn
@@ -0,0 +1,59 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//chrome/process_version_rc_template.gni") + +assert(is_win) + +group("port_monitor") { + public_deps = [ + ":port_monitor_dll", + ] +} + +shared_library("port_monitor_dll") { + output_name = "gcp_portmon" + + sources = [ + "port_monitor.def", + "port_monitor_dll.cc", + ] + + deps = [ + ":lib", + ":resources", + "//base", + "//chrome/common:constants", + "//chrome/common:version_header", + "//cloud_print/common", + "//cloud_print/virtual_driver/win", + ] + + libs = [ "userenv.lib" ] +} + +source_set("lib") { + sources = [ + "port_monitor.cc", + "port_monitor.h", + ] + + deps = [ + "//base", + "//chrome/common:constants", + "//chrome/installer/launcher_support", + "//cloud_print/common", + "//cloud_print/virtual_driver/win", + ] +} + +process_version_rc_template("resources") { + sources = [ + "../gcp_portmon_dll.ver", + ] + + # Note: target_gen_dir will be different for each toolchain so the output + # name doesn't need mangling. + output = "$target_gen_dir/gcp_portmon_dll.rc" +}
diff --git a/cloud_print/virtual_driver/win/port_monitor/port_monitor.cc b/cloud_print/virtual_driver/win/port_monitor/port_monitor.cc new file mode 100644 index 0000000..8748bb6 --- /dev/null +++ b/cloud_print/virtual_driver/win/port_monitor/port_monitor.cc
@@ -0,0 +1,689 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "cloud_print/virtual_driver/win/port_monitor/port_monitor.h" + +#include <windows.h> +#include <lmcons.h> +#include <shellapi.h> +#include <shlobj.h> +#include <stddef.h> +#include <stdint.h> +#include <strsafe.h> +#include <userenv.h> +#include <winspool.h> + +#include "base/at_exit.h" +#include "base/command_line.h" +#include "base/files/file_enumerator.h" +#include "base/files/file_util.h" +#include "base/logging.h" +#include "base/path_service.h" +#include "base/process/launch.h" +#include "base/process/process.h" +#include "base/strings/string16.h" +#include "base/strings/string_util.h" +#include "base/win/registry.h" +#include "base/win/scoped_handle.h" +#include "base/win/windows_version.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/installer/launcher_support/chrome_launcher_support.h" +#include "cloud_print/common/win/cloud_print_utils.h" +#include "cloud_print/virtual_driver/win/port_monitor/spooler_win.h" +#include "cloud_print/virtual_driver/win/virtual_driver_consts.h" +#include "cloud_print/virtual_driver/win/virtual_driver_helpers.h" + +namespace cloud_print { + +namespace { + +const wchar_t kIePath[] = L"Internet Explorer\\iexplore.exe"; + +const char kChromeInstallUrl[] = + "https://google.com/cloudprint/learn/chrome.html"; + +const wchar_t kCloudPrintRegKey[] = L"Software\\Google\\CloudPrint"; + +const wchar_t kXpsMimeType[] = L"application/vnd.ms-xpsdocument"; + +const wchar_t kAppDataDir[] = L"Google\\Cloud Printer"; + +const wchar_t kDocumentPathPlaceHolder[] = L"%%Document_Path%%"; + +const wchar_t kDocumentTypePlaceHolder[] = L"%%Document_Type%%"; + +const wchar_t kJobTitlePlaceHolder[] = L"%%Job_Title%%"; + +struct MonitorData { + std::unique_ptr<base::AtExitManager> at_exit_manager; +}; + +struct PortData { + PortData() : job_id(0), printer_handle(NULL), file(0) {} + ~PortData() { Close(); } + void Close() { + if (printer_handle) { + ClosePrinter(printer_handle); + printer_handle = NULL; + } + if (file) { + base::CloseFile(file); + file = NULL; + } + } + DWORD job_id; + HANDLE printer_handle; + FILE* file; + base::FilePath file_path; +}; + +typedef struct { ACCESS_MASK granted_access; } XcvUiData; + +MONITORUI g_monitor_ui = {sizeof(MONITORUI), MonitorUiAddPortUi, + MonitorUiConfigureOrDeletePortUI, + MonitorUiConfigureOrDeletePortUI}; + +MONITOR2 g_monitor_2 = {sizeof(MONITOR2), + Monitor2EnumPorts, + Monitor2OpenPort, + NULL, // OpenPortEx is not supported. + Monitor2StartDocPort, + Monitor2WritePort, + Monitor2ReadPort, + Monitor2EndDocPort, + Monitor2ClosePort, + NULL, // AddPort is not supported. + NULL, // AddPortEx is not supported. + NULL, // ConfigurePort is not supported. + NULL, // DeletePort is not supported. + NULL, + NULL, // SetPortTimeOuts is not supported. + Monitor2XcvOpenPort, + Monitor2XcvDataPort, + Monitor2XcvClosePort, + Monitor2Shutdown}; + +base::FilePath GetLocalAppDataLow() { + wchar_t system_buffer[MAX_PATH]; + if (FAILED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, + system_buffer))) + return base::FilePath(); + return base::FilePath(system_buffer).DirName().AppendASCII("LocalLow"); +} + +base::FilePath GetAppDataDir() { + base::FilePath file_path; + if (base::win::GetVersion() >= base::win::VERSION_VISTA) + file_path = GetLocalAppDataLow(); + else + PathService::Get(base::DIR_LOCAL_APP_DATA, &file_path); + if (file_path.empty()) { + LOG(ERROR) << "Can't get app data dir"; + } + return file_path.Append(kAppDataDir); +} + +// Delete files which where not deleted by chrome. +void DeleteLeakedFiles(const base::FilePath& dir) { + base::Time delete_before = base::Time::Now() - base::TimeDelta::FromDays(1); + base::FileEnumerator enumerator(dir, false, base::FileEnumerator::FILES); + for (base::FilePath file_path = enumerator.Next(); !file_path.empty(); + file_path = enumerator.Next()) { + if (enumerator.GetInfo().GetLastModifiedTime() < delete_before) + base::DeleteFile(file_path, false); + } +} + +// Attempts to retrieve the title of the specified print job. +// On success returns TRUE and the first title_chars characters of the job title +// are copied into title. +// On failure returns FALSE and title is unmodified. +bool GetJobTitle(HANDLE printer_handle, DWORD job_id, base::string16* title) { + DCHECK(printer_handle != NULL); + DCHECK(title != NULL); + DWORD bytes_needed = 0; + GetJob(printer_handle, job_id, 1, NULL, 0, &bytes_needed); + if (bytes_needed == 0) { + LOG(ERROR) << "Unable to get bytes needed for job info."; + return false; + } + std::unique_ptr<BYTE[]> buffer(new BYTE[bytes_needed]); + if (!GetJob(printer_handle, job_id, 1, buffer.get(), bytes_needed, + &bytes_needed)) { + LOG(ERROR) << "Unable to get job info."; + return false; + } + JOB_INFO_1* job_info = reinterpret_cast<JOB_INFO_1*>(buffer.get()); + *title = job_info->pDocument; + return true; +} + +// Handler for the UI functions exported by the port monitor. +// Verifies that a valid parent Window exists and then just displays an +// error message to let the user know that there is no interactive +// configuration. +void HandlePortUi(HWND hwnd, const base::string16& caption) { + if (hwnd != NULL && IsWindow(hwnd)) { + DisplayWindowsMessage(hwnd, CO_E_NOT_SUPPORTED, cloud_print::kPortName); + } +} + +// Gets the primary token for the user that submitted the print job. +bool GetUserToken(HANDLE* primary_token) { + HANDLE token = NULL; + if (!OpenThreadToken(GetCurrentThread(), + TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY, + FALSE, &token)) { + LOG(ERROR) << "Unable to get thread token."; + return false; + } + base::win::ScopedHandle token_scoped(token); + if (!DuplicateTokenEx( + token, TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY, NULL, + SecurityImpersonation, TokenPrimary, primary_token)) { + LOG(ERROR) << "Unable to get primary thread token."; + return false; + } + return true; +} + +bool LaunchCommandAsUser(const base::CommandLine& command) { + HANDLE token = NULL; + if (!GetUserToken(&token)) { + LOG(ERROR) << "Unable to get user token."; + return false; + } + base::win::ScopedHandle primary_token_scoped(token); + base::LaunchOptions options; + options.as_user = primary_token_scoped.Get(); + base::LaunchProcess(command, options); + return true; +} + +// Escape the command line argument as necessary per Microsoft rules. +// See QuoteForCommandLineToArgvW in base/command_line.cc +base::string16 EscapeCommandLineArg(const base::string16& arg) { + base::string16 quotable_chars(L" \\\""); + if (arg.find_first_of(quotable_chars) == base::string16::npos) { + // No quoting necessary. + return arg; + } + + base::string16 out; + out.push_back(L'"'); + for (size_t i = 0; i < arg.size(); ++i) { + if (arg[i] == '\\') { + // Find the extent of this run of backslashes. + size_t start = i, end = start + 1; + for (; end < arg.size() && arg[end] == '\\'; ++end) { + } + size_t backslash_count = end - start; + + // Backslashes are escapes only if the run is followed by a double quote. + // Since we also will end the string with a double quote, we escape for + // either a double quote or the end of the string. + if (end == arg.size() || arg[end] == '"') { + // To quote, we need to output 2x as many backslashes. + backslash_count *= 2; + } + for (size_t j = 0; j < backslash_count; ++j) + out.push_back('\\'); + + // Advance i to one before the end to balance i++ in loop. + i = end - 1; + } else if (arg[i] == '"') { + out.push_back('\\'); + out.push_back('"'); + } else { + out.push_back(arg[i]); + } + } + out.push_back('"'); + + return out; +} + +// Launch the print command as specified in the cloud print registry. +bool LaunchPrintCommandFromTemplate(const base::string16& command_template, + const base::FilePath& xps_path, + const base::string16& job_title) { + base::string16 command_string(command_template); + // Substitude the place holder with the document path wrapped in quotes. + base::ReplaceFirstSubstringAfterOffset( + &command_string, 0, kDocumentPathPlaceHolder, + EscapeCommandLineArg(xps_path.value())); + // Substitude the place holder with the document type wrapped in quotes. + base::ReplaceFirstSubstringAfterOffset( + &command_string, 0, kDocumentTypePlaceHolder, kXpsMimeType); + // Substitude the place holder with the job title wrapped in quotes. + base::ReplaceFirstSubstringAfterOffset(&command_string, 0, + kJobTitlePlaceHolder, + EscapeCommandLineArg(job_title)); + + base::CommandLine command = base::CommandLine::FromString(command_string); + + return LaunchCommandAsUser(command); +} + +// Launches a page to allow the user to download chrome. +// TODO(abodenha@chromium.org) Point to a custom page explaining what's wrong +// rather than the generic chrome download page. See +// http://code.google.com/p/chromium/issues/detail?id=112019 +void LaunchChromeDownloadPage() { + if (kIsUnittest) + return; + HANDLE token = NULL; + if (!GetUserToken(&token)) { + LOG(ERROR) << "Unable to get user token."; + return; + } + base::win::ScopedHandle token_scoped(token); + + // Consider using the shell to invoke the default browser instead of hardcoded + // reference to IE which might not be available on the system. + base::FilePath ie_path; + PathService::Get(base::DIR_PROGRAM_FILESX86, &ie_path); + ie_path = ie_path.Append(kIePath); + base::CommandLine command_line(ie_path); + command_line.AppendArg(kChromeInstallUrl); + + base::LaunchOptions options; + options.as_user = token_scoped.Get(); + base::LaunchProcess(command_line, options); +} + +// Returns false if the print job is being run in a context +// that shouldn't be launching Chrome. +bool ValidateCurrentUser() { + HANDLE token = NULL; + if (!GetUserToken(&token)) { + // If we can't get the token we're probably not impersonating + // the user, so validation should fail. + return false; + } + base::win::ScopedHandle token_scoped(token); + + if (base::win::GetVersion() >= base::win::VERSION_VISTA) { + DWORD session_id = 0; + DWORD dummy; + if (!GetTokenInformation(token_scoped.Get(), TokenSessionId, + reinterpret_cast<void*>(&session_id), + sizeof(DWORD), &dummy)) { + return false; + } + if (session_id == 0) { + return false; + } + } + return true; +} +} // namespace + +base::string16 ReadStringFromRegistry(HKEY root, const wchar_t* path_name) { + base::win::RegKey gcp_key(root, kCloudPrintRegKey, KEY_READ); + base::string16 data; + gcp_key.ReadValue(path_name, &data); + return data; +} + +base::string16 ReadStringFromAnyRegistry(const wchar_t* path_name) { + base::string16 result = ReadStringFromRegistry(HKEY_CURRENT_USER, path_name); + if (!result.empty()) + return result; + return ReadStringFromRegistry(HKEY_LOCAL_MACHINE, path_name); +} + +base::FilePath GetChromeExePath() { + base::string16 value = ReadStringFromAnyRegistry(kChromeExePathRegValue); + if (!value.empty() && base::PathExists(base::FilePath(value))) + return base::FilePath(value); + return chrome_launcher_support::GetAnyChromePath(false /* is_sxs */); +} + +base::FilePath GetChromeProfilePath() { + base::string16 value = ReadStringFromAnyRegistry(kChromeProfilePathRegValue); + if (!value.empty() && base::DirectoryExists(base::FilePath(value))) + return base::FilePath(value); + return base::FilePath(); +} + +// Launches the Cloud Print dialog in Chrome. +bool LaunchChromePrintDialog(const base::FilePath& xps_path, + const base::string16& job_title) { + base::FilePath chrome_path = GetChromeExePath(); + if (chrome_path.empty()) { + LOG(ERROR) << "Unable to get chrome exe path."; + LaunchChromeDownloadPage(); + return false; + } + + base::CommandLine command_line(chrome_path); + + base::FilePath chrome_profile = GetChromeProfilePath(); + if (!chrome_profile.empty()) + command_line.AppendSwitchPath(switches::kUserDataDir, chrome_profile); + + command_line.AppendSwitchPath(switches::kCloudPrintFile, xps_path); + command_line.AppendSwitchNative(switches::kCloudPrintFileType, kXpsMimeType); + command_line.AppendSwitchNative(switches::kCloudPrintJobTitle, job_title); + + return LaunchCommandAsUser(command_line); +} + +base::string16 GetPrintCommandTemplate() { + return ReadStringFromAnyRegistry(kPrintCommandRegValue); +} + +// Launches the print command. This will either launch Chrome to display the +// Cloud Print dialog or another exe as specified in the cloud print registry. +// xps_path references a file to print. +// job_title is the title to be used for the resulting print job. +bool LaunchPrintCommand(const base::FilePath& xps_path, + const base::string16& job_title) { + base::string16 command_template = GetPrintCommandTemplate(); + if (!command_template.empty()) { + return LaunchPrintCommandFromTemplate(command_template, xps_path, + job_title); + } else { + return LaunchChromePrintDialog(xps_path, job_title); + } +} + +BOOL WINAPI Monitor2EnumPorts(HANDLE, + wchar_t*, + DWORD level, + BYTE* ports, + DWORD ports_size, + DWORD* needed_bytes, + DWORD* returned) { + if (needed_bytes == NULL) { + LOG(ERROR) << "needed_bytes should not be NULL."; + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + if (level == 1) { + *needed_bytes = sizeof(PORT_INFO_1); + } else if (level == 2) { + *needed_bytes = sizeof(PORT_INFO_2); + } else { + LOG(ERROR) << "Level " << level << "is not supported."; + SetLastError(ERROR_INVALID_LEVEL); + return FALSE; + } + *needed_bytes += static_cast<DWORD>(cloud_print::kPortNameSize); + if (ports_size < *needed_bytes) { + LOG(WARNING) << *needed_bytes << " bytes are required. Only " << ports_size + << " were allocated."; + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + if (ports == NULL) { + LOG(ERROR) << "ports should not be NULL."; + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + if (returned == NULL) { + LOG(ERROR) << "returned should not be NULL."; + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + // Windows expects any strings refernced by PORT_INFO_X structures to + // appear at the END of the buffer referenced by ports. Placing + // strings immediately after the PORT_INFO_X structure will cause + // EnumPorts to fail until the spooler is restarted. + // This is NOT mentioned in the documentation. + wchar_t* string_target = reinterpret_cast<wchar_t*>( + ports + ports_size - cloud_print::kPortNameSize); + if (level == 1) { + PORT_INFO_1* port_info = reinterpret_cast<PORT_INFO_1*>(ports); + port_info->pName = string_target; + StringCbCopy(port_info->pName, cloud_print::kPortNameSize, + cloud_print::kPortName); + } else { + PORT_INFO_2* port_info = reinterpret_cast<PORT_INFO_2*>(ports); + port_info->pPortName = string_target; + StringCbCopy(port_info->pPortName, cloud_print::kPortNameSize, + cloud_print::kPortName); + port_info->pMonitorName = NULL; + port_info->pDescription = NULL; + port_info->fPortType = PORT_TYPE_WRITE; + port_info->Reserved = 0; + } + *returned = 1; + return TRUE; +} + +BOOL WINAPI Monitor2OpenPort(HANDLE, wchar_t*, HANDLE* handle) { + if (handle == NULL) { + LOG(ERROR) << "handle should not be NULL."; + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + *handle = new PortData(); + return TRUE; +} + +BOOL WINAPI Monitor2StartDocPort(HANDLE port_handle, + wchar_t* printer_name, + DWORD job_id, + DWORD, + BYTE*) { + SetGoogleUpdateUsage(kGoogleUpdateProductId); + if (port_handle == NULL) { + LOG(ERROR) << "port_handle should not be NULL."; + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + if (printer_name == NULL) { + LOG(ERROR) << "printer_name should not be NULL."; + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + if (!ValidateCurrentUser()) { + // TODO(abodenha@chromium.org) Abort the print job. + return FALSE; + } + PortData* port_data = reinterpret_cast<PortData*>(port_handle); + port_data->job_id = job_id; + if (!OpenPrinter(printer_name, &(port_data->printer_handle), NULL)) { + LOG(WARNING) << "Unable to open printer " << printer_name << "."; + // We can continue without a handle to the printer. + // It just means we can't get the job title or tell the spooler that + // the print job is complete. + // This is the normal flow during a unit test. + port_data->printer_handle = NULL; + } + base::FilePath& file_path = port_data->file_path; + base::FilePath app_data_dir = GetAppDataDir(); + if (app_data_dir.empty()) + return FALSE; + DeleteLeakedFiles(app_data_dir); + if (!base::CreateDirectory(app_data_dir) || + !base::CreateTemporaryFileInDir(app_data_dir, &file_path)) { + LOG(ERROR) << "Can't create temporary file in " << app_data_dir.value(); + return FALSE; + } + port_data->file = base::OpenFile(file_path, "wb+"); + if (port_data->file == NULL) { + LOG(ERROR) << "Error opening file " << file_path.value() << "."; + return FALSE; + } + return TRUE; +} + +BOOL WINAPI Monitor2WritePort(HANDLE port_handle, + BYTE* buffer, + DWORD buffer_size, + DWORD* bytes_written) { + PortData* port_data = reinterpret_cast<PortData*>(port_handle); + if (!ValidateCurrentUser()) { + // TODO(abodenha@chromium.org) Abort the print job. + return FALSE; + } + *bytes_written = + static_cast<DWORD>(fwrite(buffer, 1, buffer_size, port_data->file)); + if (*bytes_written > 0) { + return TRUE; + } else { + return FALSE; + } +} + +BOOL WINAPI Monitor2ReadPort(HANDLE, BYTE*, DWORD, DWORD* read_bytes) { + LOG(ERROR) << "Read is not supported."; + *read_bytes = 0; + SetLastError(ERROR_NOT_SUPPORTED); + return FALSE; +} + +BOOL WINAPI Monitor2EndDocPort(HANDLE port_handle) { + if (!ValidateCurrentUser()) { + // TODO(abodenha@chromium.org) Abort the print job. + return FALSE; + } + PortData* port_data = reinterpret_cast<PortData*>(port_handle); + if (port_data == NULL) { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (port_data->file != NULL) { + base::CloseFile(port_data->file); + port_data->file = NULL; + bool delete_file = true; + int64_t file_size = 0; + base::GetFileSize(port_data->file_path, &file_size); + if (file_size > 0) { + base::string16 job_title; + if (port_data->printer_handle != NULL) { + GetJobTitle(port_data->printer_handle, port_data->job_id, &job_title); + } + if (LaunchPrintCommand(port_data->file_path, job_title)) { + delete_file = false; + } + } + if (delete_file) + base::DeleteFile(port_data->file_path, false); + } + if (port_data->printer_handle != NULL) { + // Tell the spooler that the job is complete. + SetJob(port_data->printer_handle, port_data->job_id, 0, NULL, + JOB_CONTROL_SENT_TO_PRINTER); + } + port_data->Close(); + // Return success even if we can't display the dialog. + // TODO(abodenha@chromium.org) Come up with a better way of handling + // this situation. + return TRUE; +} + +BOOL WINAPI Monitor2ClosePort(HANDLE port_handle) { + if (port_handle == NULL) { + LOG(ERROR) << "port_handle should not be NULL."; + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + delete reinterpret_cast<PortData*>(port_handle); + return TRUE; +} + +VOID WINAPI Monitor2Shutdown(HANDLE monitor_handle) { + if (monitor_handle != NULL) { + delete reinterpret_cast<MonitorData*>(monitor_handle); + } +} + +BOOL WINAPI Monitor2XcvOpenPort(HANDLE, + const wchar_t*, + ACCESS_MASK granted_access, + HANDLE* handle) { + if (handle == NULL) { + LOG(ERROR) << "handle should not be NULL."; + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + XcvUiData* xcv_data = new XcvUiData(); + xcv_data->granted_access = granted_access; + *handle = xcv_data; + return TRUE; +} + +DWORD WINAPI Monitor2XcvDataPort(HANDLE xcv_handle, + const wchar_t* data_name, + BYTE*, + DWORD, + BYTE* output_data, + DWORD output_data_bytes, + DWORD* output_data_bytes_needed) { + XcvUiData* xcv_data = reinterpret_cast<XcvUiData*>(xcv_handle); + DWORD ret_val = ERROR_SUCCESS; + if ((xcv_data->granted_access & SERVER_ACCESS_ADMINISTER) == 0) { + return ERROR_ACCESS_DENIED; + } + if (output_data == NULL || output_data_bytes == 0) { + return ERROR_INVALID_PARAMETER; + } + // We don't handle AddPort or DeletePort since we don't support + // dynamic creation of ports. + if (lstrcmp(L"MonitorUI", data_name) == 0) { + DWORD dll_path_len = 0; + base::FilePath dll_path(L"gcp_portmon.dll"); + dll_path_len = static_cast<DWORD>(dll_path.value().length()); + if (output_data_bytes_needed != NULL) { + *output_data_bytes_needed = dll_path_len; + } + if (output_data_bytes < dll_path_len) { + return ERROR_INSUFFICIENT_BUFFER; + } else { + ret_val = StringCbCopy(reinterpret_cast<wchar_t*>(output_data), + output_data_bytes, dll_path.value().c_str()); + } + } else { + return ERROR_INVALID_PARAMETER; + } + return ret_val; +} + +BOOL WINAPI Monitor2XcvClosePort(HANDLE handle) { + delete reinterpret_cast<XcvUiData*>(handle); + return TRUE; +} + +BOOL WINAPI MonitorUiAddPortUi(const wchar_t*, + HWND hwnd, + const wchar_t* monitor_name, + wchar_t**) { + HandlePortUi(hwnd, monitor_name); + return TRUE; +} + +BOOL WINAPI MonitorUiConfigureOrDeletePortUI(const wchar_t*, + HWND hwnd, + const wchar_t* port_name) { + HandlePortUi(hwnd, port_name); + return TRUE; +} + +} // namespace cloud_print + +MONITOR2* WINAPI InitializePrintMonitor2(MONITORINIT*, HANDLE* handle) { + if (handle == NULL) { + SetLastError(ERROR_INVALID_PARAMETER); + return NULL; + } + cloud_print::MonitorData* monitor_data = new cloud_print::MonitorData; + *handle = monitor_data; + if (!cloud_print::kIsUnittest) { + // Unit tests set up their own AtExitManager + monitor_data->at_exit_manager.reset(new base::AtExitManager()); + // Single spooler.exe handles verbose users. + PathService::DisableCache(); + } + return &cloud_print::g_monitor_2; +} + +MONITORUI* WINAPI InitializePrintMonitorUI(void) { + return &cloud_print::g_monitor_ui; +}
diff --git a/cloud_print/virtual_driver/win/port_monitor/port_monitor.def b/cloud_print/virtual_driver/win/port_monitor/port_monitor.def new file mode 100644 index 0000000..3b2cd17 --- /dev/null +++ b/cloud_print/virtual_driver/win/port_monitor/port_monitor.def
@@ -0,0 +1,9 @@ +; Copyright (c) 2011 The Chromium Authors. All rights reserved. +; Use of this source code is governed by a BSD-style license that can be +; found in the LICENSE file. + +EXPORTS + InitializePrintMonitor2 + InitializePrintMonitorUI + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE
diff --git a/cloud_print/virtual_driver/win/port_monitor/port_monitor.h b/cloud_print/virtual_driver/win/port_monitor/port_monitor.h new file mode 100644 index 0000000..aac9663 --- /dev/null +++ b/cloud_print/virtual_driver/win/port_monitor/port_monitor.h
@@ -0,0 +1,94 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CLOUD_PRINT_VIRTUAL_DRIVER_WIN_PORT_MONITOR_PORT_MONITOR_H_ +#define CLOUD_PRINT_VIRTUAL_DRIVER_WIN_PORT_MONITOR_PORT_MONITOR_H_ + +#include <windows.h> +#include <string> +#include "base/files/file_util.h" +#include "base/process/process.h" +#include "base/strings/string16.h" + +namespace cloud_print { + +// Returns path to be used for launching Chrome. +base::FilePath GetChromeExePath(); + +// Returns path to user profile to be used for launching Chrome. +base::FilePath GetChromeProfilePath(); + +// Returns the print command to launch, if set, instead of Chrome. +base::string16 GetPrintCommandTemplate(); + +// Implementations for the function pointers in the MONITOR2 structure +// returned by InitializePrintMonitor2. The prototypes and behaviors +// are as described in the MONITOR2 documentation from Microsoft. + +BOOL WINAPI Monitor2EnumPorts(HANDLE, + wchar_t*, + DWORD level, + BYTE* ports, + DWORD ports_size, + DWORD* needed_bytes, + DWORD* returned); + +BOOL WINAPI Monitor2OpenPort(HANDLE monitor_data, wchar_t*, HANDLE* handle); + +BOOL WINAPI Monitor2StartDocPort(HANDLE port_handle, + wchar_t* printer_name, + DWORD job_id, + DWORD, + BYTE*); + +BOOL WINAPI Monitor2WritePort(HANDLE port, + BYTE* buffer, + DWORD buffer_size, + DWORD* bytes_written); + +BOOL WINAPI Monitor2ReadPort(HANDLE, BYTE*, DWORD, DWORD* bytes_read); + +BOOL WINAPI Monitor2EndDocPort(HANDLE port_handle); + +BOOL WINAPI Monitor2ClosePort(HANDLE port_handle); + +VOID WINAPI Monitor2Shutdown(HANDLE monitor_handle); + +BOOL WINAPI Monitor2XcvOpenPort(HANDLE monitor, + const wchar_t*, + ACCESS_MASK granted_access, + HANDLE* handle); + +DWORD WINAPI Monitor2XcvDataPort(HANDLE xcv_handle, + const wchar_t* data_name, + BYTE*, + DWORD, + BYTE* output_data, + DWORD output_data_bytes, + DWORD* output_data_bytes_needed); + +BOOL WINAPI Monitor2XcvClosePort(HANDLE handle); + +// Implementations for the function pointers in the MONITORUI structure +// returned by InitializePrintMonitorUI. The prototypes and behaviors +// are as described in the MONITORUI documentation from Microsoft. + +BOOL WINAPI MonitorUiAddPortUi(const wchar_t*, + HWND hwnd, + const wchar_t* monitor_name, + wchar_t**); + +BOOL WINAPI MonitorUiConfigureOrDeletePortUI(const wchar_t*, + HWND hwnd, + const wchar_t* port_name); + +extern const wchar_t kChromeExePath[]; +extern const wchar_t kChromeExePathRegValue[]; +extern const wchar_t kChromeProfilePathRegValue[]; +extern const wchar_t kPrintCommandRegValue[]; +extern const bool kIsUnittest; + +} // namespace cloud_print + +#endif // CLOUD_PRINT_VIRTUAL_DRIVER_WIN_PORT_MONITOR_PORT_MONITOR_H_
diff --git a/cloud_print/virtual_driver/win/port_monitor/port_monitor_dll.cc b/cloud_print/virtual_driver/win/port_monitor/port_monitor_dll.cc new file mode 100644 index 0000000..66039bc9 --- /dev/null +++ b/cloud_print/virtual_driver/win/port_monitor/port_monitor_dll.cc
@@ -0,0 +1,96 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "cloud_print/virtual_driver/win/port_monitor/port_monitor.h" + +#include <windows.h> +#include <lmcons.h> +#include <shellapi.h> +#include <shlobj.h> +#include <strsafe.h> +#include <userenv.h> +#include <winspool.h> + +#include "base/at_exit.h" +#include "base/command_line.h" +#include "base/files/file_util.h" +#include "base/logging.h" +#include "base/process/process_info.h" +#include "base/strings/string16.h" +#include "base/win/registry.h" +#include "base/win/scoped_handle.h" +#include "base/win/windows_version.h" +#include "chrome/common/chrome_switches.h" +#include "cloud_print/common/win/cloud_print_utils.h" +#include "cloud_print/virtual_driver/win/port_monitor/spooler_win.h" +#include "cloud_print/virtual_driver/win/virtual_driver_consts.h" +#include "cloud_print/virtual_driver/win/virtual_driver_helpers.h" + +namespace cloud_print { + +const wchar_t kChromeExePath[] = L"google\\chrome\\application\\chrome.exe"; +const wchar_t kChromeExePathRegValue[] = L"PathToChromeExe"; +const wchar_t kChromeProfilePathRegValue[] = L"PathToChromeProfile"; +const wchar_t kPrintCommandRegValue[] = L"PrintCommand"; +const bool kIsUnittest = false; + +namespace { + +// Returns true if Xps support is installed. +bool XpsIsInstalled() { + base::FilePath xps_path; + if (!SUCCEEDED(GetPrinterDriverDir(&xps_path))) { + return false; + } + xps_path = xps_path.Append(L"mxdwdrv.dll"); + if (!base::PathExists(xps_path)) { + return false; + } + return true; +} + +// Returns true if registration/unregistration can be attempted. +bool CanRegister() { + if (!XpsIsInstalled()) { + return false; + } + if (base::win::GetVersion() >= base::win::VERSION_VISTA) { + if (base::GetCurrentProcessIntegrityLevel() != base::HIGH_INTEGRITY) + return false; + } + return true; +} + +} // namespace + +} // namespace cloud_print + +HRESULT WINAPI DllRegisterServer(void) { + base::AtExitManager at_exit_manager; + if (!cloud_print::CanRegister()) { + return E_ACCESSDENIED; + } + MONITOR_INFO_2 monitor_info = {0}; + // YUCK!!! I can either copy the constant, const_cast, or define my own + // MONITOR_INFO_2 that will take const strings. + base::FilePath dll_path(L"gcp_portmon.dll"); + monitor_info.pDLLName = const_cast<LPWSTR>(dll_path.value().c_str()); + monitor_info.pName = const_cast<LPWSTR>(dll_path.value().c_str()); + if (AddMonitor(NULL, 2, reinterpret_cast<BYTE*>(&monitor_info))) { + return S_OK; + } + return cloud_print::GetLastHResult(); +} + +HRESULT WINAPI DllUnregisterServer(void) { + base::AtExitManager at_exit_manager; + if (!cloud_print::CanRegister()) { + return E_ACCESSDENIED; + } + base::FilePath dll_path(L"gcp_portmon.dll"); + if (DeleteMonitor(NULL, NULL, const_cast<LPWSTR>(dll_path.value().c_str()))) { + return S_OK; + } + return cloud_print::GetLastHResult(); +}
diff --git a/cloud_print/virtual_driver/win/port_monitor/port_monitor_unittest.cc b/cloud_print/virtual_driver/win/port_monitor/port_monitor_unittest.cc new file mode 100644 index 0000000..3ef126c --- /dev/null +++ b/cloud_print/virtual_driver/win/port_monitor/port_monitor_unittest.cc
@@ -0,0 +1,248 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "cloud_print/virtual_driver/win/port_monitor/port_monitor.h" + +#include <stddef.h> +#include <winspool.h> + +#include "base/files/file_util.h" +#include "base/macros.h" +#include "base/path_service.h" +#include "base/strings/string16.h" +#include "base/win/registry.h" +#include "base/win/scoped_handle.h" +#include "cloud_print/virtual_driver/win/port_monitor/spooler_win.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace cloud_print { + +const wchar_t kChromeExePath[] = L"google\\chrome\\application\\chrometest.exe"; +const wchar_t kChromeExePathRegValue[] = L"PathToChromeTestExe"; +const wchar_t kChromeProfilePathRegValue[] = L"PathToChromeTestProfile"; +const wchar_t kPrintCommandRegValue[] = L"TestPrintCommand"; +const bool kIsUnittest = true; + +namespace { + +const wchar_t kAlternateChromeExePath[] = + L"google\\chrome\\application\\chrometestalternate.exe"; +const wchar_t kTestPrintCommand[] = L"testprintcommand.exe"; + +const wchar_t kCloudPrintRegKey[] = L"Software\\Google\\CloudPrint"; + +} // namespace + +class PortMonitorTest : public testing::Test { + public: + PortMonitorTest() {} + + protected: + // Creates a registry entry pointing at a chrome + virtual void SetUpChromeExeRegistry() { + // Create a temporary chrome.exe location value. + base::win::RegKey key(HKEY_CURRENT_USER, cloud_print::kCloudPrintRegKey, + KEY_ALL_ACCESS); + + base::FilePath path; + PathService::Get(base::DIR_LOCAL_APP_DATA, &path); + path = path.Append(kAlternateChromeExePath); + ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(cloud_print::kChromeExePathRegValue, + path.value().c_str())); + base::FilePath temp; + PathService::Get(base::DIR_TEMP, &temp); + // Write any dir here. + ASSERT_EQ(ERROR_SUCCESS, + key.WriteValue(cloud_print::kChromeProfilePathRegValue, + temp.value().c_str())); + + ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(cloud_print::kPrintCommandRegValue, + kTestPrintCommand)); + } + // Deletes the registry entry created in SetUpChromeExeRegistry + virtual void DeleteChromeExeRegistry() { + base::win::RegKey key(HKEY_CURRENT_USER, cloud_print::kCloudPrintRegKey, + KEY_ALL_ACCESS); + key.DeleteValue(cloud_print::kChromeExePathRegValue); + key.DeleteValue(cloud_print::kChromeProfilePathRegValue); + key.DeleteValue(cloud_print::kPrintCommandRegValue); + } + + virtual void CreateTempChromeExeFiles() { + base::FilePath path; + PathService::Get(base::DIR_LOCAL_APP_DATA, &path); + base::FilePath main_path = path.Append(kChromeExePath); + ASSERT_TRUE(base::CreateDirectory(main_path)); + base::FilePath alternate_path = path.Append(kAlternateChromeExePath); + ASSERT_TRUE(base::CreateDirectory(alternate_path)); + } + + virtual void DeleteTempChromeExeFiles() { + base::FilePath path; + PathService::Get(base::DIR_LOCAL_APP_DATA, &path); + base::FilePath main_path = path.Append(kChromeExePath); + ASSERT_TRUE(base::DeleteFile(main_path, true)); + PathService::Get(base::DIR_LOCAL_APP_DATA, &path); + base::FilePath alternate_path = path.Append(kAlternateChromeExePath); + ASSERT_TRUE(base::DeleteFile(alternate_path, true)); + } + + protected: + void SetUp() override { SetUpChromeExeRegistry(); } + + void TearDown() override { DeleteChromeExeRegistry(); } + + private: + DISALLOW_COPY_AND_ASSIGN(PortMonitorTest); +}; + +TEST_F(PortMonitorTest, GetChromeExePathTest) { + CreateTempChromeExeFiles(); + base::FilePath chrome_path = cloud_print::GetChromeExePath(); + EXPECT_FALSE(chrome_path.empty()); + EXPECT_TRUE(chrome_path.value().rfind(kAlternateChromeExePath) != + std::string::npos); + EXPECT_TRUE(base::PathExists(chrome_path)); + DeleteChromeExeRegistry(); + chrome_path = cloud_print::GetChromeExePath(); + // No Chrome or regular chrome path. + EXPECT_TRUE(chrome_path.empty() || + chrome_path.value().rfind(kChromeExePath) == std::string::npos); +} + +TEST_F(PortMonitorTest, GetPrintCommandTemplateTest) { + base::string16 print_command = cloud_print::GetPrintCommandTemplate(); + EXPECT_FALSE(print_command.empty()); + EXPECT_EQ(print_command, kTestPrintCommand); + DeleteChromeExeRegistry(); + print_command = cloud_print::GetPrintCommandTemplate(); + EXPECT_TRUE(print_command.empty()); +} + +TEST_F(PortMonitorTest, GetChromeProfilePathTest) { + base::FilePath data_path = cloud_print::GetChromeProfilePath(); + EXPECT_FALSE(data_path.empty()); + base::FilePath temp; + PathService::Get(base::DIR_TEMP, &temp); + EXPECT_EQ(data_path, temp); + EXPECT_TRUE(base::DirectoryExists(data_path)); + DeleteChromeExeRegistry(); + data_path = cloud_print::GetChromeProfilePath(); + EXPECT_TRUE(data_path.empty()); +} + +TEST_F(PortMonitorTest, EnumPortsTest) { + DWORD needed_bytes = 0; + DWORD returned = 0; + EXPECT_FALSE( + Monitor2EnumPorts(NULL, NULL, 1, NULL, 0, &needed_bytes, &returned)); + EXPECT_EQ(static_cast<DWORD>(ERROR_INSUFFICIENT_BUFFER), GetLastError()); + EXPECT_NE(0u, needed_bytes); + EXPECT_EQ(0u, returned); + + BYTE* buffer = new BYTE[needed_bytes]; + ASSERT_TRUE(buffer != NULL); + EXPECT_TRUE(Monitor2EnumPorts(NULL, NULL, 1, buffer, needed_bytes, + &needed_bytes, &returned)); + EXPECT_NE(0u, needed_bytes); + EXPECT_EQ(1u, returned); + PORT_INFO_1* port_info_1 = reinterpret_cast<PORT_INFO_1*>(buffer); + EXPECT_TRUE(port_info_1->pName != NULL); + delete[] buffer; + + returned = 0; + needed_bytes = 0; + EXPECT_FALSE( + Monitor2EnumPorts(NULL, NULL, 2, NULL, 0, &needed_bytes, &returned)); + EXPECT_EQ(static_cast<DWORD>(ERROR_INSUFFICIENT_BUFFER), GetLastError()); + EXPECT_NE(0u, needed_bytes); + EXPECT_EQ(0u, returned); + + buffer = new BYTE[needed_bytes]; + ASSERT_TRUE(buffer != NULL); + EXPECT_TRUE(Monitor2EnumPorts(NULL, NULL, 2, buffer, needed_bytes, + &needed_bytes, &returned)); + EXPECT_NE(0u, needed_bytes); + EXPECT_EQ(1u, returned); + PORT_INFO_2* port_info_2 = reinterpret_cast<PORT_INFO_2*>(buffer); + EXPECT_TRUE(port_info_2->pPortName != NULL); + delete[] buffer; +} + +TEST_F(PortMonitorTest, FlowTest) { + const wchar_t kXcvDataItem[] = L"MonitorUI"; + MONITORINIT monitor_init = {0}; + HANDLE monitor_handle = NULL; + HANDLE port_handle = NULL; + HANDLE xcv_handle = NULL; + DWORD bytes_processed = 0; + DWORD bytes_needed = 0; + const size_t kBufferSize = 100; + BYTE buffer[kBufferSize] = {0}; + + // Initialize the print monitor + MONITOR2* monitor2 = InitializePrintMonitor2(&monitor_init, &monitor_handle); + EXPECT_TRUE(monitor2 != NULL); + EXPECT_TRUE(monitor_handle != NULL); + + // Test the XCV functions. Used for reporting the location of the + // UI portion of the port monitor. + EXPECT_TRUE(monitor2->pfnXcvOpenPort != NULL); + EXPECT_TRUE(monitor2->pfnXcvOpenPort(monitor_handle, NULL, 0, &xcv_handle)); + EXPECT_TRUE(xcv_handle != NULL); + EXPECT_TRUE(monitor2->pfnXcvDataPort != NULL); + EXPECT_EQ(static_cast<DWORD>(ERROR_ACCESS_DENIED), + monitor2->pfnXcvDataPort(xcv_handle, kXcvDataItem, NULL, 0, buffer, + kBufferSize, &bytes_needed)); + EXPECT_TRUE(monitor2->pfnXcvClosePort != NULL); + EXPECT_TRUE(monitor2->pfnXcvClosePort(xcv_handle)); + EXPECT_TRUE(monitor2->pfnXcvOpenPort(monitor_handle, NULL, + SERVER_ACCESS_ADMINISTER, &xcv_handle)); + EXPECT_TRUE(xcv_handle != NULL); + EXPECT_TRUE(monitor2->pfnXcvDataPort != NULL); + EXPECT_EQ(static_cast<DWORD>(ERROR_SUCCESS), + monitor2->pfnXcvDataPort(xcv_handle, kXcvDataItem, NULL, 0, buffer, + kBufferSize, &bytes_needed)); + EXPECT_TRUE(monitor2->pfnXcvClosePort != NULL); + EXPECT_TRUE(monitor2->pfnXcvClosePort(xcv_handle)); + + // Test opening the port and running a print job. + EXPECT_TRUE(monitor2->pfnOpenPort != NULL); + EXPECT_TRUE(monitor2->pfnOpenPort(monitor_handle, NULL, &port_handle)); + EXPECT_TRUE(port_handle != NULL); + EXPECT_TRUE(monitor2->pfnStartDocPort != NULL); + EXPECT_TRUE(monitor2->pfnWritePort != NULL); + EXPECT_TRUE(monitor2->pfnReadPort != NULL); + EXPECT_TRUE(monitor2->pfnEndDocPort != NULL); + + // These functions should fail if we have not impersonated the user. + EXPECT_FALSE(monitor2->pfnStartDocPort(port_handle, const_cast<wchar_t*>(L""), + 0, 0, NULL)); + EXPECT_FALSE(monitor2->pfnWritePort(port_handle, buffer, kBufferSize, + &bytes_processed)); + EXPECT_EQ(0u, bytes_processed); + EXPECT_FALSE(monitor2->pfnReadPort(port_handle, buffer, sizeof(buffer), + &bytes_processed)); + EXPECT_EQ(0u, bytes_processed); + EXPECT_FALSE(monitor2->pfnEndDocPort(port_handle)); + + // Now impersonate so we can test the success case. + ASSERT_TRUE(ImpersonateSelf(SecurityImpersonation)); + EXPECT_TRUE(monitor2->pfnStartDocPort(port_handle, const_cast<wchar_t*>(L""), + 0, 0, NULL)); + EXPECT_TRUE(monitor2->pfnWritePort(port_handle, buffer, kBufferSize, + &bytes_processed)); + EXPECT_EQ(kBufferSize, bytes_processed); + EXPECT_FALSE(monitor2->pfnReadPort(port_handle, buffer, sizeof(buffer), + &bytes_processed)); + EXPECT_EQ(0u, bytes_processed); + EXPECT_TRUE(monitor2->pfnEndDocPort(port_handle)); + RevertToSelf(); + EXPECT_TRUE(monitor2->pfnClosePort != NULL); + EXPECT_TRUE(monitor2->pfnClosePort(port_handle)); + // Shutdown the port monitor. + Monitor2Shutdown(monitor_handle); +} + +} // namespace cloud_print
diff --git a/cloud_print/virtual_driver/win/port_monitor/spooler_win.h b/cloud_print/virtual_driver/win/port_monitor/spooler_win.h new file mode 100644 index 0000000..e6073f9 --- /dev/null +++ b/cloud_print/virtual_driver/win/port_monitor/spooler_win.h
@@ -0,0 +1,98 @@ +// Copyright (c) 2011 The Chromium 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 CLOUD_PRINT_VIRTUAL_DRIVER_WIN_PORT_MONITOR_SPOOLER_WIN_H_ +#define CLOUD_PRINT_VIRTUAL_DRIVER_WIN_PORT_MONITOR_SPOOLER_WIN_H_ + +#include <windows.h> + +// Compatible structures and prototypes are also defined in the Windows DDK in +// winsplp.h. +#ifndef _WINSPLP_ + +typedef struct { + DWORD size; + BOOL(WINAPI* pfnEnumPorts) + (HANDLE, + wchar_t*, + DWORD level, + BYTE* ports, + DWORD ports_size, + DWORD* needed_bytes, + DWORD* returned); + + BOOL(WINAPI* pfnOpenPort)(HANDLE monitor_data, wchar_t*, HANDLE* handle); + + void* pfnOpenPortEx; // Unused. + + BOOL(WINAPI* pfnStartDocPort) + (HANDLE port_handle, wchar_t* printer_name, DWORD job_id, DWORD, BYTE*); + + BOOL(WINAPI* pfnWritePort) + (HANDLE port, BYTE* buffer, DWORD buffer_size, DWORD* bytes_written); + + BOOL(WINAPI* pfnReadPort)(HANDLE, BYTE*, DWORD, DWORD* bytes_read); + + BOOL(WINAPI* pfnEndDocPort)(HANDLE port_handle); + + BOOL(WINAPI* pfnClosePort)(HANDLE port_handle); + + void* pfnAddPort; // Unused. + + void* pfnAddPortEx; // Unused. + + void* pfnConfigurePort; // Unused. + + void* pfnDeletePort; // Unused. + + void* pfnGetPrinterDataFromPort; // Unused. + + void* pfnSetPortTimeOuts; // Unusued. + + BOOL(WINAPI* pfnXcvOpenPort) + (HANDLE monitor, const wchar_t*, ACCESS_MASK granted_access, HANDLE* handle); + + DWORD(WINAPI* pfnXcvDataPort) + (HANDLE xcv_handle, + const wchar_t* data_name, + BYTE*, + DWORD, + BYTE* output_data, + DWORD output_data_bytes, + DWORD* output_data_bytes_needed); + + BOOL(WINAPI* pfnXcvClosePort)(HANDLE handle); + + VOID(WINAPI* pfnShutdown)(HANDLE monitor_handle); +} MONITOR2; + +typedef struct { + DWORD size; + + BOOL(WINAPI* pfnAddPortUI) + (const wchar_t*, HWND hwnd, const wchar_t* monitor_name, wchar_t**); + + BOOL(WINAPI* pfnConfigurePortUI) + (const wchar_t*, HWND hwnd, const wchar_t* port_name); + + BOOL(WINAPI* pfnDeletePortUI) + (const wchar_t*, HWND hwnd, const wchar_t* port_name); +} MONITORUI; + +typedef struct { + DWORD cbSize; + HANDLE hSpooler; + HKEY hckRegistryRoot; + void* pMonitorReg; // Unused + BOOL bLocal; + LPCWSTR pszServerName; +} MONITORINIT; + +MONITOR2* WINAPI InitializePrintMonitor2(MONITORINIT* monitor_init, + HANDLE* monitor_handle); + +MONITORUI* WINAPI InitializePrintMonitorUI(void); + +#endif // ifdef USE_WIN_DDK +#endif // CLOUD_PRINT_VIRTUAL_DRIVER_WIN_PORT_MONITOR_SPOOLER_WIN_H_
diff --git a/cloud_print/virtual_driver/win/virtual_driver_consts.cc b/cloud_print/virtual_driver/win/virtual_driver_consts.cc new file mode 100644 index 0000000..ffa975f --- /dev/null +++ b/cloud_print/virtual_driver/win/virtual_driver_consts.cc
@@ -0,0 +1,19 @@ +// Copyright (c) 2011 The Chromium 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 "cloud_print/virtual_driver/win/virtual_driver_consts.h" + +#include <windows.h> +#include <stddef.h> + +#include "cloud_print/virtual_driver/win/virtual_driver_helpers.h" + +namespace cloud_print { + +const wchar_t kPortName[] = L"GCP:"; +const size_t kPortNameSize = sizeof(kPortName); +const wchar_t kGoogleUpdateProductId[] = + L"{9B13FA92-1F73-4761-AB78-2C6ADAC3660D}"; + +} // namespace cloud_print
diff --git a/cloud_print/virtual_driver/win/virtual_driver_consts.h b/cloud_print/virtual_driver/win/virtual_driver_consts.h new file mode 100644 index 0000000..f97022d --- /dev/null +++ b/cloud_print/virtual_driver/win/virtual_driver_consts.h
@@ -0,0 +1,16 @@ +// Copyright (c) 2011 The Chromium 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 CLOUD_PRINT_VIRTUAL_DRIVER_WIN_VIRTUAL_DRIVER_CONSTS_H_ +#define CLOUD_PRINT_VIRTUAL_DRIVER_WIN_VIRTUAL_DRIVER_CONSTS_H_ + +namespace cloud_print { + +extern const wchar_t kPortName[]; +extern const size_t kPortNameSize; +extern const wchar_t kGoogleUpdateProductId[]; + +} // namespace cloud_print + +#endif // CLOUD_PRINT_VIRTUAL_DRIVER_WIN_VIRTUAL_DRIVER_CONSTS_H_
diff --git a/cloud_print/virtual_driver/win/virtual_driver_helpers.cc b/cloud_print/virtual_driver/win/virtual_driver_helpers.cc new file mode 100644 index 0000000..603447c --- /dev/null +++ b/cloud_print/virtual_driver/win/virtual_driver_helpers.cc
@@ -0,0 +1,39 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "cloud_print/virtual_driver/win/virtual_driver_helpers.h" + +#include <windows.h> +#include <winspool.h> + +#include "base/files/file_util.h" +#include "base/logging.h" +#include "base/strings/string16.h" +#include "base/win/windows_version.h" +#include "cloud_print/common/win/cloud_print_utils.h" + +namespace cloud_print { + +void DisplayWindowsMessage(HWND hwnd, + HRESULT hr, + const base::string16& caption) { + ::MessageBox(hwnd, GetErrorMessage(hr).c_str(), caption.c_str(), MB_OK); +} + +HRESULT GetPrinterDriverDir(base::FilePath* path) { + BYTE driver_dir_buffer[MAX_PATH * sizeof(wchar_t)]; + DWORD needed = 0; + if (!GetPrinterDriverDirectory(NULL, NULL, 1, driver_dir_buffer, + MAX_PATH * sizeof(wchar_t), &needed)) { + // We could try to allocate a larger buffer if needed > MAX_PATH + // but that really shouldn't happen. + return cloud_print::GetLastHResult(); + } + *path = base::FilePath(reinterpret_cast<wchar_t*>(driver_dir_buffer)); + + // The XPS driver is a "Level 3" driver + *path = path->Append(L"3"); + return S_OK; +} +}
diff --git a/cloud_print/virtual_driver/win/virtual_driver_helpers.h b/cloud_print/virtual_driver/win/virtual_driver_helpers.h new file mode 100644 index 0000000..eadebe8 --- /dev/null +++ b/cloud_print/virtual_driver/win/virtual_driver_helpers.h
@@ -0,0 +1,28 @@ +// Copyright (c) 2011 The Chromium 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 CLOUD_PRINT_VIRTUAL_DRIVER_WIN_VIRTUAL_DRIVER_HELPERS_H_ +#define CLOUD_PRINT_VIRTUAL_DRIVER_WIN_VIRTUAL_DRIVER_HELPERS_H_ + +#include <windows.h> + +#include "base/strings/string16.h" + +namespace base { +class FilePath; +} + +namespace cloud_print { + +// Convert an HRESULT to a localized string and display it in a message box. +void DisplayWindowsMessage(HWND hwnd, + HRESULT hr, + const base::string16& caption); + +// Gets the standard install path for "version 3" print drivers. +HRESULT GetPrinterDriverDir(base::FilePath* path); + +} // namespace cloud_print + +#endif // CLOUD_PRINT_VIRTUAL_DRIVER_WIN_VIRTUAL_DRIVER_HELPERS_H_
diff --git a/components/metrics/public/cpp/call_stack_profile_struct_traits.h b/components/metrics/public/cpp/call_stack_profile_struct_traits.h index f623b2d..99c4fe3c 100644 --- a/components/metrics/public/cpp/call_stack_profile_struct_traits.h +++ b/components/metrics/public/cpp/call_stack_profile_struct_traits.h
@@ -136,10 +136,21 @@ static bool Read(metrics::mojom::CallStackProfileDataView data, base::StackSamplingProfiler::CallStackProfile* out) { - return data.ReadModules(&out->modules) && data.ReadSamples(&out->samples) && - data.ReadProfileDuration(&out->profile_duration) && - data.ReadSamplingPeriod(&out->sampling_period) && - ValidateSamples(out->samples, out->modules.size()); + std::vector<base::StackSamplingProfiler::Module> modules; + std::vector<base::StackSamplingProfiler::Sample> samples; + base::TimeDelta profile_duration, sampling_period; + if (!data.ReadModules(&modules) || !data.ReadSamples(&samples) || + !data.ReadProfileDuration(&profile_duration) || + !data.ReadSamplingPeriod(&sampling_period) || + !ValidateSamples(samples, modules.size())) + return false; + + *out = base::StackSamplingProfiler::CallStackProfile(); + out->modules = std::move(modules); + out->samples = std::move(samples); + out->profile_duration = profile_duration; + out->sampling_period = sampling_period; + return true; } };
diff --git a/components/ntp_snippets/OWNERS b/components/ntp_snippets/OWNERS index 9e1ec3b7..5facc94e 100644 --- a/components/ntp_snippets/OWNERS +++ b/components/ntp_snippets/OWNERS
@@ -1,4 +1,10 @@ -noyau@chromium.org +# Main owners: bauerb@chromium.org +jkrcal@chromium.org treib@chromium.org + +# For ios: +noyau@chromium.org + +# Fallback, in case all of the above are OOO: markusheintz@chromium.org
diff --git a/components/ntp_tiles/BUILD.gn b/components/ntp_tiles/BUILD.gn index 9a8ae6b..503c3866 100644 --- a/components/ntp_tiles/BUILD.gn +++ b/components/ntp_tiles/BUILD.gn
@@ -22,6 +22,7 @@ "most_visited_sites.h", "ntp_tile.cc", "ntp_tile.h", + "ntp_tile_source.h", "popular_sites.cc", "popular_sites.h", "pref_names.cc", @@ -99,7 +100,7 @@ java_cpp_enum("ntp_tiles_enums_java") { sources = [ "metrics.h", - "ntp_tile.h", + "ntp_tile_source.h", ] } }
diff --git a/components/ntp_tiles/ntp_tile.h b/components/ntp_tiles/ntp_tile.h index ef228b54..fa37cf8 100644 --- a/components/ntp_tiles/ntp_tile.h +++ b/components/ntp_tiles/ntp_tile.h
@@ -10,24 +10,11 @@ #include "base/files/file_path.h" #include "base/macros.h" #include "base/strings/string16.h" +#include "components/ntp_tiles/ntp_tile_source.h" #include "url/gurl.h" namespace ntp_tiles { -// The source of an NTP tile. -// A Java counterpart will be generated for this enum. -// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.ntp -enum class NTPTileSource { - // Tile comes from the personal top sites list, based on local history. - TOP_SITES, - // Tile comes from the suggestions service, based on synced history. - SUGGESTIONS_SERVICE, - // Tile is regionally popular. - POPULAR, - // Tile is on an custodian-managed whitelist. - WHITELIST -}; - // A suggested site shown on the New Tab Page. struct NTPTile { base::string16 title;
diff --git a/components/ntp_tiles/ntp_tile_source.h b/components/ntp_tiles/ntp_tile_source.h new file mode 100644 index 0000000..1ac85a9 --- /dev/null +++ b/components/ntp_tiles/ntp_tile_source.h
@@ -0,0 +1,28 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_NTP_TILES_NTP_TILE_SOURCE_H_ +#define COMPONENTS_NTP_TILES_NTP_TILE_SOURCE_H_ + +namespace ntp_tiles { + +// The source of an NTP tile. +// A Java counterpart will be generated for this enum. +// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.ntp +enum class NTPTileSource { + // Tile comes from the personal top sites list, based on local history. + TOP_SITES, + // Tile comes from the suggestions service, based on synced history. + SUGGESTIONS_SERVICE, + // Tile is regionally popular. + POPULAR, + // Tile is on a custodian-managed whitelist. + WHITELIST, + + LAST = WHITELIST +}; + +} // namespace ntp_tiles + +#endif // COMPONENTS_NTP_TILES_NTP_TILE_SOURCE_H_
diff --git a/components/subresource_filter/content/renderer/document_subresource_filter.cc b/components/subresource_filter/content/renderer/document_subresource_filter.cc index 8e326a9e..dadb24c3eb 100644 --- a/components/subresource_filter/content/renderer/document_subresource_filter.cc +++ b/components/subresource_filter/content/renderer/document_subresource_filter.cc
@@ -13,6 +13,7 @@ #include "components/subresource_filter/core/common/first_party_origin.h" #include "components/subresource_filter/core/common/memory_mapped_ruleset.h" #include "components/subresource_filter/core/common/scoped_timers.h" +#include "components/subresource_filter/core/common/time_measurements.h" #include "third_party/WebKit/public/platform/WebURL.h" namespace subresource_filter { @@ -130,18 +131,18 @@ TRACE_EVENT1("loader", "DocumentSubresourceFilter::allowLoad", "url", resourceUrl.string().utf8()); - auto wall_duration_exporter = [this](base::TimeDelta delta) { - statistics_.evaluation_total_wall_duration += delta; - UMA_HISTOGRAM_MICRO_TIMES( - "SubresourceFilter.SubresourceLoad.Evaluation.WallDuration", delta); - }; - auto cpu_duration_exporter = [this](base::TimeDelta delta) { - statistics_.evaluation_total_cpu_duration += delta; - UMA_HISTOGRAM_MICRO_TIMES( - "SubresourceFilter.SubresourceLoad.Evaluation.CPUDuration", delta); - }; - SCOPED_TIMER(wall_duration_exporter); - SCOPED_THREAD_TIMER(cpu_duration_exporter); + auto wall_duration_timer = ScopedTimers::StartIf( + ScopedThreadTimers::IsSupported(), [this](base::TimeDelta delta) { + statistics_.evaluation_total_wall_duration += delta; + UMA_HISTOGRAM_MICRO_TIMES( + "SubresourceFilter.SubresourceLoad.Evaluation.WallDuration", delta); + }); + auto cpu_duration_timer = + ScopedThreadTimers::Start([this](base::TimeDelta delta) { + statistics_.evaluation_total_cpu_duration += delta; + UMA_HISTOGRAM_MICRO_TIMES( + "SubresourceFilter.SubresourceLoad.Evaluation.CPUDuration", delta); + }); ++statistics_.num_loads_total;
diff --git a/components/subresource_filter/content/renderer/subresource_filter_agent.cc b/components/subresource_filter/content/renderer/subresource_filter_agent.cc index 6e6c1aa..409e646 100644 --- a/components/subresource_filter/content/renderer/subresource_filter_agent.cc +++ b/components/subresource_filter/content/renderer/subresource_filter_agent.cc
@@ -12,7 +12,7 @@ #include "components/subresource_filter/content/renderer/document_subresource_filter.h" #include "components/subresource_filter/content/renderer/ruleset_dealer.h" #include "components/subresource_filter/core/common/memory_mapped_ruleset.h" -#include "components/subresource_filter/core/common/scoped_timers.h" +#include "components/subresource_filter/core/common/time_measurements.h" #include "content/public/common/browser_side_navigation_policy.h" #include "content/public/renderer/render_frame.h" #include "ipc/ipc_message.h" @@ -96,15 +96,16 @@ "SubresourceFilter.DocumentLoad.NumSubresourceLoads.Disallowed", statistics.num_loads_disallowed); - UMA_HISTOGRAM_CUSTOM_MICRO_TIMES( - "SubresourceFilter.DocumentLoad.SubresourceEvaluation." - "TotalWallDuration", - statistics.evaluation_total_wall_duration, - base::TimeDelta::FromMicroseconds(1), base::TimeDelta::FromSeconds(10), - 50); + // If ThreadTicks is not supported, then no CPU time measurements have been + // collected. Don't report both CPU and wall duration to be consistent. + if (ScopedThreadTimers::IsSupported()) { + UMA_HISTOGRAM_CUSTOM_MICRO_TIMES( + "SubresourceFilter.DocumentLoad.SubresourceEvaluation." + "TotalWallDuration", + statistics.evaluation_total_wall_duration, + base::TimeDelta::FromMicroseconds(1), base::TimeDelta::FromSeconds(10), + 50); - // If ThreadTicks is not supported, then no measurements have been collected. - if (base::ThreadTicks::IsSupported()) { UMA_HISTOGRAM_CUSTOM_MICRO_TIMES( "SubresourceFilter.DocumentLoad.SubresourceEvaluation.TotalCPUDuration", statistics.evaluation_total_cpu_duration,
diff --git a/components/subresource_filter/core/browser/ruleset_service.cc b/components/subresource_filter/core/browser/ruleset_service.cc index 031a1f08..d772734 100644 --- a/components/subresource_filter/core/browser/ruleset_service.cc +++ b/components/subresource_filter/core/browser/ruleset_service.cc
@@ -28,7 +28,7 @@ #include "components/subresource_filter/core/common/copying_file_stream.h" #include "components/subresource_filter/core/common/indexed_ruleset.h" #include "components/subresource_filter/core/common/proto/rules.pb.h" -#include "components/subresource_filter/core/common/scoped_timers.h" +#include "components/subresource_filter/core/common/time_measurements.h" #include "components/subresource_filter/core/common/unindexed_ruleset.h" #include "third_party/protobuf/src/google/protobuf/io/zero_copy_stream_impl_lite.h"
diff --git a/components/subresource_filter/core/common/BUILD.gn b/components/subresource_filter/core/common/BUILD.gn index 7708731c..905a444 100644 --- a/components/subresource_filter/core/common/BUILD.gn +++ b/components/subresource_filter/core/common/BUILD.gn
@@ -25,6 +25,7 @@ "ngram_extractor.h", "scoped_timers.h", "string_splitter.h", + "time_measurements.h", "uint64_hasher.h", "unindexed_ruleset.cc", "unindexed_ruleset.h",
diff --git a/components/subresource_filter/core/common/scoped_timers.h b/components/subresource_filter/core/common/scoped_timers.h index 58a834c2..6eb617b1 100644 --- a/components/subresource_filter/core/common/scoped_timers.h +++ b/components/subresource_filter/core/common/scoped_timers.h
@@ -2,171 +2,34 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// This file provides tools for measuring time intervals and reporting them to -// UMA histograms or via custom functors. It is possible to measure time both -// with base::TimeTicks and base::ThreadTicks. -// WARNING: *UMA_HISTOGRAM_* macros in this file are not thread-safe. -// See also: "base/metrics/histogram_macros*.h". +// This file provides a ScopedTimerImpl class which measures its lifetime using +// different time providers, and can report the measurement via user-defined +// callbacks. The class comes with ScopedTimerImplFactory which has convenient +// factory methods returning timer instances. // -// TODO(pkalinnikov): Consider moving content of this file to "base/metrics/*" -// after some refactoring. Note that most of the code generated by the macros -// below is not thread-safe. +// Although the classes can be used directly, the most common usages are covered +// by the ScopedTimers and ScopedThreadTimers type aliases. See comments to +// these aliases below. +// +// TODO(pkalinnikov): Consider moving this file to "base/metrics/". #ifndef COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_SCOPED_TIMERS_ #define COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_SCOPED_TIMERS_ #include <type_traits> +#include <utility> #include "base/macros.h" -#include "base/metrics/histogram.h" #include "base/time/time.h" namespace subresource_filter { -// Creates a scoped object that measures its lifetime using base::TimeTicks, and -// reports the result as base::TimeDelta via provided |export_functor|. The -// functor is copied if passed in by value. -// -// Example: -// void Function() { -// auto export_time = [](base::TimeDelta delta) { -// LOG(INFO) << "Duration: " << delta.InMicroseconds(); -// }; -// SCOPED_TIMER(export_time); -// ... Useful things happen here ... -// } // |export_time| will be triggered here. -// -// This is recommended for when you want to measure the time it takes for a -// method/scope to execute, including, possibly, the time spent by the thread on -// being blocked and/or descheduled. -#define SCOPED_TIMER(export_functor) \ - IMPL_SCOPED_TIMER_EXPANDER(impl::TimeTicksProvider, export_functor, \ - __COUNTER__) - -// Similar to SCOPED_TIMER, but uses base::ThreadTicks for measuring time. -// -// This is recommended for when you want to measure the time it takes for a -// method/scope to do actual work, i.e. excluding the time spent by the thread -// on being blocked and/or descheduled. -#define SCOPED_THREAD_TIMER(export_functor) \ - IMPL_SCOPED_TIMER_EXPANDER(impl::ThreadTicksProvider, export_functor, \ - __COUNTER__) - -// Creates a scoped object that measures its lifetime using base::ThreadTicks, -// and reports the result in milliseconds as a UMA statistic to a histogram with -// the provided |name| which is expected to be a runtime constant. The histogram -// collects times up to 10 seconds in 50 buckets. -// -// Under the hood there is a static base::HistogramBase* pointer initialized -// right before the scoped object. The pointer is used by a specific -// |export_functor| passed in to a SCOPED_THREAD_TIMER (see it above). -// -// Example: -// void Function() { -// SCOPED_UMA_HISTOGRAM_THREAD_TIMER("Component.FunctionTime"); -// ... Useful things happen here ... -// } -// -// WARNING: The generated code is not thread-safe. -#define SCOPED_UMA_HISTOGRAM_THREAD_TIMER(name) \ - IMPL_SCOPED_UMA_HISTOGRAM_TIMER_EXPANDER( \ - name, impl::ThreadTicksProvider, impl::ExportMillisecondsToHistogram, \ - 10 * 1000, __COUNTER__) - -// Similar to SCOPED_UMA_HISTOGRAM_THREAD_TIMER above, but the histogram -// collects times in microseconds, up to 1 second, and using 50 buckets. -// -// WARNING: The generated code is not thread-safe. -#define SCOPED_UMA_HISTOGRAM_MICRO_THREAD_TIMER(name) \ - IMPL_SCOPED_UMA_HISTOGRAM_TIMER_EXPANDER( \ - name, impl::ThreadTicksProvider, impl::ExportMicrosecondsToHistogram, \ - 1000 * 1000, __COUNTER__) - -// Similar to SCOPED_UMA_HISTOGRAM_TIMER in "base/metrics/histogram_macros.h", -// but the histogram stores times in microseconds, up to 1 second, in 50 -// buckets. -// -// WARNING: The generated code is not thread-safe. -#define SCOPED_UMA_HISTOGRAM_MICRO_TIMER(name) \ - IMPL_SCOPED_UMA_HISTOGRAM_TIMER_EXPANDER( \ - name, impl::TimeTicksProvider, impl::ExportMicrosecondsToHistogram, \ - 1000 * 1000, __COUNTER__) - -// Similar to UMA_HISTOGRAM_TIMES in "base/metrics/histogram_macros.h", but -// the histogram stores times in microseconds, up to 1 second, in 50 buckets. -// -// WARNING: The generated code is not thread-safe. -#define UMA_HISTOGRAM_MICRO_TIMES(name, sample) \ - UMA_HISTOGRAM_CUSTOM_MICRO_TIMES(name, sample, \ - base::TimeDelta::FromMicroseconds(1), \ - base::TimeDelta::FromSeconds(1), 50) - -// This can be used when the default ranges are not sufficient. This macro lets -// the metric developer customize the min and max of the sampled range, as well -// as the number of buckets recorded. -#define UMA_HISTOGRAM_CUSTOM_MICRO_TIMES(name, sample, min, max, bucket_count) \ - IMPL_UMA_HISTOGRAM_ADD(name, sample.InMicroseconds(), min.InMicroseconds(), \ - max.InMicroseconds(), bucket_count) - -// ----------------------------------------------------------------------------- -// Below are helpers used by other macros. Shouldn't be used directly. --------- - -// This is necessary to expand __COUNTER__ to an actual value. -#define IMPL_SCOPED_TIMER_EXPANDER(time_provider, export_functor, suffix) \ - IMPL_SCOPED_TIMER_UNIQUE(time_provider, export_functor, suffix) - -// Creates a scoped timer, which uses |time_provider| to measure time, and -// |export_functor| to report it. -#define IMPL_SCOPED_TIMER_UNIQUE(time_provider, export_functor, suffix) \ - impl::ScopedTimer<time_provider, decltype(export_functor)> \ - scoped_timer_##suffix(export_functor); - -// This is necessary to expand __COUNTER__ to an actual value. -#define IMPL_SCOPED_UMA_HISTOGRAM_TIMER_EXPANDER( \ - name, time_provider, histogram_exporter, max_value, suffix) \ - IMPL_SCOPED_UMA_HISTOGRAM_TIMER_UNIQUE( \ - name, time_provider, histogram_exporter, max_value, suffix) - -// Creates a static histogram pointer and a scoped object referring to it -// throught the |histogram_exporter| functor. Both the pointer and the scoped -// object are uniquely-named, using the unique |suffix| passed in. -#define IMPL_SCOPED_UMA_HISTOGRAM_TIMER_UNIQUE( \ - name, time_provider, histogram_exporter, max_value, suffix) \ - IMPL_DEFINE_STATIC_UMA_HISTOGRAM_POINTER(name, 1, max_value, 50, suffix) \ - IMPL_SCOPED_TIMER_UNIQUE(time_provider, \ - (histogram_exporter(histogram_##suffix)), suffix) - -// This is necessary to expand __COUNTER__ to an actual value. -#define IMPL_UMA_HISTOGRAM_MICRO_TIMES_EXPANDER(name, max_value, suffix, \ - sample) \ - IMPL_UMA_HISTOGRAM_MICRO_TIMES_UNIQUE(name, max_value, suffix, sample) - -// Defines a static UMA histogram pointer and writes a |sample| to it. -#define IMPL_UMA_HISTOGRAM_ADD(name, sample, min, max, bucket_count) \ - do { \ - IMPL_DEFINE_STATIC_UMA_HISTOGRAM_POINTER(name, min, max, bucket_count, 0) \ - histogram_0->Add(sample); \ - } while (0) - -// Defines a static pointer to a UMA histogram. -// -// WARNING: Static local variable initialization is deliberately *not* -// thread-safe in Chrome builds. See the "-fno-threadsafe-statics" flag in -// "build/config/compiler/BUILD.gn" and "/Zc:threadSafeInit-" in -// "build/config/win/BUILD.gn" for details. -#define IMPL_DEFINE_STATIC_UMA_HISTOGRAM_POINTER(name, min, max, bucket_count, \ - suffix) \ - static base::HistogramBase* histogram_##suffix = \ - base::Histogram::FactoryGet( \ - name, min, max, bucket_count, \ - base::HistogramBase::kUmaTargetedHistogramFlag); - namespace impl { -// ScopedTimer is a multi-purpose scoped timer. It measures time delta from its -// construction till destruction. For example, by putting an instance of this -// class to the beginning of a scope it is possible to measure how long the -// scope is being executed. +// ScopedTimerImpl is a multi-purpose scoped timer. It measures time delta from +// its construction until its destruction. For example, by putting an instance +// of this class to the beginning of a scope it is possible to measure how long +// the scope is being executed. // // The obtained time measurement is reported via ExportFunctor, which takes // base::TimeDelta as a parameter. @@ -179,23 +42,46 @@ // * static TimeType Now(); // - Returns the current time of some TimeType, e.g., base::TimeTicks. // -// Time measurement is exported exactly once, unless TimeProvider::IsSupported() -// is false. In the latter case ExportFunctor is never called. +// The ExportFunctor is invoked exactly once, upon destruction, if both +// |activate| and TimeProvider::IsSupported() are true. Otherwise, the +// ExportFunctor is not called and no time measurements are performed, making +// the overhead of an instance practically zero. template <typename TimeProvider, typename ExportFunctor> -class ScopedTimer { +class ScopedTimerImpl { public: - ScopedTimer(ExportFunctor export_functor) : export_functor_(export_functor) { - if (TimeProvider::IsSupported()) { + // Constructs a timer reporting its measurement to |export_functor|. The timer + // will be activated iff |activate| && TimeProvider::IsSupported(). + explicit ScopedTimerImpl(ExportFunctor&& export_functor, bool activate = true) + : export_functor_(std::forward<ExportFunctor>(export_functor)), + activated_(activate && TimeProvider::IsSupported()) { + if (activated_) { TimeProvider::WaitUntilInitialized(); construction_time_ = TimeProvider::Now(); } } - ~ScopedTimer() { - if (TimeProvider::IsSupported()) { - const base::TimeDelta delta = TimeProvider::Now() - construction_time_; - export_functor_(delta); + // The class is moveable. The |rhs| becomes deactivated when it is moved from, + // so that no time measurement will be reported upon its destruction. + ScopedTimerImpl(ScopedTimerImpl&& rhs) + : export_functor_(std::forward<ExportFunctor>(rhs.export_functor_)), + construction_time_(std::move(rhs.construction_time_)), + activated_(rhs.activated_) { + rhs.activated_ = false; + } + + // If |this| was activated before assignment, it reports its measurement + // before stealing the one from |rhs|. + ScopedTimerImpl& operator=(ScopedTimerImpl&& rhs) { + if (&rhs != this) { + this->~ScopedTimerImpl(); + ::new (this) ScopedTimerImpl(std::move(rhs)); } + return *this; + } + + ~ScopedTimerImpl() { + if (activated_) + export_functor_(TimeProvider::Now() - construction_time_); } private: @@ -204,8 +90,9 @@ ExportFunctor export_functor_; TimeType construction_time_; + bool activated_ = false; - DISALLOW_COPY_AND_ASSIGN(ScopedTimer); + DISALLOW_COPY_AND_ASSIGN(ScopedTimerImpl); }; // TimeProvider implementations ------------------------------------------------ @@ -219,30 +106,51 @@ using ThreadTicksProvider = base::ThreadTicks; -// ExportFunctor implementations ----------------------------------------------- +// ScopedTimerImpl factories --------------------------------------------------- -template <bool is_microsec_precision> -class ExportTimeDeltaToHistogram { +// The class used to produce scoped timers using a certain |TimeProvider|. +template <typename TimeProvider> +class ScopedTimerImplFactory { public: - ExportTimeDeltaToHistogram(base::HistogramBase* histogram) - : histogram_(histogram) {} - - void operator()(base::TimeDelta delta) { - if (is_microsec_precision) - histogram_->Add(delta.InMicroseconds()); - else - histogram_->Add(delta.InMilliseconds()); + // Returns a scoped timer which uses |export_functor| to report its + // measurement. The timer is activated iff TimeProvider::IsSupported(). + template <typename ExportFunctor> + static ScopedTimerImpl<TimeProvider, ExportFunctor> Start( + ExportFunctor&& export_functor) { + return ScopedTimerImpl<TimeProvider, ExportFunctor>( + std::forward<ExportFunctor>(export_functor)); } - private: - base::HistogramBase* histogram_; + // Similar to the Start method above, but the timer is activated iff + // |condition| && TimeProvider::IsSupported(). + template <typename ExportFunctor> + static ScopedTimerImpl<TimeProvider, ExportFunctor> StartIf( + bool condition, + ExportFunctor&& export_functor) { + return ScopedTimerImpl<TimeProvider, ExportFunctor>( + std::forward<ExportFunctor>(export_functor), condition); + } + + static bool IsSupported() { return TimeProvider::IsSupported(); } }; -using ExportMillisecondsToHistogram = ExportTimeDeltaToHistogram<false>; -using ExportMicrosecondsToHistogram = ExportTimeDeltaToHistogram<true>; - } // namespace impl +// A factory to produce scoped timers that measure time by means of TimeTicks. +// +// Example usage: +// void foo() { +// auto scoped_timer = ScopedTimers::Start([](base::TimeDelta duration) { +// LOG(INFO) << "Duration: " << duration.InMicroseconds() << " us"; +// }); +// ... Some time-consuming code goes here ... +// } +using ScopedTimers = impl::ScopedTimerImplFactory<impl::TimeTicksProvider>; + +// Similar to ScopedTimers, but the produced timers use ThreadTicks. +using ScopedThreadTimers = + impl::ScopedTimerImplFactory<impl::ThreadTicksProvider>; + } // namespace subresource_filter #endif // COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_SCOPED_TIMERS_
diff --git a/components/subresource_filter/core/common/scoped_timers_unittest.cc b/components/subresource_filter/core/common/scoped_timers_unittest.cc index 80cc66c..4a10af7 100644 --- a/components/subresource_filter/core/common/scoped_timers_unittest.cc +++ b/components/subresource_filter/core/common/scoped_timers_unittest.cc
@@ -6,11 +6,12 @@ #include "base/test/histogram_tester.h" #include "base/time/time.h" +#include "components/subresource_filter/core/common/time_measurements.h" #include "testing/gtest/include/gtest/gtest.h" namespace { -class ExportFunctorForTests { +class MockExportFunctor { public: int number_of_calls() const { return number_of_calls_; } void operator()(base::TimeDelta) { ++number_of_calls_; } @@ -19,74 +20,138 @@ int number_of_calls_ = 0; }; -// Casts an l-value parameter to a reference to it. -template <typename T> -T& reference(T& value) { - return value; +template <typename TimerFactory> +void ExpectFunctorIsCalledOnceOnDestruction() { + MockExportFunctor export_functor; + { + auto scoped_timer = TimerFactory::Start(export_functor); + EXPECT_EQ(0, export_functor.number_of_calls()); + } + const int expected_number_of_calls = TimerFactory::IsSupported() ? 1 : 0; + EXPECT_EQ(expected_number_of_calls, export_functor.number_of_calls()); +} + +template <typename TimerFactory> +void ExpectStoredLambdaIsInvokedOnceOnDestruction() { + bool export_is_called = false; + auto export_functor = [&export_is_called](base::TimeDelta) { + EXPECT_FALSE(export_is_called); + export_is_called = true; + }; + + { + auto scoped_timer = TimerFactory::Start(export_functor); + EXPECT_FALSE(export_is_called); + } + EXPECT_EQ(TimerFactory::IsSupported(), export_is_called); +} + +template <typename TimerFactory> +void ExpectInlineLambdaIsInvokedOnceOnDestruction() { + bool export_is_called = false; + { + auto scoped_timer = + TimerFactory::Start([&export_is_called](base::TimeDelta) { + EXPECT_FALSE(export_is_called); + export_is_called = true; + }); + EXPECT_FALSE(export_is_called); + } + EXPECT_EQ(TimerFactory::IsSupported(), export_is_called); +} + +template <typename TimerFactory> +void ExpectWellBehavedStartIf(bool condition) { + bool export_is_called = false; + auto export_functor = [&export_is_called](base::TimeDelta) { + EXPECT_FALSE(export_is_called); + export_is_called = true; + }; + + { + auto scoped_timer = TimerFactory::StartIf(condition, export_functor); + EXPECT_FALSE(export_is_called); + } + EXPECT_EQ(condition && TimerFactory::IsSupported(), export_is_called); +} + +template <typename TimerFactory> +void ExpectWellBehavedMoveContructor() { + MockExportFunctor export_functor; + const int expected_number_of_calls = TimerFactory::IsSupported() ? 1 : 0; + { + auto scoped_timer = TimerFactory::Start(export_functor); + EXPECT_EQ(0, export_functor.number_of_calls()); + { + auto another_scoped_timer = std::move(scoped_timer); + EXPECT_EQ(0, export_functor.number_of_calls()); + } + // |another_scoped_timer| should have called |export_functor|. + EXPECT_EQ(expected_number_of_calls, export_functor.number_of_calls()); + } + // But |scoped_timer| should have not since then. + EXPECT_EQ(expected_number_of_calls, export_functor.number_of_calls()); +} + +template <typename TimerFactory> +void ExpectWellBehavedMoveAssignment() { + MockExportFunctor export_functor; + const int expected_number_of_calls = TimerFactory::IsSupported() ? 1 : 0; + { + auto scoped_timer = TimerFactory::Start(export_functor); + EXPECT_EQ(0, export_functor.number_of_calls()); + { + auto another_scoped_timer = std::move(scoped_timer); + scoped_timer = std::move(another_scoped_timer); + EXPECT_EQ(0, export_functor.number_of_calls()); + } + // |another_scoped_timer| shouldn't have called |export_functor|. + EXPECT_EQ(0, export_functor.number_of_calls()); + } + // But |scoped_timer| should have because it owns the measurement. + EXPECT_EQ(expected_number_of_calls, export_functor.number_of_calls()); } } // namespace namespace subresource_filter { -TEST(ScopedTimersTest, ScopedTimerCallsFunctor) { - ExportFunctorForTests export_functor; - { - // Reference is needed to bypass object copying. - SCOPED_TIMER(reference(export_functor)); - EXPECT_EQ(0, export_functor.number_of_calls()); - } - EXPECT_EQ(1, export_functor.number_of_calls()); +TEST(ScopedTimersTest, CallsFunctor) { + ExpectFunctorIsCalledOnceOnDestruction<ScopedTimers>(); + ExpectFunctorIsCalledOnceOnDestruction<ScopedThreadTimers>(); } -TEST(ScopedTimersTest, ScopedThreadTimerCallsFunctor) { - ExportFunctorForTests export_functor; - { - // Reference is needed to bypass functor copying. - SCOPED_THREAD_TIMER(reference(export_functor)); - EXPECT_EQ(0, export_functor.number_of_calls()); - } - const int expected_number_of_calls = base::ThreadTicks::IsSupported() ? 1 : 0; - EXPECT_EQ(expected_number_of_calls, export_functor.number_of_calls()); +TEST(ScopedTimersTest, CallsStoredLambdaFunctor) { + ExpectStoredLambdaIsInvokedOnceOnDestruction<ScopedTimers>(); + ExpectStoredLambdaIsInvokedOnceOnDestruction<ScopedThreadTimers>(); } -TEST(ScopedTimersTest, ScopedTimersCopyFunctor) { - ExportFunctorForTests export_functor; - { - SCOPED_TIMER(export_functor); - SCOPED_THREAD_TIMER(export_functor); - EXPECT_EQ(0, export_functor.number_of_calls()); - } - EXPECT_EQ(0, export_functor.number_of_calls()); +TEST(ScopedTimersTest, CallsInlineLambdaFunctor) { + ExpectInlineLambdaIsInvokedOnceOnDestruction<ScopedTimers>(); + ExpectInlineLambdaIsInvokedOnceOnDestruction<ScopedThreadTimers>(); } -TEST(ScopedTimersTest, ScopedThreadTimerCallsStoredLambdaFunctor) { - bool export_is_called = false; - auto export_functor = [&export_is_called](base::TimeDelta) { - EXPECT_FALSE(export_is_called); - export_is_called = true; - }; +TEST(ScopedTimersTest, StartIf) { + ExpectWellBehavedStartIf<ScopedTimers>(false); + ExpectWellBehavedStartIf<ScopedTimers>(true); - { - SCOPED_THREAD_TIMER(export_functor); - EXPECT_FALSE(export_is_called); - } - EXPECT_EQ(base::ThreadTicks::IsSupported(), export_is_called); + ExpectWellBehavedStartIf<ScopedThreadTimers>(false); + ExpectWellBehavedStartIf<ScopedThreadTimers>(true); } -TEST(ScopedTimersTest, ScopedTimerCallsStoredLambdaFunctor) { - bool export_is_called = false; - auto export_functor = [&export_is_called](base::TimeDelta) { - export_is_called = true; - }; - - { - SCOPED_TIMER(export_functor); - EXPECT_FALSE(export_is_called); - } - EXPECT_TRUE(export_is_called); +TEST(ScopedTimersTest, MoveConstructTimer) { + ExpectWellBehavedMoveContructor<ScopedTimers>(); + ExpectWellBehavedMoveContructor<ScopedThreadTimers>(); } +TEST(ScopedTimersTest, MoveAssignTimer) { + ExpectWellBehavedMoveAssignment<ScopedTimers>(); + ExpectWellBehavedMoveAssignment<ScopedThreadTimers>(); +} + +// Below are tests for macros in "time_measurements.h" ------------------------- +// TODO(pkalinnikov): Move these to a separate file? + TEST(ScopedTimersTest, ScopedUmaHistogramMacros) { base::HistogramTester tester; { @@ -99,11 +164,12 @@ tester.ExpectTotalCount("ScopedTimers.MicroTimer", 0); } - const int expected_count = base::ThreadTicks::IsSupported() ? 1 : 0; + int expected_count = ScopedTimers::IsSupported() ? 1 : 0; + tester.ExpectTotalCount("ScopedTimers.MicroTimer", expected_count); + + expected_count = ScopedThreadTimers::IsSupported() ? 1 : 0; tester.ExpectTotalCount("ScopedTimers.ThreadTimer", expected_count); tester.ExpectTotalCount("ScopedTimers.MicroThreadTimer", expected_count); - - tester.ExpectTotalCount("ScopedTimers.MicroTimer", 1); } TEST(ScopedTimersTest, UmaHistogramMicroTimesFromExportFunctor) { @@ -112,7 +178,7 @@ UMA_HISTOGRAM_MICRO_TIMES("ScopedTimers.MicroTimes", delta); }; { - SCOPED_TIMER(export_functor); + auto scoped_timer = ScopedTimers::Start(export_functor); tester.ExpectTotalCount("ScopedTimers.MicroTimes", 0); } tester.ExpectTotalCount("ScopedTimers.MicroTimes", 1);
diff --git a/components/subresource_filter/core/common/time_measurements.h b/components/subresource_filter/core/common/time_measurements.h new file mode 100644 index 0000000..e682ffce --- /dev/null +++ b/components/subresource_filter/core/common/time_measurements.h
@@ -0,0 +1,150 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file provides tools for measuring time intervals and reporting them to +// UMA histograms. +// WARNING: *UMA_HISTOGRAM_* macros in this file are not thread-safe. +// See also: "base/metrics/histogram_macros*.h". +// +// TODO(pkalinnikov): Consider moving content of this file to "base/metrics/*" +// after some refactoring. Note that most of the code generated by the macros +// below is not thread-safe. + +#ifndef COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_TIME_MEASUREMENTS_ +#define COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_TIME_MEASUREMENTS_ + +#include "base/metrics/histogram.h" +#include "base/time/time.h" +#include "components/subresource_filter/core/common/scoped_timers.h" + +namespace subresource_filter { + +// Creates a scoped object that measures its lifetime using base::ThreadTicks, +// and reports the result in milliseconds as a UMA statistic to a histogram with +// the provided |name| which is expected to be a runtime constant. The histogram +// collects times up to 10 seconds in 50 buckets. +// +// Under the hood there is a static base::HistogramBase* pointer initialized +// right before the scoped object. The pointer is used by a specific +// |export_functor| passed in to a SCOPED_THREAD_TIMER (see it above). +// +// Example: +// void Function() { +// SCOPED_UMA_HISTOGRAM_THREAD_TIMER("Component.FunctionTime"); +// ... Useful things happen here ... +// } +// +// WARNING: The generated code is not thread-safe. +#define SCOPED_UMA_HISTOGRAM_THREAD_TIMER(name) \ + IMPL_SCOPED_UMA_HISTOGRAM_TIMER_EXPANDER( \ + name, impl::ThreadTicksProvider, impl::ExportMillisecondsToHistogram, \ + 10 * 1000, __COUNTER__) + +// Similar to SCOPED_UMA_HISTOGRAM_THREAD_TIMER above, but the histogram +// collects times in microseconds, up to 1 second, and using 50 buckets. +// +// WARNING: The generated code is not thread-safe. +#define SCOPED_UMA_HISTOGRAM_MICRO_THREAD_TIMER(name) \ + IMPL_SCOPED_UMA_HISTOGRAM_TIMER_EXPANDER( \ + name, impl::ThreadTicksProvider, impl::ExportMicrosecondsToHistogram, \ + 1000 * 1000, __COUNTER__) + +// Similar to SCOPED_UMA_HISTOGRAM_TIMER in "base/metrics/histogram_macros.h", +// but the histogram stores times in microseconds, up to 1 second, in 50 +// buckets. +// +// WARNING: The generated code is not thread-safe. +#define SCOPED_UMA_HISTOGRAM_MICRO_TIMER(name) \ + IMPL_SCOPED_UMA_HISTOGRAM_TIMER_EXPANDER( \ + name, impl::TimeTicksProvider, impl::ExportMicrosecondsToHistogram, \ + 1000 * 1000, __COUNTER__) + +// Similar to UMA_HISTOGRAM_TIMES in "base/metrics/histogram_macros.h", but +// the histogram stores times in microseconds, up to 1 second, in 50 buckets. +// +// WARNING: The generated code is not thread-safe. +#define UMA_HISTOGRAM_MICRO_TIMES(name, sample) \ + UMA_HISTOGRAM_CUSTOM_MICRO_TIMES(name, sample, \ + base::TimeDelta::FromMicroseconds(1), \ + base::TimeDelta::FromSeconds(1), 50) + +// This can be used when the default ranges are not sufficient. This macro lets +// the metric developer customize the min and max of the sampled range, as well +// as the number of buckets recorded. +#define UMA_HISTOGRAM_CUSTOM_MICRO_TIMES(name, sample, min, max, bucket_count) \ + IMPL_UMA_HISTOGRAM_ADD(name, sample.InMicroseconds(), min.InMicroseconds(), \ + max.InMicroseconds(), bucket_count) + +// ----------------------------------------------------------------------------- +// Below are helpers used by other macros. Shouldn't be used directly. --------- + +// This is necessary to expand __COUNTER__ to an actual value. +#define IMPL_SCOPED_UMA_HISTOGRAM_TIMER_EXPANDER( \ + name, time_provider, histogram_exporter, max_value, suffix) \ + IMPL_SCOPED_UMA_HISTOGRAM_TIMER_UNIQUE( \ + name, time_provider, histogram_exporter, max_value, suffix) + +// Creates a static histogram pointer and a scoped object referring to it +// throught the |histogram_exporter| functor. Both the pointer and the scoped +// object are uniquely-named, using the unique |suffix| passed in. +#define IMPL_SCOPED_UMA_HISTOGRAM_TIMER_UNIQUE( \ + name, time_provider, histogram_exporter, max_value, suffix) \ + IMPL_DEFINE_STATIC_UMA_HISTOGRAM_POINTER(name, 1, max_value, 50, suffix) \ + auto scoped_uma_histogram_timer_##suffix = \ + impl::ScopedTimerImplFactory<time_provider>::Start( \ + histogram_exporter(histogram_##suffix)); + +// This is necessary to expand __COUNTER__ to an actual value. +#define IMPL_UMA_HISTOGRAM_MICRO_TIMES_EXPANDER(name, max_value, suffix, \ + sample) \ + IMPL_UMA_HISTOGRAM_MICRO_TIMES_UNIQUE(name, max_value, suffix, sample) + +// Defines a static UMA histogram pointer and writes a |sample| to it. +#define IMPL_UMA_HISTOGRAM_ADD(name, sample, min, max, bucket_count) \ + do { \ + IMPL_DEFINE_STATIC_UMA_HISTOGRAM_POINTER(name, min, max, bucket_count, 0) \ + histogram_0->Add(sample); \ + } while (0) + +// Defines a static pointer to a UMA histogram. +// +// WARNING: Static local variable initialization is deliberately *not* +// thread-safe in Chrome builds. See the "-fno-threadsafe-statics" flag in +// "build/config/compiler/BUILD.gn" and "/Zc:threadSafeInit-" in +// "build/config/win/BUILD.gn" for details. +#define IMPL_DEFINE_STATIC_UMA_HISTOGRAM_POINTER(name, min, max, bucket_count, \ + suffix) \ + static base::HistogramBase* histogram_##suffix = \ + base::Histogram::FactoryGet( \ + name, min, max, bucket_count, \ + base::HistogramBase::kUmaTargetedHistogramFlag); + +namespace impl { + +// ExportFunctor implementation that puts measurements into a UMA |histogram|. +template <bool is_microsec_precision> +class ExportTimeDeltaToHistogram { + public: + ExportTimeDeltaToHistogram(base::HistogramBase* histogram) + : histogram_(histogram) {} + + void operator()(base::TimeDelta duration) { + if (is_microsec_precision) + histogram_->Add(duration.InMicroseconds()); + else + histogram_->Add(duration.InMilliseconds()); + } + + private: + base::HistogramBase* histogram_; +}; + +using ExportMillisecondsToHistogram = ExportTimeDeltaToHistogram<false>; +using ExportMicrosecondsToHistogram = ExportTimeDeltaToHistogram<true>; + +} // namespace impl + +} // namespace subresource_filter + +#endif // COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_TIME_MEASUREMENTS_
diff --git a/content/app/content_main_runner.cc b/content/app/content_main_runner.cc index e1504f7..929756b 100644 --- a/content/app/content_main_runner.cc +++ b/content/app/content_main_runner.cc
@@ -155,9 +155,9 @@ #endif std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList); - feature_list->InitializeFromCommandLine( - command_line.GetSwitchValueASCII(switches::kEnableFeatures), - command_line.GetSwitchValueASCII(switches::kDisableFeatures)); + base::FieldTrialList::CreateFeaturesFromCommandLine( + command_line, switches::kEnableFeatures, switches::kDisableFeatures, + feature_list.get()); base::FeatureList::SetInstance(std::move(feature_list)); }
diff --git a/content/browser/browser_child_process_host_impl.cc b/content/browser/browser_child_process_host_impl.cc index c786b11..d311660a 100644 --- a/content/browser/browser_child_process_host_impl.cc +++ b/content/browser/browser_child_process_host_impl.cc
@@ -219,19 +219,11 @@ // static void BrowserChildProcessHostImpl::CopyFeatureAndFieldTrialFlags( base::CommandLine* cmd_line) { - std::string enabled_features; - std::string disabled_features; - base::FeatureList::GetInstance()->GetFeatureOverrides(&enabled_features, - &disabled_features); - if (!enabled_features.empty()) - cmd_line->AppendSwitchASCII(switches::kEnableFeatures, enabled_features); - if (!disabled_features.empty()) - cmd_line->AppendSwitchASCII(switches::kDisableFeatures, disabled_features); - // If we run base::FieldTrials, we want to pass to their state to the // child process so that it can act in accordance with each state. - base::FieldTrialList::CopyFieldTrialStateToFlags(switches::kFieldTrialHandle, - cmd_line); + base::FieldTrialList::CopyFieldTrialStateToFlags( + switches::kFieldTrialHandle, switches::kEnableFeatures, + switches::kDisableFeatures, cmd_line); } void BrowserChildProcessHostImpl::Launch(
diff --git a/content/browser/gpu/gpu_internals_ui.cc b/content/browser/gpu/gpu_internals_ui.cc index e5db5003..17d924e5 100644 --- a/content/browser/gpu/gpu_internals_ui.cc +++ b/content/browser/gpu/gpu_internals_ui.cc
@@ -128,6 +128,9 @@ basic_info->Append(NewDescriptionValuePair( "In-process GPU", new base::FundamentalValue(gpu_info.in_process_gpu))); basic_info->Append(NewDescriptionValuePair( + "Passthrough Command Decoder", + new base::FundamentalValue(gpu_info.passthrough_cmd_decoder))); + basic_info->Append(NewDescriptionValuePair( "Sandboxed", new base::FundamentalValue(gpu_info.sandboxed))); basic_info->Append(NewDescriptionValuePair( "GPU0", GPUDeviceToString(gpu_info.gpu)));
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc index 216d953..179b773 100644 --- a/content/browser/gpu/gpu_process_host.cc +++ b/content/browser/gpu/gpu_process_host.cc
@@ -162,7 +162,8 @@ switches::kGpuTestingGLVendor, switches::kGpuTestingGLRenderer, switches::kGpuTestingGLVersion, - switches::kDisableGpuDriverBugWorkarounds}; + switches::kDisableGpuDriverBugWorkarounds, + switches::kUsePassthroughCmdDecoder}; enum GPUProcessLifetimeEvent { LAUNCHED,
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc index da25e25..c65b5cb 100644 --- a/content/browser/renderer_host/render_view_host_impl.cc +++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -462,6 +462,9 @@ #if defined(OS_ANDROID) prefs.device_supports_mouse = false; + + prefs.video_fullscreen_orientation_lock_enabled = + base::FeatureList::IsEnabled(media::kVideoFullscreenOrientationLock); #endif prefs.pointer_events_max_touch_points = ui::MaxTouchPoints();
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc index 286c6276..29adfca 100644 --- a/content/child/runtime_features.cc +++ b/content/child/runtime_features.cc
@@ -42,6 +42,8 @@ // Android does not yet support switching of audio output devices WebRuntimeFeatures::enableAudioOutputDevices(false); WebRuntimeFeatures::enableAutoplayMutedVideos(true); + // Android does not yet support SystemMonitor. + WebRuntimeFeatures::enableOnDeviceChange(false); #else WebRuntimeFeatures::enableNavigatorContentUtils(true); #endif // defined(OS_ANDROID)
diff --git a/content/public/common/web_preferences.cc b/content/public/common/web_preferences.cc index 64eafb6..6a888d2 100644 --- a/content/public/common/web_preferences.cc +++ b/content/public/common/web_preferences.cc
@@ -208,6 +208,7 @@ resue_global_for_unowned_main_frame(false), progress_bar_completion(ProgressBarCompletion::LOAD_EVENT), spellcheck_enabled_by_default(true), + video_fullscreen_orientation_lock_enabled(false), #endif #if defined(OS_ANDROID) default_minimum_page_scale_factor(0.25f),
diff --git a/content/public/common/web_preferences.h b/content/public/common/web_preferences.h index d7e3f80..e6ad3dcf 100644 --- a/content/public/common/web_preferences.h +++ b/content/public/common/web_preferences.h
@@ -247,6 +247,8 @@ // Specifies default setting for spellcheck when the spellcheck attribute is // not explicitly specified. bool spellcheck_enabled_by_default; + // If enabled, when a video goes fullscreen, the orientation should be locked. + bool video_fullscreen_orientation_lock_enabled; #endif // Default (used if the page or UA doesn't override these) values for page
diff --git a/content/renderer/media/media_stream_audio_processor_options.cc b/content/renderer/media/media_stream_audio_processor_options.cc index 7c1c929d..73e2b51 100644 --- a/content/renderer/media/media_stream_audio_processor_options.cc +++ b/content/renderer/media/media_stream_audio_processor_options.cc
@@ -134,32 +134,8 @@ return the_default; } -void SetIfNotSet(rtc::Optional<bool>* field, bool value) { - if (!*field) { - *field = rtc::Optional<bool>(value); - } -} - } // namespace -// TODO(xians): Remove this method after the APM in WebRtc is deprecated. -void MediaAudioConstraints::ApplyFixedAudioConstraints( - cricket::AudioOptions* options) { - SetIfNotSet(&options->echo_cancellation, true); -#if defined(OS_ANDROID) - SetIfNotSet(&options->extended_filter_aec, false); -#else - // Enable the extended filter mode AEC on all non-mobile platforms. - SetIfNotSet(&options->extended_filter_aec, true); -#endif - SetIfNotSet(&options->auto_gain_control, true); - SetIfNotSet(&options->experimental_agc, true); - SetIfNotSet(&options->noise_suppression, true); - SetIfNotSet(&options->highpass_filter, true); - SetIfNotSet(&options->typing_detection, true); - SetIfNotSet(&options->experimental_ns, true); -} - MediaAudioConstraints::MediaAudioConstraints( const blink::WebMediaConstraints& constraints, int effects) : constraints_(constraints),
diff --git a/content/renderer/media/media_stream_audio_processor_options.h b/content/renderer/media/media_stream_audio_processor_options.h index cb7eb797..a7fe921 100644 --- a/content/renderer/media/media_stream_audio_processor_options.h +++ b/content/renderer/media/media_stream_audio_processor_options.h
@@ -52,7 +52,6 @@ // be added. // TODO(hta): Switch to an interface without "cricket::" when webrtc has one. - static void ApplyFixedAudioConstraints(cricket::AudioOptions* options); // |effects| is the bitmasks telling whether certain platform // hardware audio effects are enabled, like hardware echo cancellation. If
diff --git a/content/renderer/media/mock_media_stream_dispatcher.cc b/content/renderer/media/mock_media_stream_dispatcher.cc index 77bea1f..db27d90 100644 --- a/content/renderer/media/mock_media_stream_dispatcher.cc +++ b/content/renderer/media/mock_media_stream_dispatcher.cc
@@ -40,10 +40,10 @@ video_array_.clear(); if (controls.audio.requested) { - AddAudioInputDeviceToArray(false); + AddAudioInputDeviceToArray(false, controls.audio.device_id); } if (controls.video.requested) { - AddVideoDeviceToArray(true); + AddVideoDeviceToArray(true, controls.video.device_id); } ++request_stream_counter_; } @@ -82,9 +82,10 @@ } void MockMediaStreamDispatcher::AddAudioInputDeviceToArray( - bool matched_output) { + bool matched_output, + const std::string& device_id) { StreamDeviceInfo audio; - audio.device.id = test_same_id_ ? "test_id" : "audio_input_device_id"; + audio.device.id = test_same_id_ ? "test_id" : device_id; audio.device.id = audio.device.id + base::IntToString(session_id_); audio.device.name = "microphone"; audio.device.type = MEDIA_DEVICE_AUDIO_CAPTURE; @@ -100,9 +101,11 @@ audio_input_array_.push_back(audio); } -void MockMediaStreamDispatcher::AddVideoDeviceToArray(bool facing_user) { +void MockMediaStreamDispatcher::AddVideoDeviceToArray( + bool facing_user, + const std::string& device_id) { StreamDeviceInfo video; - video.device.id = test_same_id_ ? "test_id" : "video_device_id"; + video.device.id = test_same_id_ ? "test_id" : device_id; video.device.id = video.device.id + base::IntToString(session_id_); video.device.name = "usb video camera"; video.device.type = MEDIA_DEVICE_VIDEO_CAPTURE;
diff --git a/content/renderer/media/mock_media_stream_dispatcher.h b/content/renderer/media/mock_media_stream_dispatcher.h index d23f551..6550031 100644 --- a/content/renderer/media/mock_media_stream_dispatcher.h +++ b/content/renderer/media/mock_media_stream_dispatcher.h
@@ -48,8 +48,9 @@ const StreamDeviceInfoArray& video_array() const { return video_array_; } private: - void AddAudioInputDeviceToArray(bool matched_output); - void AddVideoDeviceToArray(bool facing_user); + void AddAudioInputDeviceToArray(bool matched_output, + const std::string& device_id); + void AddVideoDeviceToArray(bool facing_user, const std::string& device_id); int audio_input_request_id_; base::WeakPtr<MediaStreamDispatcherEventHandler> event_handler_;
diff --git a/content/renderer/media/user_media_client_impl.cc b/content/renderer/media/user_media_client_impl.cc index 2381c46..b7cccf7 100644 --- a/content/renderer/media/user_media_client_impl.cc +++ b/content/renderer/media/user_media_client_impl.cc
@@ -240,6 +240,13 @@ // webGetUserMedia. UpdateWebRTCMethodCount(WEBKIT_GET_USER_MEDIA); DCHECK(CalledOnValidThread()); + DCHECK(!user_media_request.isNull()); + // ownerDocument may be null if we are in a test. + // In that case, it's OK to not check frame(). + DCHECK(user_media_request.ownerDocument().isNull() || + render_frame()->GetWebFrame() == + static_cast<blink::WebFrame*>( + user_media_request.ownerDocument().frame())); if (RenderThreadImpl::current()) { RenderThreadImpl::current()->peer_connection_tracker()->TrackGetUserMedia( @@ -249,61 +256,41 @@ int request_id = g_next_request_id++; std::unique_ptr<StreamControls> controls = base::MakeUnique<StreamControls>(); - // |user_media_request| can't be mocked. So in order to test at all we check - // if it isNull. - // TODO(guidou): Remove this test-specific code path. - if (user_media_request.isNull()) { - // We are in a test. - controls->audio.requested = true; - controls->video.requested = true; + bool enable_automatic_output_device_selection = false; + bool request_audio_input_devices = false; + if (user_media_request.audio()) { + CopyConstraintsToTrackControls(user_media_request.audioConstraints(), + &controls->audio, + &request_audio_input_devices); + CopyHotwordAndLocalEchoToStreamControls( + user_media_request.audioConstraints(), controls.get()); + // Check if this input device should be used to select a matching output + // device for audio rendering. + GetConstraintValueAsBoolean( + user_media_request.audioConstraints(), + &blink::WebMediaTrackConstraintSet::renderToAssociatedSink, + &enable_automatic_output_device_selection); + } + bool request_video_input_devices = false; + if (user_media_request.video()) { + CopyConstraintsToTrackControls(user_media_request.videoConstraints(), + &controls->video, + &request_video_input_devices); + } + + url::Origin security_origin = user_media_request.getSecurityOrigin(); + if (request_audio_input_devices || request_video_input_devices) { + GetMediaDevicesDispatcher()->EnumerateDevices( + request_audio_input_devices, request_video_input_devices, + false /* request_audio_output_devices */, security_origin, + base::Bind(&UserMediaClientImpl::SelectUserMediaDevice, + weak_factory_.GetWeakPtr(), request_id, user_media_request, + base::Passed(&controls), + enable_automatic_output_device_selection, security_origin)); + } else { FinalizeRequestUserMedia( request_id, user_media_request, std::move(controls), - false /* automatic_output_device_selection */, url::Origin()); - } else { - // ownerDocument may be null if we are in a test. - // In that case, it's OK to not check frame(). - DCHECK(user_media_request.ownerDocument().isNull() || - render_frame()->GetWebFrame() == - static_cast<blink::WebFrame*>( - user_media_request.ownerDocument().frame())); - - bool enable_automatic_output_device_selection = false; - bool request_audio_input_devices = false; - if (user_media_request.audio()) { - CopyConstraintsToTrackControls(user_media_request.audioConstraints(), - &controls->audio, - &request_audio_input_devices); - CopyHotwordAndLocalEchoToStreamControls( - user_media_request.audioConstraints(), controls.get()); - // Check if this input device should be used to select a matching output - // device for audio rendering. - GetConstraintValueAsBoolean( - user_media_request.audioConstraints(), - &blink::WebMediaTrackConstraintSet::renderToAssociatedSink, - &enable_automatic_output_device_selection); - } - bool request_video_input_devices = false; - if (user_media_request.video()) { - CopyConstraintsToTrackControls(user_media_request.videoConstraints(), - &controls->video, - &request_video_input_devices); - } - - url::Origin security_origin = user_media_request.getSecurityOrigin(); - if (request_audio_input_devices || request_video_input_devices) { - GetMediaDevicesDispatcher()->EnumerateDevices( - request_audio_input_devices, request_video_input_devices, - false /* request_audio_output_devices */, security_origin, - base::Bind(&UserMediaClientImpl::SelectUserMediaDevice, - weak_factory_.GetWeakPtr(), request_id, user_media_request, - base::Passed(&controls), - enable_automatic_output_device_selection, - security_origin)); - } else { - FinalizeRequestUserMedia( - request_id, user_media_request, std::move(controls), - enable_automatic_output_device_selection, security_origin); - } + enable_automatic_output_device_selection, security_origin); } } @@ -445,29 +432,16 @@ } request_info->generated = true; - // WebUserMediaRequest don't have an implementation in unit tests. - // Therefore we need to check for isNull here and initialize the - // constraints. - blink::WebUserMediaRequest* request = &(request_info->request); - blink::WebMediaConstraints audio_constraints; - blink::WebMediaConstraints video_constraints; - if (request->isNull()) { - audio_constraints.initialize(); - video_constraints.initialize(); - } else { - audio_constraints = request->audioConstraints(); - video_constraints = request->videoConstraints(); - } - + DCHECK(!request_info->request.isNull()); blink::WebVector<blink::WebMediaStreamTrack> audio_track_vector( audio_array.size()); - CreateAudioTracks(audio_array, audio_constraints, &audio_track_vector, - request_info); + CreateAudioTracks(audio_array, request_info->request.audioConstraints(), + &audio_track_vector, request_info); blink::WebVector<blink::WebMediaStreamTrack> video_track_vector( video_array.size()); - CreateVideoTracks(video_array, video_constraints, &video_track_vector, - request_info); + CreateVideoTracks(video_array, request_info->request.videoConstraints(), + &video_track_vector, request_info); blink::WebString webkit_id = base::UTF8ToUTF16(label); blink::WebMediaStream* web_stream = &(request_info->web_stream);
diff --git a/content/renderer/media/user_media_client_impl_unittest.cc b/content/renderer/media/user_media_client_impl_unittest.cc index 437f3c2c..41f634f5 100644 --- a/content/renderer/media/user_media_client_impl_unittest.cc +++ b/content/renderer/media/user_media_client_impl_unittest.cc
@@ -36,6 +36,42 @@ namespace content { +blink::WebMediaConstraints CreateDefaultConstraints() { + MockConstraintFactory factory; + factory.AddAdvanced(); + return factory.CreateWebMediaConstraints(); +} + +blink::WebMediaConstraints CreateDeviceConstraints( + const char* basic_exact_value, + const char* basic_ideal_value = nullptr, + const char* advanced_exact_value = nullptr, + const char* advanced_ideal_value = nullptr) { + MockConstraintFactory factory; + blink::WebMediaTrackConstraintSet basic; + if (basic_exact_value) { + factory.basic().deviceId.setExact( + blink::WebString::fromUTF8(basic_exact_value)); + } + if (basic_ideal_value) { + blink::WebString value = blink::WebString::fromUTF8(basic_ideal_value); + factory.basic().deviceId.setIdeal( + blink::WebVector<blink::WebString>(&value, 1)); + } + + auto& advanced = factory.AddAdvanced(); + if (advanced_exact_value) { + blink::WebString value = blink::WebString::fromUTF8(advanced_exact_value); + advanced.deviceId.setExact(value); + } + if (advanced_ideal_value) { + blink::WebString value = blink::WebString::fromUTF8(advanced_ideal_value); + advanced.deviceId.setIdeal(blink::WebVector<blink::WebString>(&value, 1)); + } + + return factory.CreateWebMediaConstraints(); +} + class MockMediaStreamVideoCapturerSource : public MockMediaStreamVideoSource { public: MockMediaStreamVideoCapturerSource( @@ -48,6 +84,13 @@ } }; +const char kInvalidDeviceId[] = "invalid"; +const char kFakeAudioInputDeviceId1[] = "fake_audio_input 1"; +const char kFakeAudioInputDeviceId2[] = "fake_audio_input 2"; +const char kFakeVideoInputDeviceId1[] = "fake_video_input 1"; +const char kFakeVideoInputDeviceId2[] = "fake_video_input 2"; +const char kFakeAudioOutputDeviceId1[] = "fake_audio_output 1"; + class MockMediaDevicesDispatcherHost : public ::mojom::MediaDevicesDispatcherHost { public: @@ -60,19 +103,19 @@ std::vector<std::vector<MediaDeviceInfo>> result(NUM_MEDIA_DEVICE_TYPES); if (request_audio_input) { result[MEDIA_DEVICE_TYPE_AUDIO_INPUT].push_back(MediaDeviceInfo( - "fake_audio_input 1", "Fake Audio Input 1", "fake_group 1")); + kFakeAudioInputDeviceId1, "Fake Audio Input 1", "fake_group 1")); result[MEDIA_DEVICE_TYPE_AUDIO_INPUT].push_back(MediaDeviceInfo( - "fake_audio_input 2", "Fake Audio Input 2", "fake_group 2")); + kFakeAudioInputDeviceId2, "Fake Audio Input 2", "fake_group 2")); } if (request_video_input) { result[MEDIA_DEVICE_TYPE_VIDEO_INPUT].push_back( - MediaDeviceInfo("fake_video_input 1", "Fake Video Input 1", "")); + MediaDeviceInfo(kFakeVideoInputDeviceId1, "Fake Video Input 1", "")); result[MEDIA_DEVICE_TYPE_VIDEO_INPUT].push_back( - MediaDeviceInfo("fake_video_input 2", "Fake Video Input 2", "")); + MediaDeviceInfo(kFakeVideoInputDeviceId2, "Fake Video Input 2", "")); } if (request_audio_output) { result[MEDIA_DEVICE_TYPE_AUDIO_OUTPUT].push_back(MediaDeviceInfo( - "fake_audio_output 1", "Fake Audio Input 1", "fake_group 1")); + kFakeAudioOutputDeviceId1, "Fake Audio Input 1", "fake_group 1")); } callback.Run(result); } @@ -114,7 +157,9 @@ } void RequestUserMedia() { - blink::WebUserMediaRequest user_media_request; + blink::WebUserMediaRequest user_media_request = + blink::WebUserMediaRequest::createForTesting( + CreateDefaultConstraints(), CreateDefaultConstraints()); RequestUserMedia(user_media_request); } @@ -246,10 +291,10 @@ child_process_.reset(new ChildProcess()); dependency_factory_.reset(new MockPeerConnectionDependencyFactory()); ms_dispatcher_ = new MockMediaStreamDispatcher(); - used_media_impl_.reset(new UserMediaClientImplUnderTest( + user_media_client_impl_.reset(new UserMediaClientImplUnderTest( dependency_factory_.get(), std::unique_ptr<MediaStreamDispatcher>(ms_dispatcher_))); - used_media_impl_->SetMediaDevicesDispatcherForTesting( + user_media_client_impl_->SetMediaDevicesDispatcherForTesting( binding_user_media.CreateInterfacePtrAndBind()); base::WeakPtr<MediaDevicesEventDispatcher> event_dispatcher = MediaDevicesEventDispatcher::GetForRenderFrame(nullptr); @@ -259,23 +304,24 @@ void TearDown() override { MediaDevicesEventDispatcher::GetForRenderFrame(nullptr)->OnDestruct(); - used_media_impl_.reset(); + user_media_client_impl_.reset(); blink::WebHeap::collectAllGarbageForTesting(); } void LoadNewDocumentInFrame() { - used_media_impl_->WillCommitProvisionalLoad(); + user_media_client_impl_->WillCommitProvisionalLoad(); } blink::WebMediaStream RequestLocalMediaStream() { - used_media_impl_->RequestUserMedia(); + user_media_client_impl_->RequestUserMedia(); FakeMediaStreamDispatcherRequestUserMediaComplete(); StartMockedVideoSource(); EXPECT_EQ(UserMediaClientImplUnderTest::REQUEST_SUCCEEDED, - used_media_impl_->request_state()); + user_media_client_impl_->request_state()); - blink::WebMediaStream desc = used_media_impl_->last_generated_stream(); + blink::WebMediaStream desc = + user_media_client_impl_->last_generated_stream(); content::MediaStream* native_stream = content::MediaStream::GetMediaStream(desc); if (!native_stream) { @@ -296,23 +342,22 @@ void FakeMediaStreamDispatcherRequestUserMediaComplete() { // Audio request ID is used as the shared request ID. - used_media_impl_->OnStreamGenerated( + user_media_client_impl_->OnStreamGenerated( ms_dispatcher_->audio_input_request_id(), - ms_dispatcher_->stream_label(), - ms_dispatcher_->audio_input_array(), + ms_dispatcher_->stream_label(), ms_dispatcher_->audio_input_array(), ms_dispatcher_->video_array()); } void StartMockedVideoSource() { MockMediaStreamVideoCapturerSource* video_source = - used_media_impl_->last_created_video_source(); + user_media_client_impl_->last_created_video_source(); if (video_source->SourceHasAttemptedToStart()) video_source->StartMockedSource(); } void FailToStartMockedVideoSource() { MockMediaStreamVideoCapturerSource* video_source = - used_media_impl_->last_created_video_source(); + user_media_client_impl_->last_created_video_source(); if (video_source->SourceHasAttemptedToStart()) video_source->FailToStartMockedSource(); blink::WebHeap::collectGarbageForTesting(); @@ -324,13 +369,41 @@ blink::WebUserMediaRequest request = blink::WebUserMediaRequest::createForTesting(audio_constraints, null_constraints); - used_media_impl_->RequestUserMedia(request); - bool result = used_media_impl_->UserMediaRequestHasAutomaticDeviceSelection( + user_media_client_impl_->RequestUserMedia(request); + bool result = + user_media_client_impl_->UserMediaRequestHasAutomaticDeviceSelection( + ms_dispatcher_->audio_input_request_id()); + user_media_client_impl_->DeleteRequest( ms_dispatcher_->audio_input_request_id()); - used_media_impl_->DeleteRequest(ms_dispatcher_->audio_input_request_id()); return result; } + void TestValidRequestWithDeviceConstraints( + const blink::WebMediaConstraints& audio_constraints, + const blink::WebMediaConstraints& video_constraints, + const std::string& expected_audio_device_id, + const std::string& expected_video_device_id) { + DCHECK(!audio_constraints.isNull()); + DCHECK(!video_constraints.isNull()); + blink::WebUserMediaRequest request = + blink::WebUserMediaRequest::createForTesting(audio_constraints, + video_constraints); + user_media_client_impl_->RequestUserMedia(request); + FakeMediaStreamDispatcherRequestUserMediaComplete(); + StartMockedVideoSource(); + + EXPECT_EQ(UserMediaClientImplUnderTest::REQUEST_SUCCEEDED, + user_media_client_impl_->request_state()); + EXPECT_EQ(1U, ms_dispatcher_->audio_input_array().size()); + EXPECT_EQ(1U, ms_dispatcher_->video_array().size()); + // MockMediaStreamDispatcher appends the session ID to its internal device + // IDs. + EXPECT_EQ(std::string(expected_audio_device_id) + "0", + ms_dispatcher_->audio_input_array()[0].device.id); + EXPECT_EQ(std::string(expected_video_device_id) + "0", + ms_dispatcher_->video_array()[0].device.id); + } + protected: base::MessageLoop message_loop_; std::unique_ptr<ChildProcess> child_process_; @@ -339,7 +412,7 @@ mojo::Binding<::mojom::MediaDevicesDispatcherHost> binding_user_media; mojo::Binding<::mojom::MediaDevicesDispatcherHost> binding_event_dispatcher_; - std::unique_ptr<UserMediaClientImplUnderTest> used_media_impl_; + std::unique_ptr<UserMediaClientImplUnderTest> user_media_client_impl_; std::unique_ptr<MockPeerConnectionDependencyFactory> dependency_factory_; }; @@ -461,7 +534,7 @@ RequestLocalMediaStream(); // Makes sure the test itself don't hold a reference to the created // MediaStream. - used_media_impl_->ClearLastGeneratedStream(); + user_media_client_impl_->ClearLastGeneratedStream(); blink::WebHeap::collectAllGarbageForTesting(); // Expect the sources to be stopped when the MediaStream goes out of scope. @@ -483,13 +556,13 @@ // This test what happens if a video source to a MediaSteam fails to start. TEST_F(UserMediaClientImplTest, MediaVideoSourceFailToStart) { - used_media_impl_->RequestUserMedia(); + user_media_client_impl_->RequestUserMedia(); FakeMediaStreamDispatcherRequestUserMediaComplete(); FailToStartMockedVideoSource(); EXPECT_EQ(UserMediaClientImplUnderTest::REQUEST_FAILED, - used_media_impl_->request_state()); + user_media_client_impl_->request_state()); EXPECT_EQ(MEDIA_DEVICE_TRACK_START_FAILURE, - used_media_impl_->error_reason()); + user_media_client_impl_->error_reason()); blink::WebHeap::collectAllGarbageForTesting(); EXPECT_EQ(1, ms_dispatcher_->request_stream_counter()); EXPECT_EQ(1, ms_dispatcher_->stop_audio_device_counter()); @@ -498,14 +571,14 @@ // This test what happens if an audio source fail to initialize. TEST_F(UserMediaClientImplTest, MediaAudioSourceFailToInitialize) { - used_media_impl_->SetCreateSourceThatFails(true); - used_media_impl_->RequestUserMedia(); + user_media_client_impl_->SetCreateSourceThatFails(true); + user_media_client_impl_->RequestUserMedia(); FakeMediaStreamDispatcherRequestUserMediaComplete(); StartMockedVideoSource(); EXPECT_EQ(UserMediaClientImplUnderTest::REQUEST_FAILED, - used_media_impl_->request_state()); + user_media_client_impl_->request_state()); EXPECT_EQ(MEDIA_DEVICE_TRACK_START_FAILURE, - used_media_impl_->error_reason()); + user_media_client_impl_->error_reason()); blink::WebHeap::collectAllGarbageForTesting(); EXPECT_EQ(1, ms_dispatcher_->request_stream_counter()); EXPECT_EQ(1, ms_dispatcher_->stop_audio_device_counter()); @@ -515,37 +588,37 @@ // This test what happens if UserMediaClientImpl is deleted before a source has // started. TEST_F(UserMediaClientImplTest, MediaStreamImplShutDown) { - used_media_impl_->RequestUserMedia(); + user_media_client_impl_->RequestUserMedia(); FakeMediaStreamDispatcherRequestUserMediaComplete(); EXPECT_EQ(1, ms_dispatcher_->request_stream_counter()); EXPECT_EQ(UserMediaClientImplUnderTest::REQUEST_NOT_COMPLETE, - used_media_impl_->request_state()); - used_media_impl_.reset(); + user_media_client_impl_->request_state()); + user_media_client_impl_.reset(); } // This test what happens if a new document is loaded in the frame while the // MediaStream is being generated by the MediaStreamDispatcher. TEST_F(UserMediaClientImplTest, ReloadFrameWhileGeneratingStream) { - used_media_impl_->RequestUserMedia(); + user_media_client_impl_->RequestUserMedia(); LoadNewDocumentInFrame(); EXPECT_EQ(1, ms_dispatcher_->request_stream_counter()); EXPECT_EQ(0, ms_dispatcher_->stop_audio_device_counter()); EXPECT_EQ(0, ms_dispatcher_->stop_video_device_counter()); EXPECT_EQ(UserMediaClientImplUnderTest::REQUEST_NOT_COMPLETE, - used_media_impl_->request_state()); + user_media_client_impl_->request_state()); } // This test what happens if a newdocument is loaded in the frame while the // sources are being started. TEST_F(UserMediaClientImplTest, ReloadFrameWhileGeneratingSources) { - used_media_impl_->RequestUserMedia(); + user_media_client_impl_->RequestUserMedia(); FakeMediaStreamDispatcherRequestUserMediaComplete(); EXPECT_EQ(1, ms_dispatcher_->request_stream_counter()); LoadNewDocumentInFrame(); EXPECT_EQ(1, ms_dispatcher_->stop_audio_device_counter()); EXPECT_EQ(1, ms_dispatcher_->stop_video_device_counter()); EXPECT_EQ(UserMediaClientImplUnderTest::REQUEST_NOT_COMPLETE, - used_media_impl_->request_state()); + user_media_client_impl_->request_state()); } // This test what happens if stop is called on a track after the frame has @@ -572,16 +645,17 @@ } TEST_F(UserMediaClientImplTest, EnumerateMediaDevices) { - used_media_impl_->RequestMediaDevices(); + user_media_client_impl_->RequestMediaDevices(); base::RunLoop().RunUntilIdle(); EXPECT_EQ(UserMediaClientImplUnderTest::REQUEST_SUCCEEDED, - used_media_impl_->request_state()); - EXPECT_EQ(static_cast<size_t>(5), used_media_impl_->last_devices().size()); + user_media_client_impl_->request_state()); + EXPECT_EQ(static_cast<size_t>(5), + user_media_client_impl_->last_devices().size()); // Audio input device with matched output ID. const blink::WebMediaDeviceInfo* device = - &used_media_impl_->last_devices()[0]; + &user_media_client_impl_->last_devices()[0]; EXPECT_FALSE(device->deviceId().isEmpty()); EXPECT_EQ(blink::WebMediaDeviceInfo::MediaDeviceKindAudioInput, device->kind()); @@ -589,7 +663,7 @@ EXPECT_FALSE(device->groupId().isEmpty()); // Audio input device without matched output ID. - device = &used_media_impl_->last_devices()[1]; + device = &user_media_client_impl_->last_devices()[1]; EXPECT_FALSE(device->deviceId().isEmpty()); EXPECT_EQ(blink::WebMediaDeviceInfo::MediaDeviceKindAudioInput, device->kind()); @@ -597,14 +671,14 @@ EXPECT_FALSE(device->groupId().isEmpty()); // Video input devices. - device = &used_media_impl_->last_devices()[2]; + device = &user_media_client_impl_->last_devices()[2]; EXPECT_FALSE(device->deviceId().isEmpty()); EXPECT_EQ(blink::WebMediaDeviceInfo::MediaDeviceKindVideoInput, device->kind()); EXPECT_FALSE(device->label().isEmpty()); EXPECT_TRUE(device->groupId().isEmpty()); - device = &used_media_impl_->last_devices()[3]; + device = &user_media_client_impl_->last_devices()[3]; EXPECT_FALSE(device->deviceId().isEmpty()); EXPECT_EQ(blink::WebMediaDeviceInfo::MediaDeviceKindVideoInput, device->kind()); @@ -612,7 +686,7 @@ EXPECT_TRUE(device->groupId().isEmpty()); // Audio output device. - device = &used_media_impl_->last_devices()[4]; + device = &user_media_client_impl_->last_devices()[4]; EXPECT_FALSE(device->deviceId().isEmpty()); EXPECT_EQ(blink::WebMediaDeviceInfo::MediaDeviceKindAudioOutput, device->kind()); @@ -620,18 +694,20 @@ EXPECT_FALSE(device->groupId().isEmpty()); // Verfify group IDs. - EXPECT_TRUE(used_media_impl_->last_devices()[0].groupId().equals( - used_media_impl_->last_devices()[4].groupId())); - EXPECT_FALSE(used_media_impl_->last_devices()[1].groupId().equals( - used_media_impl_->last_devices()[4].groupId())); + EXPECT_TRUE(user_media_client_impl_->last_devices()[0].groupId().equals( + user_media_client_impl_->last_devices()[4].groupId())); + EXPECT_FALSE(user_media_client_impl_->last_devices()[1].groupId().equals( + user_media_client_impl_->last_devices()[4].groupId())); } TEST_F(UserMediaClientImplTest, RenderToAssociatedSinkConstraint) { // For a null UserMediaRequest (no audio requested), we expect false. - used_media_impl_->RequestUserMedia(); - EXPECT_FALSE(used_media_impl_->UserMediaRequestHasAutomaticDeviceSelection( - ms_dispatcher_->audio_input_request_id())); - used_media_impl_->DeleteRequest(ms_dispatcher_->audio_input_request_id()); + user_media_client_impl_->RequestUserMedia(); + EXPECT_FALSE( + user_media_client_impl_->UserMediaRequestHasAutomaticDeviceSelection( + ms_dispatcher_->audio_input_request_id())); + user_media_client_impl_->DeleteRequest( + ms_dispatcher_->audio_input_request_id()); // If audio is requested, but no constraint, it should be true. // Currently we expect it to be false due to a suspected bug in the @@ -670,7 +746,7 @@ EXPECT_CALL( media_devices_dispatcher_, SubscribeDeviceChangeNotifications(MEDIA_DEVICE_TYPE_AUDIO_OUTPUT, _, _)); - used_media_impl_->SetMediaDeviceChangeObserver(); + user_media_client_impl_->SetMediaDeviceChangeObserver(); base::RunLoop().RunUntilIdle(); base::WeakPtr<MediaDevicesEventDispatcher> event_dispatcher = @@ -690,7 +766,7 @@ EXPECT_CALL( media_devices_dispatcher_, UnsubscribeDeviceChangeNotifications(MEDIA_DEVICE_TYPE_AUDIO_OUTPUT, _)); - used_media_impl_->RemoveMediaDeviceChangeObserver(); + user_media_client_impl_->RemoveMediaDeviceChangeObserver(); base::RunLoop().RunUntilIdle(); } @@ -720,4 +796,87 @@ EXPECT_EQ(1, ms_dispatcher_->stop_audio_device_counter()); } +TEST_F(UserMediaClientImplTest, CreateWithMandatoryInvalidAudioDeviceId) { + blink::WebMediaConstraints audio_constraints = + CreateDeviceConstraints(kInvalidDeviceId); + blink::WebUserMediaRequest request = + blink::WebUserMediaRequest::createForTesting( + audio_constraints, blink::WebMediaConstraints()); + user_media_client_impl_->RequestUserMedia(request); + EXPECT_EQ(UserMediaClientImplUnderTest::REQUEST_FAILED, + user_media_client_impl_->request_state()); +} + +TEST_F(UserMediaClientImplTest, CreateWithMandatoryInvalidVideoDeviceId) { + blink::WebMediaConstraints video_constraints = + CreateDeviceConstraints(kInvalidDeviceId); + blink::WebUserMediaRequest request = + blink::WebUserMediaRequest::createForTesting(blink::WebMediaConstraints(), + video_constraints); + user_media_client_impl_->RequestUserMedia(request); + EXPECT_EQ(UserMediaClientImplUnderTest::REQUEST_FAILED, + user_media_client_impl_->request_state()); +} + +TEST_F(UserMediaClientImplTest, CreateWithMandatoryValidDeviceIds) { + blink::WebMediaConstraints audio_constraints = + CreateDeviceConstraints(kFakeAudioInputDeviceId1); + blink::WebMediaConstraints video_constraints = + CreateDeviceConstraints(kFakeVideoInputDeviceId1); + TestValidRequestWithDeviceConstraints(audio_constraints, video_constraints, + kFakeAudioInputDeviceId1, + kFakeVideoInputDeviceId1); +} + +TEST_F(UserMediaClientImplTest, CreateWithBasicIdealValidDeviceId) { + blink::WebMediaConstraints audio_constraints = + CreateDeviceConstraints(nullptr, kFakeAudioInputDeviceId1); + blink::WebMediaConstraints video_constraints = + CreateDeviceConstraints(nullptr, kFakeVideoInputDeviceId1); + TestValidRequestWithDeviceConstraints(audio_constraints, video_constraints, + kFakeAudioInputDeviceId1, + kFakeVideoInputDeviceId1); +} + +TEST_F(UserMediaClientImplTest, CreateWithAdvancedExactValidDeviceId) { + blink::WebMediaConstraints audio_constraints = + CreateDeviceConstraints(nullptr, nullptr, kFakeAudioInputDeviceId1); + blink::WebMediaConstraints video_constraints = CreateDeviceConstraints( + nullptr, nullptr, kFakeVideoInputDeviceId1); + TestValidRequestWithDeviceConstraints(audio_constraints, video_constraints, + kFakeAudioInputDeviceId1, + kFakeVideoInputDeviceId1); +} + +TEST_F(UserMediaClientImplTest, CreateWithAdvancedIdealValidDeviceId) { + blink::WebMediaConstraints audio_constraints = CreateDeviceConstraints( + nullptr, nullptr, nullptr, kFakeAudioInputDeviceId1); + blink::WebMediaConstraints video_constraints = CreateDeviceConstraints( + nullptr, nullptr, nullptr, kFakeVideoInputDeviceId1); + TestValidRequestWithDeviceConstraints(audio_constraints, video_constraints, + kFakeAudioInputDeviceId1, + kFakeVideoInputDeviceId1); +} + +TEST_F(UserMediaClientImplTest, CreateWithAllOptionalInvalidDeviceId) { + blink::WebMediaConstraints audio_constraints = CreateDeviceConstraints( + nullptr, kInvalidDeviceId, kInvalidDeviceId, kInvalidDeviceId); + blink::WebMediaConstraints video_constraints = CreateDeviceConstraints( + nullptr, kInvalidDeviceId, kInvalidDeviceId, kInvalidDeviceId); + // MockMediaStreamDispatcher uses empty string as default device ID. + TestValidRequestWithDeviceConstraints(audio_constraints, video_constraints, + std::string(), std::string()); +} + +TEST_F(UserMediaClientImplTest, + CreateWithAdvancedIdealValidOtherOptionalInvalidDeviceId) { + blink::WebMediaConstraints audio_constraints = CreateDeviceConstraints( + nullptr, kInvalidDeviceId, kInvalidDeviceId, kFakeAudioInputDeviceId1); + blink::WebMediaConstraints video_constraints = CreateDeviceConstraints( + nullptr, kInvalidDeviceId, kInvalidDeviceId, kFakeVideoInputDeviceId1); + TestValidRequestWithDeviceConstraints(audio_constraints, video_constraints, + kFakeAudioInputDeviceId1, + kFakeVideoInputDeviceId1); +} + } // namespace content
diff --git a/content/renderer/render_thread_impl_browsertest.cc b/content/renderer/render_thread_impl_browsertest.cc index 53a92f7..85bfe6e1 100644 --- a/content/renderer/render_thread_impl_browsertest.cc +++ b/content/renderer/render_thread_impl_browsertest.cc
@@ -17,6 +17,7 @@ #include "base/strings/string_number_conversions.h" #include "base/threading/sequenced_worker_pool.h" #include "base/threading/thread_task_runner_handle.h" +#include "build/build_config.h" #include "cc/output/buffer_to_texture_target_map.h" #include "components/discardable_memory/client/client_discardable_shared_memory_manager.h" #include "components/discardable_memory/service/discardable_shared_memory_manager.h" @@ -441,6 +442,9 @@ EXPECT_FALSE(memory->Lock()); } +// Disable the test for the Android asan build. +// See http://crbug.com/667837 for detail. +#if !(defined(OS_ANDROID) && defined(ADDRESS_SANITIZER)) IN_PROC_BROWSER_TEST_F(RenderThreadImplDiscardableMemoryBrowserTest, DiscardableMemoryAddressSpace) { const size_t kLargeSize = 4 * 1024 * 1024; // 4MiB. @@ -458,6 +462,7 @@ instances.push_back(std::move(memory)); } } +#endif IN_PROC_BROWSER_TEST_F(RenderThreadImplDiscardableMemoryBrowserTest, ReleaseFreeDiscardableMemory) {
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc index 1c416ec0..26af975 100644 --- a/content/renderer/render_view_impl.cc +++ b/content/renderer/render_view_impl.cc
@@ -1040,6 +1040,9 @@ base::SysInfo::IsLowEndDevice(); // TODO(mlamouri): rename this setting "isLowEndDevice". settings->setForcePreloadNoneForMediaElements(is_low_end_device); + + WebRuntimeFeatures::enableVideoFullscreenOrientationLock( + prefs.video_fullscreen_orientation_lock_enabled); #endif settings->setViewportEnabled(prefs.viewport_enabled);
diff --git a/content/test/gpu/gpu_tests/gpu_test_expectations.py b/content/test/gpu/gpu_tests/gpu_test_expectations.py index 9df6f00..b8f4d0e6 100644 --- a/content/test/gpu/gpu_tests/gpu_test_expectations.py +++ b/content/test/gpu/gpu_tests/gpu_test_expectations.py
@@ -5,7 +5,7 @@ from gpu_tests import test_expectations ANGLE_CONDITIONS = ['d3d9', 'd3d11', 'opengl', 'no_angle'] - +CMD_DECODER_CONDITIONS = ['passthrough', 'no_passthrough'] GPU_CONDITIONS = ['amd', 'arm', 'broadcom', 'hisilicon', 'intel', 'imagination', 'nvidia', 'qualcomm', 'vivante'] @@ -15,6 +15,7 @@ self.gpu_conditions = [] self.device_id_conditions = [] self.angle_conditions = [] + self.cmd_decoder_conditions = [] self.max_num_retries = max_num_retries assert self.max_num_retries == 0 or expectation == 'flaky' super(GpuExpectation, self).__init__( @@ -67,6 +68,8 @@ self.gpu_conditions.append(cl) elif cl in ANGLE_CONDITIONS: self.angle_conditions.append(cl) + elif cl in CMD_DECODER_CONDITIONS: + self.cmd_decoder_conditions.append(cl) else: # Delegate to superclass. super(GpuExpectation, self).ParseCondition(condition) @@ -112,8 +115,12 @@ angle_matches = ( (not expectation.angle_conditions) or angle_renderer in expectation.angle_conditions) + cmd_decoder = self._GetCommandDecoder(gpu_info) + cmd_decoder_matches = ( + (not expectation.cmd_decoder_conditions) or + cmd_decoder in expectation.cmd_decoder_conditions) - return gpu_matches and angle_matches + return gpu_matches and angle_matches and cmd_decoder_matches def _GetGpuVendorString(self, gpu_info): if gpu_info: @@ -149,3 +156,9 @@ elif 'OpenGL' in gl_renderer: return 'opengl' return 'no_angle' + + def _GetCommandDecoder(self, gpu_info): + if gpu_info and gpu_info.aux_attributes and \ + gpu_info.aux_attributes.get('passthrough_cmd_decoder', False): + return 'passthrough' + return 'no_passthrough'
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py index e25370a..7a6d171 100644 --- a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py +++ b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
@@ -133,14 +133,14 @@ # Win NVIDIA failures self.Flaky('conformance/textures/misc/texture-npot-video.html', - ['win', 'nvidia'], bug=626524) + ['win', 'nvidia', 'no_passthrough'], bug=626524) self.Flaky('conformance/textures/misc/texture-upload-size.html', ['win', 'nvidia'], bug=630860) # Win7 / Intel failures self.Fail('conformance/textures/misc/' + 'copy-tex-image-and-sub-image-2d.html', - ['win7', 'intel']) + ['win7', 'intel', 'no_passthrough']) # Win / AMD flakiness seen on new tryservers. # It's unfortunate that this suppression needs to be so broad, but @@ -214,6 +214,114 @@ self.Fail('conformance/uniforms/uniform-default-values.html', ['win', 'intel', 'opengl'], bug=1007) # angle bug ID + # Win / Passthrough command decoder + self.Fail('conformance/attribs/gl-vertexattribpointer.html', + ['win', 'passthrough', 'd3d11'], bug=1523) # angle bug ID + self.Fail('conformance/extensions/*', ['win', 'passthrough', 'd3d11'], + bug=1523) # angle bug ID + self.Fail('conformance/canvas/framebuffer-bindings-unaffected-on-' + + 'resize.html', ['win', 'passthrough', 'd3d11'], bug=665521) + self.Fail('conformance/glsl/bugs/essl3-shaders-with-webgl1.html', + ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID + self.Fail('conformance/glsl/misc/attrib-location-length-limits.html', + ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID + self.Fail('conformance/glsl/misc/shader-varying-packing-restrictions.html', + ['win', 'passthrough', 'd3d11'], bug=1638) # angle bug ID + self.Fail('conformance/glsl/misc/shader-with-257-character-define.html', + ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID + self.Fail('conformance/glsl/misc/shader-with-257-character-identifier.' + + 'frag.html', ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID + self.Fail('conformance/glsl/misc/shader-with-dfdx.frag.html', + ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID + self.Fail('conformance/glsl/misc/shaders-with-invariance.html', + ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID + self.Fail('conformance/glsl/misc/shaders-with-name-conflicts.html', + ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID + self.Fail('conformance/glsl/misc/shaders-with-uniform-structs.html', + ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID + self.Fail('conformance/glsl/variables/glsl-built-ins.html', + ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID + self.Fail('conformance/limits/gl-line-width.html', + ['win', 'passthrough', 'd3d11'], bug=1523) # angle bug ID + self.Fail('conformance/misc/error-reporting.html', + ['win', 'passthrough', 'd3d11'], bug=602688) + self.Fail('conformance/misc/invalid-passed-params.html', + ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID + self.Fail('conformance/misc/object-deletion-behaviour.html', + ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID + self.Fail('conformance/misc/type-conversion-test.html', + ['win', 'passthrough', 'd3d11'], bug=602688) + self.Fail('conformance/misc/uninitialized-test.html', + ['win', 'passthrough', 'd3d11'], bug=1635) # angle bug ID + self.Fail('conformance/misc/webgl-specific.html', + ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID + self.Fail('conformance/more/conformance/quickCheckAPI-B2.html', + ['win', 'passthrough', 'd3d11'], bug=665518) + self.Fail('conformance/more/conformance/quickCheckAPI-D_G.html', + ['win', 'passthrough', 'd3d11'], bug=665518) + self.Fail('conformance/more/functions/copyTexImage2D.html', + ['win', 'passthrough', 'd3d11'], bug=665518) + self.Fail('conformance/more/functions/copyTexImage2DBadArgs.html', + ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID + self.Fail('conformance/more/functions/copyTexSubImage2D.html', + ['win', 'passthrough', 'd3d11'], bug=665518) + self.Fail('conformance/more/functions/drawArrays.html', + ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID + self.Fail('conformance/more/functions/drawArraysOutOfBounds.html', + ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID + self.Fail('conformance/more/functions/drawElementsBadArgs.html', + ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID + self.Fail('conformance/more/functions/texSubImage2DBadArgs.html', + ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID + self.Fail('conformance/more/functions/texSubImage2DHTMLBadArgs.html', + ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID + self.Fail('conformance/more/functions/vertexAttribPointerBadArgs.html', + ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID + self.Fail('conformance/programs/get-active-test.html', + ['win', 'passthrough', 'd3d11'], bug=602688) + self.Fail('conformance/programs/program-test.html', + ['win', 'passthrough', 'd3d11'], bug=602688) + self.Fail('conformance/reading/read-pixels-test.html', + ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID + self.Fail('conformance/renderbuffers/feedback-loop.html', + ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID + self.Fail('conformance/renderbuffers/framebuffer-object-attachment.html', + ['win', 'passthrough', 'd3d11'], bug=602688) + self.Fail('conformance/renderbuffers/framebuffer-test.html', + ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID + self.Fail('conformance/rendering/draw-arrays-out-of-bounds.html', + ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID + self.Fail('conformance/rendering/draw-elements-out-of-bounds.html', + ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID + self.Fail('conformance/textures/misc/copy-tex-image-2d-formats.html', + ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID + self.Fail('conformance/textures/misc/copy-tex-image-and-sub-image-2d.html', + ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID + self.Fail('conformance/textures/misc/mipmap-fbo.html', + ['win', 'passthrough', 'd3d11'], bug=665518) + self.Fail('conformance/textures/misc/tex-input-validation.html', + ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID + self.Fail('conformance/textures/misc/texture-active-bind-2.html', + ['win', 'passthrough', 'd3d11'], bug=665518) + self.Fail('conformance/textures/misc/texture-attachment-formats.html', + ['win', 'passthrough', 'd3d11'], bug=602688) + self.Fail('conformance/textures/misc/texture-copying-feedback-loops.html', + ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID + self.Fail('conformance/textures/misc/texture-fakeblack.html', + ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID + self.Fail('conformance/textures/misc/texture-mips.html', + ['win', 'passthrough', 'd3d11'], bug=665518) + self.Fail('conformance/textures/misc/texture-npot.html', + ['win', 'passthrough', 'd3d11'], bug=665518) + self.Fail('conformance/textures/misc/texture-npot-video.html', + ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID + self.Fail('conformance/uniforms/uniform-samplers-test.html', + ['win', 'passthrough', 'd3d11'], bug=1639) # angle bug ID + self.Fail('WebglExtension_OES_texture_float_linear', + ['win', 'passthrough', 'd3d11'], bug=1523) # angle bug ID + self.Fail('WebglExtension_OES_texture_half_float_linear', + ['win', 'passthrough', 'd3d11'], bug=1523) # angle bug ID + # Mac failures self.Flaky('conformance/extensions/oes-texture-float-with-video.html', ['mac'], bug=599272)
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_expectations_unittest.py b/content/test/gpu/gpu_tests/webgl_conformance_expectations_unittest.py index 08961fe..71661466a 100644 --- a/content/test/gpu/gpu_tests/webgl_conformance_expectations_unittest.py +++ b/content/test/gpu/gpu_tests/webgl_conformance_expectations_unittest.py
@@ -107,6 +107,7 @@ ( set(e.os_conditions), set(e.browser_conditions), + set(e.cmd_decoder_conditions), set(e.angle_conditions), ), set(e.gpu_conditions),
diff --git a/gpu/config/gpu_info.cc b/gpu/config/gpu_info.cc index 3af11f6..6ce2d78 100644 --- a/gpu/config/gpu_info.cc +++ b/gpu/config/gpu_info.cc
@@ -76,6 +76,7 @@ sandboxed(false), process_crash_count(0), in_process_gpu(true), + passthrough_cmd_decoder(false), basic_info_state(kCollectInfoNone), context_info_state(kCollectInfoNone), #if defined(OS_WIN) @@ -125,6 +126,7 @@ bool sandboxed; int process_crash_count; bool in_process_gpu; + bool passthrough_cmd_decoder; CollectInfoResult basic_info_state; CollectInfoResult context_info_state; #if defined(OS_WIN) @@ -188,6 +190,7 @@ enumerator->AddBool("sandboxed", sandboxed); enumerator->AddInt("processCrashCount", process_crash_count); enumerator->AddBool("inProcessGpu", in_process_gpu); + enumerator->AddBool("passthroughCmdDecoder", passthrough_cmd_decoder); enumerator->AddInt("basicInfoState", basic_info_state); enumerator->AddInt("contextInfoState", context_info_state); #if defined(OS_WIN)
diff --git a/gpu/config/gpu_info.h b/gpu/config/gpu_info.h index fbb6aac..86479489 100644 --- a/gpu/config/gpu_info.h +++ b/gpu/config/gpu_info.h
@@ -224,6 +224,9 @@ // True if the GPU is running in the browser process instead of its own. bool in_process_gpu; + // True if the GPU process is using the passthrough command decoder. + bool passthrough_cmd_decoder; + // The state of whether the basic/context/DxDiagnostics info is collected and // if the collection fails or not. CollectInfoResult basic_info_state;
diff --git a/gpu/config/gpu_info_collector.cc b/gpu/config/gpu_info_collector.cc index 79ae1c8..2d2dfe2 100644 --- a/gpu/config/gpu_info_collector.cc +++ b/gpu/config/gpu_info_collector.cc
@@ -228,6 +228,8 @@ basic_gpu_info->sandboxed = context_gpu_info.sandboxed; basic_gpu_info->direct_rendering = context_gpu_info.direct_rendering; basic_gpu_info->in_process_gpu = context_gpu_info.in_process_gpu; + basic_gpu_info->passthrough_cmd_decoder = + context_gpu_info.passthrough_cmd_decoder; basic_gpu_info->context_info_state = context_gpu_info.context_info_state; basic_gpu_info->initialization_time = context_gpu_info.initialization_time; basic_gpu_info->video_decode_accelerator_capabilities =
diff --git a/gpu/ipc/common/gpu_info.mojom b/gpu/ipc/common/gpu_info.mojom index 2dc02806..0e950cb 100644 --- a/gpu/ipc/common/gpu_info.mojom +++ b/gpu/ipc/common/gpu_info.mojom
@@ -102,6 +102,7 @@ bool sandboxed; int32 process_crash_count; bool in_process_gpu; + bool passthrough_cmd_decoder; CollectInfoResult basic_info_state; CollectInfoResult context_info_state; CollectInfoResult dx_diagnostics_info_state;
diff --git a/gpu/ipc/common/gpu_info_struct_traits.cc b/gpu/ipc/common/gpu_info_struct_traits.cc index 6c2bd820..b64e110 100644 --- a/gpu/ipc/common/gpu_info_struct_traits.cc +++ b/gpu/ipc/common/gpu_info_struct_traits.cc
@@ -224,6 +224,7 @@ out->direct_rendering = data.direct_rendering(); out->sandboxed = data.sandboxed(); out->in_process_gpu = data.in_process_gpu(); + out->passthrough_cmd_decoder = data.passthrough_cmd_decoder(); out->process_crash_count = data.process_crash_count(); out->jpeg_decode_accelerator_supported = data.jpeg_decode_accelerator_supported();
diff --git a/gpu/ipc/common/gpu_info_struct_traits.h b/gpu/ipc/common/gpu_info_struct_traits.h index ea76e0e..6dfa12c 100644 --- a/gpu/ipc/common/gpu_info_struct_traits.h +++ b/gpu/ipc/common/gpu_info_struct_traits.h
@@ -243,6 +243,10 @@ return input.in_process_gpu; } + static bool passthrough_cmd_decoder(const gpu::GPUInfo& input) { + return input.passthrough_cmd_decoder; + } + static gpu::CollectInfoResult basic_info_state(const gpu::GPUInfo& input) { return input.basic_info_state; }
diff --git a/gpu/ipc/common/gpu_param_traits_macros.h b/gpu/ipc/common/gpu_param_traits_macros.h index e6409d2..64248121 100644 --- a/gpu/ipc/common/gpu_param_traits_macros.h +++ b/gpu/ipc/common/gpu_param_traits_macros.h
@@ -91,6 +91,7 @@ IPC_STRUCT_TRAITS_MEMBER(sandboxed) IPC_STRUCT_TRAITS_MEMBER(process_crash_count) IPC_STRUCT_TRAITS_MEMBER(in_process_gpu) + IPC_STRUCT_TRAITS_MEMBER(passthrough_cmd_decoder) IPC_STRUCT_TRAITS_MEMBER(basic_info_state) IPC_STRUCT_TRAITS_MEMBER(context_info_state) #if defined(OS_WIN)
diff --git a/gpu/ipc/common/struct_traits_unittest.cc b/gpu/ipc/common/struct_traits_unittest.cc index 70ddbc0a..07931e8 100644 --- a/gpu/ipc/common/struct_traits_unittest.cc +++ b/gpu/ipc/common/struct_traits_unittest.cc
@@ -148,6 +148,7 @@ const bool sandboxed = true; const int process_crash_count = 0xdead; const bool in_process_gpu = true; + const bool passthrough_cmd_decoder = true; const gpu::CollectInfoResult basic_info_state = gpu::CollectInfoResult::kCollectInfoSuccess; const gpu::CollectInfoResult context_info_state = @@ -197,6 +198,7 @@ input.sandboxed = sandboxed; input.process_crash_count = process_crash_count; input.in_process_gpu = in_process_gpu; + input.passthrough_cmd_decoder = passthrough_cmd_decoder; input.basic_info_state = basic_info_state; input.context_info_state = context_info_state; #if defined(OS_WIN) @@ -259,6 +261,7 @@ EXPECT_EQ(sandboxed, output.sandboxed); EXPECT_EQ(process_crash_count, output.process_crash_count); EXPECT_EQ(in_process_gpu, output.in_process_gpu); + EXPECT_EQ(passthrough_cmd_decoder, output.passthrough_cmd_decoder); EXPECT_EQ(basic_info_state, output.basic_info_state); EXPECT_EQ(context_info_state, output.context_info_state); #if defined(OS_WIN)
diff --git a/gpu/ipc/service/gpu_init.cc b/gpu/ipc/service/gpu_init.cc index 1e912037..98620c4 100644 --- a/gpu/ipc/service/gpu_init.cc +++ b/gpu/ipc/service/gpu_init.cc
@@ -158,6 +158,9 @@ #endif gpu_info_.in_process_gpu = false; + gpu_info_.passthrough_cmd_decoder = + command_line.HasSwitch(switches::kUsePassthroughCmdDecoder); + sandbox_helper_->PreSandboxStartup(); #if defined(OS_LINUX)
diff --git a/ios/DEPS b/ios/DEPS index 8f13cb93e..94f7f2c 100644 --- a/ios/DEPS +++ b/ios/DEPS
@@ -3,11 +3,13 @@ # directories in ios/ so we disallow all of them. "-ios", - # To avoid ODR violation, direct import of ios/third_party/ochamcrest - # is forbidden in ios/DEPS and code should instead use import as if - # OCHamcrest was in a framework (i.e. #import <OCHamcrest/OCHamcrest.h>). + # To avoid ODR violation, direct import of these libraries is forbidden in + # ios/DEPS and code should instead use import as if they were in a framework + # (i.e. #import <OCHamcrest/OCHamcrest.h>). + "-ios/third_party/earl_grey", "-ios/third_party/ochamcrest", # For unit tests. + "+ios/testing", "+third_party/ocmock", ]
diff --git a/ios/chrome/BUILD.gn b/ios/chrome/BUILD.gn index 5044c7b..05ccaa8 100644 --- a/ios/chrome/BUILD.gn +++ b/ios/chrome/BUILD.gn
@@ -50,6 +50,7 @@ "//ios/chrome/browser/web_resource:unit_tests", "//ios/chrome/common:unit_tests", "//ios/chrome/test:unit_tests", + "//ios/chrome/test/base:unit_tests", ] assert_no_deps = ios_assert_no_deps
diff --git a/ios/chrome/DEPS b/ios/chrome/DEPS index 6503a0e..0637ee1d 100644 --- a/ios/chrome/DEPS +++ b/ios/chrome/DEPS
@@ -1,5 +1,20 @@ include_rules = [ + "+crypto", + "+net", + "+sql", + "+ui/base", + "+ui/gfx", + + # Only parts of skia are compiled on iOS, so we explicitly list the + # files that can be included to avoid bringing in more code. + "+skia/ext/skia_utils_ios.h", + "+third_party/skia/include/core/SkBitmap.h", + "+third_party/skia/include/core/SkColor.h", + "+third_party/skia/include/core/SkGraphics.h", + # The subdirectories in ios/chrome/ will manually allow their own include # directories in ios/chrome/ so we disallow all of them. "-ios/chrome", + "+ios/chrome/common", + "+ios/chrome/test", ]
diff --git a/ios/chrome/app/DEPS b/ios/chrome/app/DEPS index 9074a78..a2e43b0 100644 --- a/ios/chrome/app/DEPS +++ b/ios/chrome/app/DEPS
@@ -1,3 +1,25 @@ include_rules = [ "+ios/chrome/browser", + + "+breakpad/src/client/ios", + "+components/bookmarks/browser", + "+components/bookmarks/test", + "+components/browser_sync", + "+components/browsing_data/core", + "+components/component_updater", + "+components/content_settings", + "+components/crash/core/common", + "+components/favicon/core", + "+components/favicon_base", + "+components/handoff", + "+components/history/core/browser", + "+components/metrics", + "+components/prefs", + "+components/reading_list/core", + "+components/signin/core/browser", + "+components/strings", + "+components/suggestions", + "+components/url_formatter", + "+components/web_resource", + "+mojo/edk/embedder/embedder.h", ]
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd index 4dd9065..eb62cf5 100644 --- a/ios/chrome/app/strings/ios_strings.grd +++ b/ios/chrome/app/strings/ios_strings.grd
@@ -155,6 +155,7 @@ <message name="IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_SYNC_DESCRIPTION" desc="Description of the Chrome sync section on the sign-in confirmation screen. [Length: unlimited]"> Your bookmarks, history, passwords, and other settings will be synced to your Google Account so you can use them on all your devices. </message> + <!-- "Chrome sync" is the Google Cloud Based service used for sync. Thus this string resource is set to "Chrome sync" even for Chromium builds. --> <message name="IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_SYNC_TITLE" desc="Title of the Chrome sync section on the sign-in confirmation screen. [Length: 50em]"> Chrome Sync </message>
diff --git a/ios/chrome/browser/DEPS b/ios/chrome/browser/DEPS index c49fd45..6b5b985 100644 --- a/ios/chrome/browser/DEPS +++ b/ios/chrome/browser/DEPS
@@ -15,7 +15,9 @@ "+components/crash/core/common", "+components/dom_distiller/core", "+components/dom_distiller/ios", + "+components/error_page/common", "+components/favicon/core", + "+components/favicon/ios", "+components/favicon_base", "+components/flags_ui", "+components/gcm_driver", @@ -51,6 +53,7 @@ "+components/prefs", "+components/profile_metrics", "+components/proxy_config", + "+components/query_parser", "+components/rappor", "+components/reading_list", "+components/rlz", @@ -64,11 +67,13 @@ "+components/signin/core/common", "+components/signin/ios/browser", "+components/ssl_config", + "+components/ssl_errors", "+components/suggestions", "+components/sync", "+components/sync_sessions", "+components/sync_preferences", "+components/task_scheduler_util", + "+components/toolbar", "+components/translate/core", "+components/translate/ios", "+components/undo", @@ -83,7 +88,6 @@ "+components/webp_transcode", "+crypto", "+google_apis", - "+ios/chrome/common", "+ios/net", "+ios/public/provider/chrome", "+ios/public/provider/components", @@ -101,12 +105,6 @@ # For tests. "+ios/chrome/test", "+ios/public/test", - "+ios/testing", - - # Only parts of skia are compiled on iOS, so we explicitly list the - # files that can be included to avoid bringing in more code. - "+skia/ext/skia_utils_ios.h", - "+third_party/skia/include/core/SkBitmap.h", # Strings and resources. "+components/grit",
diff --git a/ios/chrome/browser/interstitials/BUILD.gn b/ios/chrome/browser/interstitials/BUILD.gn index dd91059..ef500ba 100644 --- a/ios/chrome/browser/interstitials/BUILD.gn +++ b/ios/chrome/browser/interstitials/BUILD.gn
@@ -3,6 +3,7 @@ # found in the LICENSE file. source_set("interstitials") { + configs += [ "//build/config/compiler:enable_arc" ] sources = [ "ios_chrome_controller_client.h", "ios_chrome_controller_client.mm",
diff --git a/ios/chrome/browser/interstitials/ios_chrome_controller_client.mm b/ios/chrome/browser/interstitials/ios_chrome_controller_client.mm index 9b6732f..6b5c5c67 100644 --- a/ios/chrome/browser/interstitials/ios_chrome_controller_client.mm +++ b/ios/chrome/browser/interstitials/ios_chrome_controller_client.mm
@@ -13,6 +13,10 @@ #import "ios/web/public/navigation_manager.h" #include "ios/web/public/web_state/web_state.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + IOSChromeControllerClient::IOSChromeControllerClient( web::WebState* web_state, std::unique_ptr<security_interstitials::MetricsHelper> metrics_helper)
diff --git a/ios/chrome/browser/interstitials/ios_chrome_metrics_helper.mm b/ios/chrome/browser/interstitials/ios_chrome_metrics_helper.mm index 878e8df..f575e16 100644 --- a/ios/chrome/browser/interstitials/ios_chrome_metrics_helper.mm +++ b/ios/chrome/browser/interstitials/ios_chrome_metrics_helper.mm
@@ -12,6 +12,10 @@ #include "ios/chrome/browser/history/history_service_factory.h" #include "ios/web/public/web_state/web_state.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + IOSChromeMetricsHelper::IOSChromeMetricsHelper( web::WebState* web_state, const GURL& request_url,
diff --git a/ios/chrome/browser/interstitials/ios_security_interstitial_page.mm b/ios/chrome/browser/interstitials/ios_security_interstitial_page.mm index 496e9e9..e438275c 100644 --- a/ios/chrome/browser/interstitials/ios_security_interstitial_page.mm +++ b/ios/chrome/browser/interstitials/ios_security_interstitial_page.mm
@@ -17,6 +17,10 @@ #include "ui/base/webui/jstemplate_builder.h" #include "ui/base/webui/web_ui_util.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + IOSSecurityInterstitialPage::IOSSecurityInterstitialPage( web::WebState* web_state, const GURL& request_url)
diff --git a/ios/chrome/browser/itunes_links/BUILD.gn b/ios/chrome/browser/itunes_links/BUILD.gn index a4abdb08..16a4cc95 100644 --- a/ios/chrome/browser/itunes_links/BUILD.gn +++ b/ios/chrome/browser/itunes_links/BUILD.gn
@@ -3,6 +3,7 @@ # found in the LICENSE file. source_set("itunes_links") { + configs += [ "//build/config/compiler:enable_arc" ] sources = [ "itunes_links_observer.h", "itunes_links_observer.mm",
diff --git a/ios/chrome/browser/itunes_links/itunes_links_observer.mm b/ios/chrome/browser/itunes_links/itunes_links_observer.mm index c881fd69..3ba6a354 100644 --- a/ios/chrome/browser/itunes_links/itunes_links_observer.mm +++ b/ios/chrome/browser/itunes_links/itunes_links_observer.mm
@@ -7,13 +7,16 @@ #include <memory> #include "base/logging.h" -#import "base/mac/scoped_nsobject.h" #include "base/strings/sys_string_conversions.h" #import "ios/chrome/browser/storekit_launcher.h" #import "ios/web/public/web_state/web_state_observer_bridge.h" #include "ios/web/public/web_state/web_state.h" #include "url/gurl.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + @interface ITunesLinksObserver () // If |URL| points to a product on itunes.apple.com, returns the product ID. @@ -25,7 +28,7 @@ @end @implementation ITunesLinksObserver { - base::WeakNSProtocol<id<StoreKitLauncher>> _storeKitLauncher; + __weak id<StoreKitLauncher> _storeKitLauncher; std::unique_ptr<web::WebStateObserverBridge> _webStateObserverBridge; } @@ -64,7 +67,7 @@ } - (void)setStoreKitLauncher:(id<StoreKitLauncher>)storeKitLauncher { - _storeKitLauncher.reset(storeKitLauncher); + _storeKitLauncher = storeKitLauncher; } @end
diff --git a/ios/chrome/browser/ui/alert_coordinator/BUILD.gn b/ios/chrome/browser/ui/alert_coordinator/BUILD.gn index 5e70f81..a1958f5 100644 --- a/ios/chrome/browser/ui/alert_coordinator/BUILD.gn +++ b/ios/chrome/browser/ui/alert_coordinator/BUILD.gn
@@ -20,6 +20,7 @@ } source_set("unit_tests") { + configs += [ "//build/config/compiler:enable_arc" ] testonly = true sources = [ "action_sheet_coordinator_unittest.mm",
diff --git a/ios/chrome/browser/ui/alert_coordinator/action_sheet_coordinator_unittest.mm b/ios/chrome/browser/ui/alert_coordinator/action_sheet_coordinator_unittest.mm index ee05e1d..83eb94e 100644 --- a/ios/chrome/browser/ui/alert_coordinator/action_sheet_coordinator_unittest.mm +++ b/ios/chrome/browser/ui/alert_coordinator/action_sheet_coordinator_unittest.mm
@@ -9,27 +9,29 @@ #import "base/mac/foundation_util.h" #include "testing/platform_test.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + // Tests that if there is a popover, it uses the CGRect passed in init. TEST(ActionSheetCoordinatorTest, CGRectUsage) { // Setup. - UIWindow* window = [[[UIWindow alloc] - initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]; + UIWindow* window = + [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; [window makeKeyAndVisible]; - UIViewController* viewController = - [[[UIViewController alloc] init] autorelease]; + UIViewController* viewController = [[UIViewController alloc] init]; [window setRootViewController:viewController]; - UIView* view = - [[[UIView alloc] initWithFrame:viewController.view.bounds] autorelease]; + UIView* view = [[UIView alloc] initWithFrame:viewController.view.bounds]; [viewController.view addSubview:view]; CGRect rect = CGRectMake(124, 432, 126, 63); - AlertCoordinator* alertCoordinator = [[[ActionSheetCoordinator alloc] - initWithBaseViewController:viewController - title:@"title" - message:nil - rect:rect - view:view] autorelease]; + AlertCoordinator* alertCoordinator = + [[ActionSheetCoordinator alloc] initWithBaseViewController:viewController + title:@"title" + message:nil + rect:rect + view:view]; // Action. [alertCoordinator start];
diff --git a/ios/chrome/browser/ui/alert_coordinator/alert_coordinator_unittest.mm b/ios/chrome/browser/ui/alert_coordinator/alert_coordinator_unittest.mm index 8933d79..ba8ad71 100644 --- a/ios/chrome/browser/ui/alert_coordinator/alert_coordinator_unittest.mm +++ b/ios/chrome/browser/ui/alert_coordinator/alert_coordinator_unittest.mm
@@ -7,23 +7,25 @@ #import <UIKit/UIKit.h> #import "base/mac/foundation_util.h" -#import "base/mac/scoped_nsobject.h" #include "testing/platform_test.h" #import "third_party/ocmock/OCMock/OCMock.h" #include "third_party/ocmock/gtest_support.h" #include "ui/base/l10n/l10n_util.h" #include "ui/strings/grit/ui_strings.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + #pragma mark - Fixture. // Fixture to test AlertCoordinator. class AlertCoordinatorTest : public PlatformTest { protected: AlertCoordinatorTest() { - window_.reset( - [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]); + window_ = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; [window_ makeKeyAndVisible]; - view_controller_.reset([[UIViewController alloc] init]); + view_controller_ = [[UIViewController alloc] init]; [window_ setRootViewController:view_controller_]; } @@ -38,17 +40,17 @@ AlertCoordinator* getAlertCoordinator(UIViewController* viewController, NSString* title, NSString* message) { - alert_coordinator_.reset([[AlertCoordinator alloc] - initWithBaseViewController:viewController - title:title - message:message]); + alert_coordinator_ = + [[AlertCoordinator alloc] initWithBaseViewController:viewController + title:title + message:message]; return alert_coordinator_; } private: - base::scoped_nsobject<AlertCoordinator> alert_coordinator_; - base::scoped_nsobject<UIWindow> window_; - base::scoped_nsobject<UIViewController> view_controller_; + AlertCoordinator* alert_coordinator_; + UIWindow* window_; + UIViewController* view_controller_; }; #pragma mark - Tests. @@ -80,10 +82,9 @@ // visible view. TEST_F(AlertCoordinatorTest, ValidateIsNotVisible) { // Setup. - base::scoped_nsobject<UIWindow> window( - [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]); - base::scoped_nsobject<UIViewController> viewController( - [[UIViewController alloc] init]); + UIWindow* window = + [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; + UIViewController* viewController = [[UIViewController alloc] init]; [window setRootViewController:viewController]; AlertCoordinator* alertCoordinator = getAlertCoordinator(viewController); @@ -161,8 +162,7 @@ @"testCancel" : @(UIAlertActionStyleCancel), }; - base::scoped_nsobject<NSMutableDictionary> remainingActions( - [actions mutableCopy]); + NSMutableDictionary* remainingActions = [actions mutableCopy]; // Action. for (id key in actions) {
diff --git a/ios/chrome/browser/ui/alert_coordinator/input_alert_coordinator_unittest.mm b/ios/chrome/browser/ui/alert_coordinator/input_alert_coordinator_unittest.mm index 4aebd39..5cbf932 100644 --- a/ios/chrome/browser/ui/alert_coordinator/input_alert_coordinator_unittest.mm +++ b/ios/chrome/browser/ui/alert_coordinator/input_alert_coordinator_unittest.mm
@@ -8,14 +8,17 @@ #import "third_party/ocmock/OCMock/OCMock.h" #include "third_party/ocmock/gtest_support.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + TEST(InputAlertCoordinatorTest, AddTextField) { // Setup. - UIViewController* viewController = - [[[UIViewController alloc] init] autorelease]; - InputAlertCoordinator* alertCoordinator = [[[InputAlertCoordinator alloc] - initWithBaseViewController:viewController - title:@"Test" - message:nil] autorelease]; + UIViewController* viewController = [[UIViewController alloc] init]; + InputAlertCoordinator* alertCoordinator = + [[InputAlertCoordinator alloc] initWithBaseViewController:viewController + title:@"Test" + message:nil]; void (^emptyHandler)(UITextField* textField) = ^(UITextField* textField) { }; @@ -32,12 +35,11 @@ TEST(InputAlertCoordinatorTest, GetTextFields) { // Setup. - UIViewController* viewController = - [[[UIViewController alloc] init] autorelease]; - InputAlertCoordinator* alertCoordinator = [[[InputAlertCoordinator alloc] - initWithBaseViewController:viewController - title:@"Test" - message:nil] autorelease]; + UIViewController* viewController = [[UIViewController alloc] init]; + InputAlertCoordinator* alertCoordinator = + [[InputAlertCoordinator alloc] initWithBaseViewController:viewController + title:@"Test" + message:nil]; NSArray<UITextField*>* array = [NSArray array]; id alert =
diff --git a/ios/chrome/test/base/BUILD.gn b/ios/chrome/test/base/BUILD.gn new file mode 100644 index 0000000..9c7dffc --- /dev/null +++ b/ios/chrome/test/base/BUILD.gn
@@ -0,0 +1,26 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +source_set("base") { + testonly = true + sources = [ + "scoped_block_swizzler.h", + "scoped_block_swizzler.mm", + ] + deps = [ + "//base", + ] +} + +source_set("unit_tests") { + testonly = true + sources = [ + "scoped_block_swizzler_unittest.mm", + ] + deps = [ + ":base", + "//base", + "//testing/gtest", + ] +}
diff --git a/ios/chrome/test/base/scoped_block_swizzler.h b/ios/chrome/test/base/scoped_block_swizzler.h new file mode 100644 index 0000000..ecfea71 --- /dev/null +++ b/ios/chrome/test/base/scoped_block_swizzler.h
@@ -0,0 +1,40 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +#ifndef IOS_CHROME_TEST_BASE_SCOPED_BLOCK_SWIZZLER_H_ +#define IOS_CHROME_TEST_BASE_SCOPED_BLOCK_SWIZZLER_H_ + +#include <objc/runtime.h> + +#include "base/macros.h" + +// Helper class that replaces a method implementation with a given block. +// ScopedBlockSwizzler automatically swizzles when it is constructed and +// reinstalls the original method implementation when it goes out of scope. +class ScopedBlockSwizzler { + public: + // Constructs a new ScopedBlockSwizzler object and replaces the implementation + // of |selector| on the |target| class with the given |block|. + // ScopedBlockSwizzler first tries to swizzle a class method; if one is not + // found, it tries to swizzle an instance method. It is an error to pass a + // |selector| that does not exist on the |target| class. + ScopedBlockSwizzler(Class target, SEL selector, id block); + + // Destroys the ScopedBlockSwizzler object, removing the swizzled method and + // reinstalling the original method implementation. + virtual ~ScopedBlockSwizzler(); + + private: + // The method that is to be swizzled. Can be either a class method or an + // instance method. + Method method_; + + // The original implementation of the swizzled method, saved so that it can be + // reinstalled when this object goes out of scope. + IMP original_imp_; + + DISALLOW_COPY_AND_ASSIGN(ScopedBlockSwizzler); +}; + +#endif // IOS_CHROME_TEST_BASE_SCOPED_BLOCK_SWIZZLER_H_
diff --git a/ios/chrome/test/base/scoped_block_swizzler.mm b/ios/chrome/test/base/scoped_block_swizzler.mm new file mode 100644 index 0000000..312de59 --- /dev/null +++ b/ios/chrome/test/base/scoped_block_swizzler.mm
@@ -0,0 +1,24 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/test/base/scoped_block_swizzler.h" + +#include "base/logging.h" + +ScopedBlockSwizzler::ScopedBlockSwizzler(Class target, SEL selector, id block) { + method_ = class_getInstanceMethod(target, selector); + if (!method_) { + // Try swizzling a class method instead. + method_ = class_getClassMethod(target, selector); + } + DCHECK(method_); + + IMP block_imp = imp_implementationWithBlock(block); + original_imp_ = method_setImplementation(method_, block_imp); +} + +ScopedBlockSwizzler::~ScopedBlockSwizzler() { + IMP block_imp = method_setImplementation(method_, original_imp_); + DCHECK(imp_removeBlock(block_imp)); +}
diff --git a/ios/chrome/test/base/scoped_block_swizzler_unittest.mm b/ios/chrome/test/base/scoped_block_swizzler_unittest.mm new file mode 100644 index 0000000..2e390a4 --- /dev/null +++ b/ios/chrome/test/base/scoped_block_swizzler_unittest.mm
@@ -0,0 +1,103 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/mac/foundation_util.h" +#import "base/mac/scoped_nsobject.h" +#import "ios/chrome/test/base/scoped_block_swizzler.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/gtest_mac.h" +#include "testing/platform_test.h" + +// Class containing two methods that will be swizzled by the unittests. +@interface ScopedBlockSwizzlerTestClass : NSObject + +// An NSString property that will be accessed by one of the swizzled methods. +@property(nonatomic, copy) NSString* value; + ++ (NSString*)classMethodToSwizzle; +- (NSString*)instanceMethodToSwizzle; +@end + +namespace { + +NSString* const kOriginalClassValue = @"Bar"; +NSString* const kSwizzledClassValue = @"Foo"; +NSString* const kOriginalInstanceValue = @"Bizz"; +NSString* const kSwizzledInstanceValue = @"Buzz"; + +// Tests that swizzling a class method works properly. +TEST(ScopedBlockSwizzlerTest, SwizzlingClassMethods) { + EXPECT_NSEQ(kOriginalClassValue, + [ScopedBlockSwizzlerTestClass classMethodToSwizzle]); + + { + id block = ^NSString*(id self) { return kSwizzledClassValue; }; + ScopedBlockSwizzler swizzler([ScopedBlockSwizzlerTestClass class], + @selector(classMethodToSwizzle), block); + EXPECT_NSEQ(kSwizzledClassValue, + [ScopedBlockSwizzlerTestClass classMethodToSwizzle]); + } + + EXPECT_NSEQ(kOriginalClassValue, + [ScopedBlockSwizzlerTestClass classMethodToSwizzle]); +} + +// Tests that swizzling an instance method works properly. +TEST(ScopedBlockSwizzlerTest, SwizzlingInstanceMethod) { + base::scoped_nsobject<ScopedBlockSwizzlerTestClass> target( + [[ScopedBlockSwizzlerTestClass alloc] init]); + target.get().value = kSwizzledInstanceValue; + + EXPECT_NSEQ(kOriginalInstanceValue, [target instanceMethodToSwizzle]); + EXPECT_FALSE([[target instanceMethodToSwizzle] + isEqualToString:kSwizzledInstanceValue]); + + { + id block = ^NSString*(id self) { + return base::mac::ObjCCastStrict<ScopedBlockSwizzlerTestClass>(self) + .value; + }; + ScopedBlockSwizzler swizzler([ScopedBlockSwizzlerTestClass class], + @selector(instanceMethodToSwizzle), block); + EXPECT_NSEQ(kSwizzledInstanceValue, [target instanceMethodToSwizzle]); + } + + EXPECT_NSEQ(kOriginalInstanceValue, [target instanceMethodToSwizzle]); +} + +// Tests that calling |ScopedBlockSwizzler::reset()| properly unswizzles the +// method. +TEST(ScopedBlockSwizzlerTest, TestReset) { + EXPECT_NSEQ(kOriginalClassValue, + [ScopedBlockSwizzlerTestClass classMethodToSwizzle]); + + id block = ^NSString*(id self) { return kSwizzledClassValue; }; + std::unique_ptr<ScopedBlockSwizzler> swizzler( + new ScopedBlockSwizzler([ScopedBlockSwizzlerTestClass class], + @selector(classMethodToSwizzle), block)); + EXPECT_NSEQ(kSwizzledClassValue, + [ScopedBlockSwizzlerTestClass classMethodToSwizzle]); + + swizzler.reset(); + EXPECT_NSEQ(kOriginalClassValue, + [ScopedBlockSwizzlerTestClass classMethodToSwizzle]); +} + +} // namespace + +#pragma mark - ScopedBlockSwizzlerTestClass + +@implementation ScopedBlockSwizzlerTestClass + +@synthesize value = _value; + ++ (NSString*)classMethodToSwizzle { + return kOriginalClassValue; +} + +- (NSString*)instanceMethodToSwizzle { + return kOriginalInstanceValue; +} + +@end
diff --git a/ios/chrome/test/data/OWNERS b/ios/chrome/test/data/OWNERS new file mode 100644 index 0000000..72e8ffc --- /dev/null +++ b/ios/chrome/test/data/OWNERS
@@ -0,0 +1 @@ +*
diff --git a/ios/chrome/test/data/favicon/test_favicon.png b/ios/chrome/test/data/favicon/test_favicon.png new file mode 100644 index 0000000..e9100dae --- /dev/null +++ b/ios/chrome/test/data/favicon/test_favicon.png Binary files differ
diff --git a/ios/chrome/test/data/omnibox/selected_ranges.txt b/ios/chrome/test/data/omnibox/selected_ranges.txt new file mode 100644 index 0000000..8e918f0 --- /dev/null +++ b/ios/chrome/test/data/omnibox/selected_ranges.txt
@@ -0,0 +1,13 @@ +This is some example text +이것은 몇 가지 예를 들어 텍스트입니다 +यह कुछ उदाहरण पाठ है +这是一些示例文本。 +這是一些示例文本 +הנה טקסט ירושלים. +これは、いくつかの例では、テキストです + +I really like selecting ranges +私は実際に選択範囲を好き +我真的很喜欢选择范围 +정말 선택 범위를 좋아 +אני באמת אוהב את טווחי בחירה
diff --git a/ios/chrome/test/data/sessions/corrupted.plist b/ios/chrome/test/data/sessions/corrupted.plist new file mode 100644 index 0000000..3f6938b --- /dev/null +++ b/ios/chrome/test/data/sessions/corrupted.plist Binary files differ
diff --git a/ios/chrome/test/data/testbadpass.pkpass b/ios/chrome/test/data/testbadpass.pkpass new file mode 100644 index 0000000..3f59060b --- /dev/null +++ b/ios/chrome/test/data/testbadpass.pkpass
@@ -0,0 +1 @@ +This isn't even a zip file, it's so bad!
diff --git a/ios/chrome/test/data/testpass.pkpass b/ios/chrome/test/data/testpass.pkpass new file mode 100644 index 0000000..098e4cd --- /dev/null +++ b/ios/chrome/test/data/testpass.pkpass Binary files differ
diff --git a/ios/chrome/test/data/webmock/somedomain.com/index.html b/ios/chrome/test/data/webmock/somedomain.com/index.html new file mode 100644 index 0000000..c974b66 --- /dev/null +++ b/ios/chrome/test/data/webmock/somedomain.com/index.html
@@ -0,0 +1,8 @@ +<html> +<head> + <title>Some domain homepage</title> +</head> +<body> + <h1>Some domain's homepage - Testing http protocol website interception</h1> +<body> +</html> \ No newline at end of file
diff --git a/ios/consumer/base/debugger.mm b/ios/consumer/base/debugger.mm new file mode 100644 index 0000000..ff2e2b3 --- /dev/null +++ b/ios/consumer/base/debugger.mm
@@ -0,0 +1,14 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/debug/debugger.h" +#include "ios/public/consumer/base/debugger.h" + +namespace ios { + +bool BeingDebugged() { + return base::debug::BeingDebugged(); +} + +} // namespace ios
diff --git a/ios/public/consumer/base/BUILD.gn b/ios/public/consumer/base/BUILD.gn index cc242cf..eb83ba2 100644 --- a/ios/public/consumer/base/BUILD.gn +++ b/ios/public/consumer/base/BUILD.gn
@@ -3,9 +3,8 @@ # found in the LICENSE file. source_set("base") { - configs += [ "//build/config/compiler:enable_arc" ] sources = [ - "//ios/consumer/base/debugger.cc", + "//ios/consumer/base/debugger.mm", "//ios/public/consumer/base/debugger.h", ] deps = [
diff --git a/ios/web/BUILD.gn b/ios/web/BUILD.gn index f2abbbc..cebb17f 100644 --- a/ios/web/BUILD.gn +++ b/ios/web/BUILD.gn
@@ -246,6 +246,7 @@ "//components/url_formatter", "//ios/net", "//ios/third_party/blink:html_tokenizer", + "//ios/web/public/image_fetcher", "//mojo/public/cpp/system", "//mojo/public/js", "//net",
diff --git a/ios/web/public/web_state/ui/crw_web_delegate.h b/ios/web/public/web_state/ui/crw_web_delegate.h index 2a7b2b0..71befcc9 100644 --- a/ios/web/public/web_state/ui/crw_web_delegate.h +++ b/ios/web/public/web_state/ui/crw_web_delegate.h
@@ -103,11 +103,6 @@ onFormResubmissionForRequest:(NSURLRequest*)request continueBlock:(ProceduralBlock)continueBlock cancelBlock:(ProceduralBlock)cancelBlock; -// Returns the unique id of the download request and starts downloading the -// image at |url| without sending the cookies. Invokes |callback| on completion. -- (int)downloadImageAtUrl:(const GURL&)url - maxBitmapSize:(uint32_t)maxBitmapSize - callback:(const web::WebState::ImageDownloadCallback&)callback; // --------------------------------------------------------------------- // TODO(rohitrao): Eliminate as many of the following delegate methods as
diff --git a/ios/web/web_state/DEPS b/ios/web/web_state/DEPS new file mode 100644 index 0000000..eaa61126 --- /dev/null +++ b/ios/web/web_state/DEPS
@@ -0,0 +1,4 @@ +include_rules = [ + "+skia/ext/skia_utils_ios.h", + "+third_party/skia/include/core/SkBitmap.h", +]
diff --git a/ios/web/web_state/web_state_impl.h b/ios/web/web_state/web_state_impl.h index d75eb41..5f01b93 100644 --- a/ios/web/web_state/web_state_impl.h +++ b/ios/web/web_state/web_state_impl.h
@@ -43,6 +43,7 @@ struct FaviconURL; struct LoadCommittedDetails; class NavigationManager; +class ImageDataFetcher; class WebInterstitialImpl; class WebStateDelegate; class WebStateFacadeDelegate; @@ -369,6 +370,9 @@ // Mojo interface registry for this WebState. std::unique_ptr<service_manager::InterfaceRegistry> mojo_interface_registry_; + // Image Fetcher used to images. + std::unique_ptr<ImageDataFetcher> image_fetcher_; + DISALLOW_COPY_AND_ASSIGN(WebStateImpl); };
diff --git a/ios/web/web_state/web_state_impl.mm b/ios/web/web_state/web_state_impl.mm index 2be7234..9d2dfa4 100644 --- a/ios/web/web_state/web_state_impl.mm +++ b/ios/web/web_state/web_state_impl.mm
@@ -16,6 +16,7 @@ #include "ios/web/navigation/navigation_item_impl.h" #include "ios/web/net/request_group_util.h" #include "ios/web/public/browser_state.h" +#import "ios/web/public/image_fetcher/image_data_fetcher.h" #import "ios/web/public/java_script_dialog_presenter.h" #include "ios/web/public/navigation_item.h" #include "ios/web/public/url_util.h" @@ -33,7 +34,10 @@ #import "ios/web/webui/web_ui_ios_controller_factory_registry.h" #import "ios/web/webui/web_ui_ios_impl.h" #include "net/http/http_response_headers.h" +#include "net/url_request/url_fetcher.h" #include "services/service_manager/public/cpp/interface_registry.h" +#include "skia/ext/skia_utils_ios.h" +#include "third_party/skia/include/core/SkBitmap.h" namespace web { @@ -63,6 +67,8 @@ weak_factory_(this) { GlobalWebStateEventTracker::GetInstance()->OnWebStateCreated(this); web_controller_.reset([[CRWWebController alloc] initWithWebState:this]); + image_fetcher_.reset(new ImageDataFetcher(web::WebThread::GetBlockingPool())); + image_fetcher_->SetRequestContextGetter(browser_state->GetRequestContext()); } WebStateImpl::~WebStateImpl() { @@ -538,9 +544,28 @@ // cookies or not. Currently, only downloads without cookies are supported. // |bypass_cache| is ignored since the downloads never go through a cache. DCHECK(is_favicon); - return [[web_controller_ delegate] downloadImageAtUrl:url - maxBitmapSize:max_bitmap_size - callback:callback]; + + static int downloaded_image_count = 0; + int local_download_id = ++downloaded_image_count; + __block web::WebState::ImageDownloadCallback local_image_callback = callback; + __block GURL local_url(url); + ImageFetchedCallback local_callback = + ^(const GURL&, const int response_code, NSData* data) { + std::vector<SkBitmap> frames; + std::vector<gfx::Size> sizes; + if (data) { + frames = skia::ImageDataToSkBitmaps(data); + for (auto& frame : frames) { + sizes.push_back(gfx::Size(frame.width(), frame.height())); + } + } + if (response_code != net::URLFetcher::RESPONSE_CODE_INVALID) { + local_image_callback.Run(local_download_id, response_code, local_url, + frames, sizes); + } + }; + image_fetcher_->StartDownload(url, local_callback); + return downloaded_image_count; } service_manager::InterfaceRegistry* WebStateImpl::GetMojoInterfaceRegistry() {
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc index eb21168..eda4275 100644 --- a/media/base/media_switches.cc +++ b/media/base/media_switches.cc
@@ -186,6 +186,10 @@ // Replaces WPMA by the MediaPlayerRenderer for HLS and fallback playback. const base::Feature kAndroidMediaPlayerRenderer{ "android-media-player-renderer", base::FEATURE_ENABLED_BY_DEFAULT}; + +// Lock the screen orientation when a video goes fullscreen. +const base::Feature kVideoFullscreenOrientationLock{ + "VideoFullscreenOrientationLock", base::FEATURE_DISABLED_BY_DEFAULT}; #endif } // namespace media
diff --git a/media/base/media_switches.h b/media/base/media_switches.h index 9dd347b..781e927 100644 --- a/media/base/media_switches.h +++ b/media/base/media_switches.h
@@ -94,6 +94,7 @@ #if defined(OS_ANDROID) MEDIA_EXPORT extern const base::Feature kAndroidMediaPlayerRenderer; +MEDIA_EXPORT extern const base::Feature kVideoFullscreenOrientationLock; #endif // defined(OS_ANDROID) } // namespace media
diff --git a/net/http/http_security_headers_unittest.cc b/net/http/http_security_headers_unittest.cc index 2d816f14..9203781 100644 --- a/net/http/http_security_headers_unittest.cc +++ b/net/http/http_security_headers_unittest.cc
@@ -789,9 +789,9 @@ std::string failure_log; // Damage the hashes to cause a pin validation failure. - new_static_pkp_state2.spki_hashes[0].data()[0] ^= 0x80; - new_static_pkp_state2.spki_hashes[1].data()[0] ^= 0x80; - new_static_pkp_state2.spki_hashes[2].data()[0] ^= 0x80; + for (size_t i = 0; i < new_static_pkp_state2.spki_hashes.size(); i++) { + new_static_pkp_state2.spki_hashes[i].data()[0] ^= 0x80; + } const bool is_issued_by_known_root = true; HostPortPair domain_port(domain, 443);
diff --git a/net/http/transport_security_state_static.h b/net/http/transport_security_state_static.h index d9bdee5..ddb0ada 100644 --- a/net/http/transport_security_state_static.h +++ b/net/http/transport_security_state_static.h
@@ -604,6 +604,7 @@ kSPKIHash_GoogleBackup2048, kSPKIHash_GoogleG2, kSPKIHash_GeoTrustGlobal, + kSPKIHash_GlobalSignRootCA_R2, NULL, }; static const char kGoogleReportURI[] = "http://clients3.google.com/cert_upload_json";
diff --git a/net/http/transport_security_state_static.json b/net/http/transport_security_state_static.json index 8805be8..367ef139 100644 --- a/net/http/transport_security_state_static.json +++ b/net/http/transport_security_state_static.json
@@ -60,7 +60,8 @@ "static_spki_hashes": [ "GoogleBackup2048", "GoogleG2", - "GeoTrustGlobal" + "GeoTrustGlobal", + "GlobalSignRootCA_R2" ], "report_uri": "http://clients3.google.com/cert_upload_json" },
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc index 28f8a1ee..7520a48 100644 --- a/net/url_request/url_request_http_job.cc +++ b/net/url_request/url_request_http_job.cc
@@ -1485,12 +1485,25 @@ total_time); } } + + UMA_HISTOGRAM_CUSTOM_COUNTS("Net.HttpJob.PrefilterBytesRead", + prefilter_bytes_read(), 1, 50000000, 50); if (response_info_->was_cached) { UMA_HISTOGRAM_TIMES("Net.HttpJob.TotalTimeCached", total_time); + UMA_HISTOGRAM_CUSTOM_COUNTS("Net.HttpJob.PrefilterBytesRead.Cache", + prefilter_bytes_read(), 1, 50000000, 50); + if (response_info_->unused_since_prefetch) UMA_HISTOGRAM_COUNTS("Net.Prefetch.HitBytes", prefilter_bytes_read()); } else { UMA_HISTOGRAM_TIMES("Net.HttpJob.TotalTimeNotCached", total_time); + UMA_HISTOGRAM_CUSTOM_COUNTS("Net.HttpJob.PrefilterBytesRead.Net", + prefilter_bytes_read(), 1, 50000000, 50); + + if (request_info_.load_flags & LOAD_PREFETCH) { + UMA_HISTOGRAM_COUNTS("Net.Prefetch.PrefilterBytesReadFromNetwork", + prefilter_bytes_read()); + } if (is_https_google) { if (used_quic) { UMA_HISTOGRAM_MEDIUM_TIMES( @@ -1503,10 +1516,6 @@ } } - if (request_info_.load_flags & LOAD_PREFETCH && !request_->was_cached()) - UMA_HISTOGRAM_COUNTS("Net.Prefetch.PrefilterBytesReadFromNetwork", - prefilter_bytes_read()); - start_time_ = base::TimeTicks(); }
diff --git a/services/navigation/navigation.h b/services/navigation/navigation.h index a48a91b6..af242e3 100644 --- a/services/navigation/navigation.h +++ b/services/navigation/navigation.h
@@ -15,10 +15,6 @@ #include "services/service_manager/public/cpp/service.h" #include "services/service_manager/public/cpp/service_context_ref.h" -namespace content { -class BrowserContext; -} - namespace navigation { std::unique_ptr<service_manager::Service> CreateNavigationService();
diff --git a/services/preferences/public/cpp/pref_observer_store.h b/services/preferences/public/cpp/pref_observer_store.h index 16f9fe5d..1e408e1 100644 --- a/services/preferences/public/cpp/pref_observer_store.h +++ b/services/preferences/public/cpp/pref_observer_store.h
@@ -13,10 +13,6 @@ #include "mojo/public/cpp/bindings/binding.h" #include "services/preferences/public/interfaces/preferences.mojom.h" -namespace shell { -class Connector; -} - class PrefObserverStoreTest; // An implementation of PrefStore which uses prefs::mojom::PreferenceManager as
diff --git a/services/ui/gpu/gpu_service_internal.h b/services/ui/gpu/gpu_service_internal.h index f6b3c60..8fd4603 100644 --- a/services/ui/gpu/gpu_service_internal.h +++ b/services/ui/gpu/gpu_service_internal.h
@@ -25,7 +25,6 @@ #include "ui/gfx/native_widget_types.h" namespace gpu { -class GpuChannelHost; class GpuMemoryBufferFactory; class GpuWatchdogThread; class SyncPointManager;
diff --git a/services/ui/public/cpp/context_provider.h b/services/ui/public/cpp/context_provider.h index c4949635..348d7cd 100644 --- a/services/ui/public/cpp/context_provider.h +++ b/services/ui/public/cpp/context_provider.h
@@ -17,10 +17,6 @@ class GpuChannelHost; } -namespace service_manager { -class Connector; -} - namespace ui { class GLES2Context;
diff --git a/services/ui/public/cpp/gpu/mojo_gpu_memory_buffer_manager.h b/services/ui/public/cpp/gpu/mojo_gpu_memory_buffer_manager.h index 217783f..d1f5e339 100644 --- a/services/ui/public/cpp/gpu/mojo_gpu_memory_buffer_manager.h +++ b/services/ui/public/cpp/gpu/mojo_gpu_memory_buffer_manager.h
@@ -19,10 +19,6 @@ class WaitableEvent; } -namespace service_manager { -class Connector; -} - namespace ui { namespace mojom {
diff --git a/services/ui/public/cpp/tests/test_window_tree_client_setup.h b/services/ui/public/cpp/tests/test_window_tree_client_setup.h index e7146f9..c2527aa 100644 --- a/services/ui/public/cpp/tests/test_window_tree_client_setup.h +++ b/services/ui/public/cpp/tests/test_window_tree_client_setup.h
@@ -9,10 +9,6 @@ #include "base/macros.h" -namespace display { -class Display; -} - namespace ui { class TestWindowTree;
diff --git a/services/ui/public/cpp/window.h b/services/ui/public/cpp/window.h index d2d6638..015540c 100644 --- a/services/ui/public/cpp/window.h +++ b/services/ui/public/cpp/window.h
@@ -21,10 +21,6 @@ #include "ui/gfx/geometry/insets.h" #include "ui/gfx/geometry/rect.h" -namespace gfx { -class Size; -} - namespace gpu { class GpuMemoryBufferManager; } @@ -32,11 +28,9 @@ namespace ui { class InputEventHandler; -class ServiceProviderImpl; class SurfaceIdHandler; class WindowCompositorFrameSinkBinding; class WindowObserver; -class WindowSurface; class WindowDropTarget; class WindowTreeClient; class WindowTreeClientPrivate;
diff --git a/services/ui/public/cpp/window_compositor_frame_sink.cc b/services/ui/public/cpp/window_compositor_frame_sink.cc index 4c2e86352..2d89373 100644 --- a/services/ui/public/cpp/window_compositor_frame_sink.cc +++ b/services/ui/public/cpp/window_compositor_frame_sink.cc
@@ -115,7 +115,6 @@ void WindowCompositorFrameSink::WillDrawSurface() { // TODO(fsamuel, staraz): Implement this. - NOTIMPLEMENTED(); } void WindowCompositorFrameSink::OnNeedsBeginFrames(bool needs_begin_frames) {
diff --git a/services/ui/public/cpp/window_compositor_frame_sink.h b/services/ui/public/cpp/window_compositor_frame_sink.h index 8eac511a..1ea8e8c3 100644 --- a/services/ui/public/cpp/window_compositor_frame_sink.h +++ b/services/ui/public/cpp/window_compositor_frame_sink.h
@@ -14,10 +14,6 @@ #include "cc/surfaces/surface_id_allocator.h" #include "mojo/public/cpp/bindings/binding.h" -namespace gpu { -class GpuChannelHost; -} - namespace ui { class WindowCompositorFrameSinkBinding;
diff --git a/services/ui/public/cpp/window_tree_client_delegate.h b/services/ui/public/cpp/window_tree_client_delegate.h index 3664ac28..6f52db0 100644 --- a/services/ui/public/cpp/window_tree_client_delegate.h +++ b/services/ui/public/cpp/window_tree_client_delegate.h
@@ -11,10 +11,6 @@ #include "services/ui/public/interfaces/window_tree.mojom.h" namespace ui { -class Event; -} - -namespace ui { class Window; class WindowTreeClient;
diff --git a/services/ui/service.h b/services/ui/service.h index 30606d8..e8b250b 100644 --- a/services/ui/service.h +++ b/services/ui/service.h
@@ -44,10 +44,6 @@ class ScreenManager; } -namespace gfx { -class Rect; -} - namespace service_manager { class Connector; } @@ -57,7 +53,6 @@ class PlatformEventSource; namespace ws { -class ForwardingWindowManager; class WindowServer; }
diff --git a/services/ui/ws/event_dispatcher.h b/services/ui/ws/event_dispatcher.h index bcb7053f..67572d0d 100644 --- a/services/ui/ws/event_dispatcher.h +++ b/services/ui/ws/event_dispatcher.h
@@ -33,7 +33,6 @@ class DragTargetConnection; class EventDispatcherDelegate; class ServerWindow; -class WindowTree; namespace test { class EventDispatcherTestApi;
diff --git a/services/ui/ws/focus_controller.h b/services/ui/ws/focus_controller.h index 190f60e..7cf76e6c 100644 --- a/services/ui/ws/focus_controller.h +++ b/services/ui/ws/focus_controller.h
@@ -20,7 +20,6 @@ class FocusControllerObserver; class ServerWindow; class ServerWindowDrawnTracker; -struct WindowId; // Describes the source of the change. enum class FocusControllerChangeSource {
diff --git a/services/ui/ws/frame_generator.cc b/services/ui/ws/frame_generator.cc index fab84683..0c869ea 100644 --- a/services/ui/ws/frame_generator.cc +++ b/services/ui/ws/frame_generator.cc
@@ -127,7 +127,6 @@ void FrameGenerator::WillDrawSurface() { // TODO(fsamuel, staraz): Implement this. - NOTIMPLEMENTED(); } cc::CompositorFrame FrameGenerator::GenerateCompositorFrame(
diff --git a/services/ui/ws/frame_generator.h b/services/ui/ws/frame_generator.h index e2272f4..a9e822e4 100644 --- a/services/ui/ws/frame_generator.h +++ b/services/ui/ws/frame_generator.h
@@ -27,10 +27,6 @@ class SurfaceId; } -namespace gpu { -class GpuChannelHost; -} - namespace ui { class DisplayCompositor;
diff --git a/services/ui/ws/gpu_service_proxy_delegate.h b/services/ui/ws/gpu_service_proxy_delegate.h index 6f18646..c7b5a94 100644 --- a/services/ui/ws/gpu_service_proxy_delegate.h +++ b/services/ui/ws/gpu_service_proxy_delegate.h
@@ -7,10 +7,6 @@ #include "base/memory/ref_counted.h" -namespace gpu { -class GpuChannelHost; -} - namespace ui { namespace ws {
diff --git a/services/ui/ws/platform_display.h b/services/ui/ws/platform_display.h index 9b64222e..96b1ca9 100644 --- a/services/ui/ws/platform_display.h +++ b/services/ui/ws/platform_display.h
@@ -18,10 +18,6 @@ class Rect; } -namespace gpu { -class GpuChannelHost; -} - namespace ui { struct TextInputState;
diff --git a/services/ui/ws/platform_display_delegate.h b/services/ui/ws/platform_display_delegate.h index e6eb597..98b944e2 100644 --- a/services/ui/ws/platform_display_delegate.h +++ b/services/ui/ws/platform_display_delegate.h
@@ -5,10 +5,6 @@ #ifndef SERVICES_UI_WS_PLATFORM_DISPLAY_DELEGATE_H_ #define SERVICES_UI_WS_PLATFORM_DISPLAY_DELEGATE_H_ -namespace gfx { -class Size; -} - namespace ui { class Event;
diff --git a/services/ui/ws/server_window.h b/services/ui/ws/server_window.h index dd508642..6adfb97 100644 --- a/services/ui/ws/server_window.h +++ b/services/ui/ws/server_window.h
@@ -23,10 +23,6 @@ #include "ui/gfx/transform.h" #include "ui/platform_window/text_input_state.h" -namespace gpu { -class GpuMemoryBufferManager; -} - namespace ui { namespace ws {
diff --git a/services/ui/ws/server_window_compositor_frame_sink_manager.h b/services/ui/ws/server_window_compositor_frame_sink_manager.h index d2db13e..8461ebb 100644 --- a/services/ui/ws/server_window_compositor_frame_sink_manager.h +++ b/services/ui/ws/server_window_compositor_frame_sink_manager.h
@@ -14,10 +14,6 @@ #include "mojo/public/cpp/bindings/binding.h" #include "services/ui/public/interfaces/window_tree.mojom.h" -namespace gpu { -class GpuMemoryBufferManager; -} - namespace ui { namespace ws {
diff --git a/services/ui/ws/server_window_delegate.h b/services/ui/ws/server_window_delegate.h index 08db68f..26784fa 100644 --- a/services/ui/ws/server_window_delegate.h +++ b/services/ui/ws/server_window_delegate.h
@@ -21,9 +21,7 @@ namespace ws { -struct ClientWindowId; class ServerWindow; -struct WindowId; class ServerWindowDelegate { public:
diff --git a/services/ui/ws/test_server_window_delegate.h b/services/ui/ws/test_server_window_delegate.h index 8d63b62..4c8d851 100644 --- a/services/ui/ws/test_server_window_delegate.h +++ b/services/ui/ws/test_server_window_delegate.h
@@ -18,8 +18,6 @@ namespace ws { -struct WindowId; - class TestServerWindowDelegate : public ServerWindowDelegate { public: TestServerWindowDelegate();
diff --git a/services/ui/ws/user_display_manager_delegate.h b/services/ui/ws/user_display_manager_delegate.h index 0bbeb78..671d0b7 100644 --- a/services/ui/ws/user_display_manager_delegate.h +++ b/services/ui/ws/user_display_manager_delegate.h
@@ -11,9 +11,6 @@ namespace ui { namespace ws { -class Display; -class WindowManagerState; - class UserDisplayManagerDelegate { public: // Gets the frame decorations for the specified user. Returns true if the
diff --git a/services/ui/ws/window_manager_display_root.h b/services/ui/ws/window_manager_display_root.h index 279982fe..2ba39a0 100644 --- a/services/ui/ws/window_manager_display_root.h +++ b/services/ui/ws/window_manager_display_root.h
@@ -19,10 +19,6 @@ class WindowManagerState; class WindowServer; -namespace test { -class WindowManagerDisplayRootTestApi; -} - // Owns the root window of a window manager for one display. Each window manager // has one WindowManagerDisplayRoot for each Display. The root window is // parented to the root of a Display.
diff --git a/services/ui/ws/window_manager_window_tree_factory.h b/services/ui/ws/window_manager_window_tree_factory.h index 252fdf5..df5c4b0e 100644 --- a/services/ui/ws/window_manager_window_tree_factory.h +++ b/services/ui/ws/window_manager_window_tree_factory.h
@@ -14,7 +14,6 @@ namespace ui { namespace ws { -class ServerWindow; class WindowManagerWindowTreeFactorySet; class WindowServer; class WindowTree;
diff --git a/services/ui/ws/window_server_delegate.h b/services/ui/ws/window_server_delegate.h index 802dbd7..717c512 100644 --- a/services/ui/ws/window_server_delegate.h +++ b/services/ui/ws/window_server_delegate.h
@@ -17,14 +17,12 @@ namespace ui { namespace mojom { -class WindowManagerFactory; class WindowTree; } namespace ws { class Display; -class ServerWindow; class WindowServer; class WindowTree; class WindowTreeBinding;
diff --git a/services/ui/ws/window_server_test_impl.h b/services/ui/ws/window_server_test_impl.h index ffeb550..9a6dc78 100644 --- a/services/ui/ws/window_server_test_impl.h +++ b/services/ui/ws/window_server_test_impl.h
@@ -12,8 +12,6 @@ class ServerWindow; class WindowServer; -class WindowTree; -struct WindowId; class WindowServerTestImpl : public mojom::WindowServerTest { public:
diff --git a/services/ui/ws/window_tree.h b/services/ui/ws/window_tree.h index 5204624b..0331e1b 100644 --- a/services/ui/ws/window_tree.h +++ b/services/ui/ws/window_tree.h
@@ -43,13 +43,11 @@ class DisplayManager; class Display; class DragTargetConnection; -class EventMatcher; class ServerWindow; class TargetedEvent; class WindowManagerDisplayRoot; class WindowManagerState; class WindowServer; -class WindowTreeTest; namespace test { class WindowTreeTestApi;
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index 6a54c4ae..c9d2be46 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -505,8 +505,6 @@ crbug.com/659123 [ Mac ] fast/css/text-overflow-ellipsis-button.html [ Pass Failure ] -crbug.com/670295 virtual/mojo-loading/http/tests/preload/external_css_import_preload.html [ Pass Failure ] - # TODO(oshima): Mac Android are currently not supported. crbug.com/567837 [ Mac Android ] virtual/scalefactor200withzoom/fast/hidpi/static [ Skip ]
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-2d-isPointInPath-isPointInStroke.html b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-2d-isPointInPath-isPointInStroke.html new file mode 100644 index 0000000..de0e1efb --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-2d-isPointInPath-isPointInStroke.html
@@ -0,0 +1,35 @@ +<!DOCTYPE HTML> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script> +test(function() { + var offscreenCanvas = new OffscreenCanvas(100, 50); + var ctx = offscreenCanvas.getContext('2d'); + + ctx.rect(0, 0, 20, 20); + assert_true(ctx.isPointInPath(10, 10)); + assert_false(ctx.isPointInPath(30, 10)); + + var path = new Path2D(); + path.rect(20, 20, 100, 100); + assert_true(ctx.isPointInPath(path, 20, 20)); + assert_false(ctx.isPointInPath(path, 130, 20)); +}, 'Test the behavior of isPointInPath APIs for OffscreenCanvas'); + + +test(function() { + var offscreenCanvas = new OffscreenCanvas(100, 50); + var ctx = offscreenCanvas.getContext('2d'); + + ctx.strokeStyle = '#0f0'; + ctx.beginPath(); + ctx.rect(0, 0, 20, 20); + assert_true(ctx.isPointInStroke(0, 0)); + assert_false(ctx.isPointInStroke(30, 10)); + + var path = new Path2D(); + path.rect(20, 20, 100, 100); + assert_true(ctx.isPointInStroke(path, 20, 20)); + assert_true(ctx.isPointInStroke(path, 120, 20)); +}, 'Test the behavior of isPointInStroke APIs for OffscreenCanvas'); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/events/autoscroll-disabled-user-select-none.html b/third_party/WebKit/LayoutTests/fast/events/autoscroll-disabled-user-select-none.html new file mode 100644 index 0000000..689cdbe --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/events/autoscroll-disabled-user-select-none.html
@@ -0,0 +1,33 @@ +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<div id="container" style="height: 400px; overflow: auto;"> + <div style="-webkit-user-select:none; height: 2000px; background-color: yellow"> + Hello World! Hello Woorld! Hello Wooorld! Hello Woooorld!<br /> + Hello World! Hello Woorld! Hello Wooorld! Hello Woooorld!<br /> + Hello World! Hello Woorld! Hello Wooorld! Hello Woooorld!<br /> + Hello World! Hello Woorld! Hello Wooorld! Hello Woooorld!<br /> + Hello World! Hello Woorld! Hello Wooorld! Hello Woooorld!<br /> + </div> +</div> +<script> +var testSelectNone = async_test("Selection-autoscroll should not be triggered when the selection happens in an element with user-select:none"); +testSelectNone.step(function() { + if (!window.eventSender) + return; + var dragStartX = 50; + var dragStartY = 50; + var dragEndX = 60; + var dragEndY = 400; + var container = document.getElementById("container"); + + eventSender.dragMode = false; + eventSender.mouseMoveTo(dragStartX, dragStartY); + eventSender.mouseDown(); + eventSender.mouseMoveTo(dragEndX, dragEndY); + + requestAnimationFrame(function() { + assert_equals(container.scrollTop, 0); + testSelectNone.done(); + }); +}); +</script> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/forms/text/input-readonly-autoscroll.html b/third_party/WebKit/LayoutTests/fast/forms/text/input-readonly-autoscroll.html index f8ef7b87..8106051c 100644 --- a/third_party/WebKit/LayoutTests/fast/forms/text/input-readonly-autoscroll.html +++ b/third_party/WebKit/LayoutTests/fast/forms/text/input-readonly-autoscroll.html
@@ -17,7 +17,7 @@ eventSender.dragMode = false; eventSender.mouseMoveTo(20, h); eventSender.mouseDown(); - eventSender.mouseMoveTo(20, h); + eventSender.mouseMoveTo(40, h); eventSender.mouseMoveTo(300, h); } setTimeout(autoscrollTestPart2, 100);
diff --git a/third_party/WebKit/LayoutTests/media/preload-conditions.html b/third_party/WebKit/LayoutTests/http/tests/media/preload-conditions.html similarity index 97% rename from third_party/WebKit/LayoutTests/media/preload-conditions.html rename to third_party/WebKit/LayoutTests/http/tests/media/preload-conditions.html index 8e550820..2d015eac 100644 --- a/third_party/WebKit/LayoutTests/media/preload-conditions.html +++ b/third_party/WebKit/LayoutTests/http/tests/media/preload-conditions.html
@@ -2,7 +2,7 @@ <title>Test media preloading behaviour with different conditions.</title> <script src="../resources/testharness.js"></script> <script src="../resources/testharnessreport.js"></script> -<script src="media-file.js"></script> +<script src="../../media-resources/media-file.js"></script> <script> var tests = [ { @@ -135,7 +135,7 @@ [ '', 'none', 'metadata', 'auto' ].forEach(preload => { var media = document.createElement('video'); media.preload = preload; - media.src = findMediaFile('video', 'content/test'); + media.src = findMediaFile('video', 'resources/test'); assert_equals(media.readyState, HTMLMediaElement.HAVE_NOTHING); switch (media.preload) {
diff --git a/third_party/WebKit/LayoutTests/http/tests/media/video-controls-overflow-menu-updates-appropriately.html b/third_party/WebKit/LayoutTests/http/tests/media/video-controls-overflow-menu-updates-appropriately.html index e02af246..a4ace4f 100644 --- a/third_party/WebKit/LayoutTests/http/tests/media/video-controls-overflow-menu-updates-appropriately.html +++ b/third_party/WebKit/LayoutTests/http/tests/media/video-controls-overflow-menu-updates-appropriately.html
@@ -1,27 +1,29 @@ <!DOCTYPE html> <title>Overflow menu updates properly.</title> -<script src="../resources/testharness.js"></script> -<script src="../resources/testharnessreport.js"></script> -<script src="../../media-resources/media-controls.js"></script> -<script src="../../media-resources/media-file.js"></script> -<script src="../../media-resources/overflow-menu.js"></script> +<script src='../resources/testharness.js'></script> +<script src='../resources/testharnessreport.js'></script> +<script src='../../media-resources/media-controls.js'></script> +<script src='../../media-resources/media-file.js'></script> +<script src='../../media-resources/overflow-menu.js'></script> <!--Padding ensures the overflow menu is visible for the tests. --> -<body style="padding-top: 200px; padding-left: 100px"> +<body style='padding-top: 200px; padding-left: 100px'> <video controls></video> <script> -async_test(function(t) { +async_test(t => { + assert_true('internals' in window, 'window.internals must be available'); + // Set up video - var video = document.querySelector("video"); - video.src = findMediaFile("video", "resources/test"); - video.setAttribute("width", "60"); + var video = document.querySelector('video'); + video.src = findMediaFile('video', 'resources/test'); + video.setAttribute('width', '60'); // Add captions - var trackElement = document.createElement("track"); + var trackElement = document.createElement('track'); video.appendChild(trackElement); // Pretend we have a cast device internals.mediaPlayerRemoteRouteAvailabilityChanged(video, true); - video.onloadeddata = t.step_func_done(function() { + video.onloadeddata = t.step_func(_ => { var overflowList = getOverflowList(video); // Remove cast device and ensure the overflow menu updates as expected @@ -35,19 +37,22 @@ // Ensure that all of the buttons are visible in the right order for (var i = 0; i < children.length; i++) { var child = children[i]; - if (buttonsWithoutCast[i]) { - assert_not_equals(getComputedStyle(child).display, "none"); - } else { - assert_equals(getComputedStyle(child).display, "none"); - } + if (buttonsWithoutCast[i]) + assert_not_equals(getComputedStyle(child).display, 'none'); + else + assert_equals(getComputedStyle(child).display, 'none'); } internals.mediaPlayerRemoteRouteAvailabilityChanged(video, true); - assert_not_equals(getComputedStyle(children[OverflowMenuButtons.CAST]).display, "none"); + assert_not_equals(getComputedStyle(children[OverflowMenuButtons.CAST]).display, 'none'); // Removing closed captions hides button in overflow menu - assert_not_equals(getComputedStyle(children[OverflowMenuButtons.CLOSED_CAPTIONS]).display, "none"); + assert_not_equals(getComputedStyle(children[OverflowMenuButtons.CLOSED_CAPTIONS]).display, 'none'); video.removeChild(trackElement); - assert_equals(getComputedStyle(children[OverflowMenuButtons.CLOSED_CAPTIONS]).display, "none"); + + // The controls are updated asynchronously. + setTimeout(t.step_func_done(_ => { + assert_equals(getComputedStyle(children[OverflowMenuButtons.CLOSED_CAPTIONS]).display, 'none'); + })); }); }); </script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt index 27fa54e8..9e7b6d96 100644 --- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -525,6 +525,8 @@ method fillRect method getImageData method getLineDash + method isPointInPath + method isPointInStroke method lineTo method moveTo method putImageData
diff --git a/third_party/WebKit/LayoutTests/media/controls/closed-captions-dynamic-update.html b/third_party/WebKit/LayoutTests/media/controls/closed-captions-dynamic-update.html new file mode 100644 index 0000000..dc9d80d2 --- /dev/null +++ b/third_party/WebKit/LayoutTests/media/controls/closed-captions-dynamic-update.html
@@ -0,0 +1,72 @@ +<!DOCTYPE html> +<title>Tests that the closed captions button enables track switching.</title> +<script src='../../resources/testharness.js'></script> +<script src='../../resources/testharnessreport.js'></script> +<script src='../media-file.js'></script> +<script src='../media-controls.js'></script> +<video controls> + <track src='../track/captions-webvtt/captions-fast.vtt' kind='captions'> + <track src='../track/captions-webvtt/captions-rtl.vtt' kind='captions'> +</video> +<script> +async_test(t => { + var video = document.querySelector('video'); + + video.oncanplaythrough = t.step_func(_ => { + assert_true(isClosedCaptionsButtonVisible(video)); + + // The captions track should be listed in textTracks, but not yet loaded. + assert_equals(video.textTracks.length, 2); + assert_equals(video.textTracks[0].mode, 'disabled'); + assert_equals(video.textTracks[1].mode, 'disabled'); + assert_equals(textTrackContainerElement(video), null); + + var tracks = document.querySelectorAll('track'); + tracks[0].onload = t.step_func(_ => { + assert_equals(textTrackDisplayElement(video).innerText, 'Lorem'); + + // Captions should not be visible after Off is clicked. + turnClosedCaptionsOff(video); + assert_equals(textTrackDisplayElement(video), null); + + // Remove the track elements. + tracks[1].remove(); + tracks[0].remove(); + + // The controls are updated asynchronously. + setTimeout(t.step_func(_ => { + assert_false(isClosedCaptionsButtonVisible(video)); + + // Add non-default text track through HTML with unloadable URI. + var track = document.createElement('track'); + track.setAttribute('src', 'invalid.vtt'); + + track.onerror = t.step_func(_ => { + // Track failed to load. + assert_false(isClosedCaptionsButtonVisible(video)); + // Add a text track through JS to the video element. + var newTrack = video.addTextTrack('captions', 'English', 'en'); + setTimeout(t.step_func_done(_ => { + assert_true(isClosedCaptionsButtonVisible(video)); + })); + }); + + video.appendChild(track); + assert_equals(track.readyState, HTMLTrackElement.NONE); + assert_equals(track.track.mode, 'disabled'); + assert_equals(video.textTracks.length, 1); + + setTimeout(t.step_func(_ => { + assert_true(isClosedCaptionsButtonVisible(video)); + clickTextTrackAtIndex(video, 0); + })); + })); + }); + + // Captions track should load and captions should become visible after a track is selected. + clickTextTrackAtIndex(video, 0); + }); + + video.src = findMediaFile('video', '../content/counting'); +}); +</script>
diff --git a/third_party/WebKit/LayoutTests/media/controls/closed-captions-on-off.html b/third_party/WebKit/LayoutTests/media/controls/closed-captions-on-off.html new file mode 100644 index 0000000..8558d03 --- /dev/null +++ b/third_party/WebKit/LayoutTests/media/controls/closed-captions-on-off.html
@@ -0,0 +1,50 @@ +<!DOCTYPE html> +<title>Tests that tracks can be turned on and off through the track selection menu.</title> +<script src='../../resources/testharness.js'></script> +<script src='../../resources/testharnessreport.js'></script> +<script src='../media-controls.js'></script> +<script src='../media-file.js'></script> +<video controls></video> +<script> +async_test(t => { + var captions = ['First', 'Second', 'Third']; + var video = document.querySelector('video'); + + video.oncanplaythrough = t.step_func(_ => { + var track1 = video.addTextTrack('captions'); + var track2 = video.addTextTrack('captions'); + + for (var i = 0; i < captions.length; ++i) { + track1.addCue(new VTTCue(0, 120, captions[i])); + track2.addCue(new VTTCue(0, 120, captions[i])); + } + + // The controls are updated asynchronously. + assert_false(isClosedCaptionsButtonVisible(video)); + + setTimeout(t.step_func_done(_ => { + assert_true(isClosedCaptionsButtonVisible(video)); + + // The captions track should be listed in textTracks, but not yet loaded. + assert_equals(video.textTracks.length, 2); + assert_equals(video.textTracks[0].mode, 'hidden'); + assert_equals(video.textTracks[1].mode, 'hidden'); + checkCaptionsHidden(video); + + // Captions track should become visible after the track is selected. + clickTextTrackAtIndex(video, 0); + checkCaptionsVisible(video, captions); + + // Captions should not be visible after they're turned off through the menu. + turnClosedCaptionsOff(video); + checkCaptionsHidden(video); + + // Captions track should become visible after the track is selected again. + clickTextTrackAtIndex(video, 0); + checkCaptionsVisible(video, captions); + })); + }); + + video.src = findMediaFile('video', '../content/counting'); +}); +</script>
diff --git a/third_party/WebKit/LayoutTests/media/controls/closed-captions-single-track.html b/third_party/WebKit/LayoutTests/media/controls/closed-captions-single-track.html new file mode 100644 index 0000000..4c58267 --- /dev/null +++ b/third_party/WebKit/LayoutTests/media/controls/closed-captions-single-track.html
@@ -0,0 +1,51 @@ +<!DOCTYPE html> +<title>A single track should not show overflow on caption button-press, instead just toggle.</title> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script src="../media-controls.js"></script> +<script src="../media-file.js"></script> +<video controls></video> +<script> +async_test(t => { + var captions = ["Caption"]; + var video = document.querySelector("video"); + + video.oncanplaythrough = t.step_func(_ => { + var track1 = video.addTextTrack("captions"); + + for (var i = 0; i < captions.length; ++i) + track1.addCue(new VTTCue(0, 120, captions[i])); + + // The controls are updated asynchronously. + assert_false(isClosedCaptionsButtonVisible(video)); + + setTimeout(t.step_func_done(_ => { + assert_true(isClosedCaptionsButtonVisible(video)); + + // The captions track should be listed in textTracks, but not yet loaded. + assert_equals(video.textTracks.length, 1); + assert_equals(video.textTracks[0].mode, "hidden"); + checkCaptionsHidden(video); + + // Get the menu that displays the list of text tracks. + var captionsList = mediaControlsElement(internals.shadowRoot(video).firstChild, + "-internal-media-controls-text-track-list"); + + clickCaptionButton(video); + assert_equals(getComputedStyle(captionsList).display, "none"); + + // Captions track should become visible after the closed caption button is pressed. + checkCaptionsVisible(video, captions); + + // Click the closed captions button again and make sure the menu does not appear. + clickCaptionButton(video); + assert_equals(getComputedStyle(captionsList).display, "none"); + + // Captions track should become invisible after the closed caption button is pressed. + checkCaptionsHidden(video); + })); + }); + + video.src = findMediaFile("video", "../content/counting"); +}); +</script>
diff --git a/third_party/WebKit/LayoutTests/media/controls/closed-captions-switch-track.html b/third_party/WebKit/LayoutTests/media/controls/closed-captions-switch-track.html new file mode 100644 index 0000000..2915e3f3 --- /dev/null +++ b/third_party/WebKit/LayoutTests/media/controls/closed-captions-switch-track.html
@@ -0,0 +1,43 @@ +<!DOCTYPE html> +<title>Test that we can add multiple tracks and select between them from the track selection menu.</title> +<script src='../../resources/testharness.js'></script> +<script src='../../resources/testharnessreport.js'></script> +<script src='../media-file.js'></script> +<script src='../media-controls.js'></script> +<!-- Width should be large enough to display closed captions button. --> +<video controls style='width: 500px'></video> +<script> +async_test(t => { + var video = document.querySelector('video'); + var trackLanguages = ['en', 'ru', 'fr', 'jp', 'de']; + var trackCueText = ['English', 'Russian', 'French', 'Japanese', 'German']; + + video.oncanplaythrough = t.step_func(_ => { + for (var i = 0; i < trackLanguages.length; i++) { + var track = video.addTextTrack('captions', trackCueText[i], trackLanguages[i]); + track.addCue(new VTTCue(0, 1, trackCueText[i])); + track.mode = 'disabled'; + } + + // The controls are updated asynchronously. + assert_false(isClosedCaptionsButtonVisible(video)); + + setTimeout(t.step_func_done(_ => { + assert_true(isClosedCaptionsButtonVisible(video)); + assert_equals(video.textTracks.length, trackLanguages.length); + + for (var i = 0; i < trackLanguages.length; i++) { + clickTextTrackAtIndex(video, i); + assert_equals(video.textTracks[i].mode, 'showing'); + assert_equals(textTrackDisplayElement(video).innerText, trackCueText[i]); + for (var j = 0; j < trackLanguages.length; j++) { + if (j != i) + assert_equals(video.textTracks[j].mode, 'disabled'); + } + } + })); + }); + + video.src = findMediaFile('video', '../content/test'); +}); +</script>
diff --git a/third_party/WebKit/LayoutTests/media/track/text-track-selection-menu-multiple-tracks.html b/third_party/WebKit/LayoutTests/media/track/text-track-selection-menu-multiple-tracks.html deleted file mode 100644 index bd3e75fb..0000000 --- a/third_party/WebKit/LayoutTests/media/track/text-track-selection-menu-multiple-tracks.html +++ /dev/null
@@ -1,37 +0,0 @@ -<!DOCTYPE html> -<title>Test that we can add multiple tracks and select between them from the track selection menu.</title> -<script src="../../resources/testharness.js"></script> -<script src="../../resources/testharnessreport.js"></script> -<script src="../media-file.js"></script> -<script src="../media-controls.js"></script> -<!-- Width should be large enough to display closed captions button. --> -<video controls style="width: 500px"></video> -<script> -async_test(function(t) { - var video = document.querySelector("video"); - var trackLanguages = ["en", "ru", "fr", "jp", "de"]; - var trackCueText = ["English", "Russian", "French", "Japanese", "German"]; - - video.oncanplaythrough = t.step_func_done(function() { - for (var i = 0; i < trackLanguages.length; i++) { - var track = video.addTextTrack("captions", trackCueText[i], trackLanguages[i]); - track.addCue(new VTTCue(0, 1, trackCueText[i])); - track.mode = "disabled"; - } - assert_true(isClosedCaptionsButtonVisible(video)); - assert_equals(video.textTracks.length, trackLanguages.length); - - for (var i = 0; i < trackLanguages.length; i++) { - clickTextTrackAtIndex(video, i); - assert_equals(video.textTracks[i].mode, "showing"); - assert_equals(textTrackDisplayElement(video).innerText, trackCueText[i]); - for (var j = 0; j < trackLanguages.length; j++) { - if (j != i) - assert_equals(video.textTracks[j].mode, "disabled"); - } - } - }); - - video.src = findMediaFile("video", "../content/test"); -}); -</script>
diff --git a/third_party/WebKit/LayoutTests/media/video-controls-caption-single-track.html b/third_party/WebKit/LayoutTests/media/video-controls-caption-single-track.html deleted file mode 100644 index daf4f20..0000000 --- a/third_party/WebKit/LayoutTests/media/video-controls-caption-single-track.html +++ /dev/null
@@ -1,46 +0,0 @@ -<!DOCTYPE html> -<title>A single track should not show overflow on caption button-press, instead just toggle.</title> -<script src="../resources/testharness.js"></script> -<script src="../resources/testharnessreport.js"></script> -<script src="media-controls.js"></script> -<script src="media-file.js"></script> -<video controls></video> -<script> -async_test(function(t) { - var captions = ["Caption"]; - var video = document.querySelector("video"); - - video.oncanplaythrough = t.step_func_done(function() { - var track1 = video.addTextTrack("captions"); - - for (var i = 0; i < captions.length; i++) { - track1.addCue(new VTTCue(0, 120, captions[i])); - } - assert_true(isClosedCaptionsButtonVisible(video)); - - // The captions track should be listed in textTracks, but not yet loaded. - assert_equals(video.textTracks.length, 1); - assert_equals(video.textTracks[0].mode, "hidden"); - checkCaptionsHidden(video); - - // Get the menu that displays the list of text tracks. - var captionsList = mediaControlsElement(internals.shadowRoot(video).firstChild, - "-internal-media-controls-text-track-list"); - - clickCaptionButton(video); - assert_equals(getComputedStyle(captionsList).display, "none"); - - // Captions track should become visible after the closed caption button is pressed. - checkCaptionsVisible(video, captions); - - // Click the closed captions button again and make sure the menu does not appear. - clickCaptionButton(video); - assert_equals(getComputedStyle(captionsList).display, "none"); - - // Captions track should become visible after the closed caption button is pressed. - checkCaptionsHidden(video); - }); - - video.src = findMediaFile("video", "content/counting"); -}); -</script>
diff --git a/third_party/WebKit/LayoutTests/media/video-controls-captions-on-off.html b/third_party/WebKit/LayoutTests/media/video-controls-captions-on-off.html deleted file mode 100644 index 49906b1..0000000 --- a/third_party/WebKit/LayoutTests/media/video-controls-captions-on-off.html +++ /dev/null
@@ -1,43 +0,0 @@ -<!DOCTYPE html> -<title>Tests that tracks can be turned on and off through the track selection menu.</title> -<script src="../resources/testharness.js"></script> -<script src="../resources/testharnessreport.js"></script> -<script src="media-controls.js"></script> -<script src="media-file.js"></script> -<video controls></video> -<script> -async_test(function(t) { - var captions = ["First", "Second", "Third"]; - var video = document.querySelector("video"); - - video.oncanplaythrough = t.step_func_done(function() { - var track1 = video.addTextTrack("captions"); - var track2 = video.addTextTrack("captions"); - - for (var i = 0; i < captions.length; i++) { - track1.addCue(new VTTCue(0, 120, captions[i])); - track2.addCue(new VTTCue(0, 120, captions[i])); - } - assert_true(isClosedCaptionsButtonVisible(video)); - - // The captions track should be listed in textTracks, but not yet loaded. - assert_equals(video.textTracks.length, 2); - assert_equals(video.textTracks[0].mode, "hidden"); - checkCaptionsHidden(video); - - // Captions track should become visible after the track is selected. - clickTextTrackAtIndex(video, 0); - checkCaptionsVisible(video, captions); - - // Captions should not be visible after they're turned off through the menu. - turnClosedCaptionsOff(video); - checkCaptionsHidden(video); - - // Captions track should become visible after the track is selected again. - clickTextTrackAtIndex(video, 0); - checkCaptionsVisible(video, captions); - }); - - video.src = findMediaFile("video", "content/counting"); -}); -</script> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/media/video-controls-captions.html b/third_party/WebKit/LayoutTests/media/video-controls-captions.html deleted file mode 100644 index 608bcbe..0000000 --- a/third_party/WebKit/LayoutTests/media/video-controls-captions.html +++ /dev/null
@@ -1,69 +0,0 @@ -<!DOCTYPE html> -<title>Tests that the closed captions button enables track switching.</title> -<script src="../resources/testharness.js"></script> -<script src="../resources/testharnessreport.js"></script> -<script src="media-file.js"></script> -<script src="media-controls.js"></script> -<video controls> - <track src="track/captions-webvtt/captions-fast.vtt" kind="captions"> - <track src="track/captions-webvtt/captions-rtl.vtt" kind="captions"> -</video> -<script> -async_test(function(t) { - var video = document.querySelector("video"); - - video.oncanplaythrough = t.step_func(function() { - assert_true(isClosedCaptionsButtonVisible(video)); - - // The captions track should be listed in textTracks, but not yet loaded. - assert_equals(video.textTracks.length, 2); - assert_equals(video.textTracks[0].mode, "disabled"); - assert_equals(textTrackContainerElement(video), null); - - var tracks = document.querySelectorAll("track"); - tracks[0].onload = t.step_func(function() { - assert_equals(textTrackDisplayElement(video).innerText, "Lorem"); - - // Captions should not be visible after Off is clicked. - turnClosedCaptionsOff(video); - assert_equals(textTrackDisplayElement(video), null); - - // Remove DOM node representing the track element. - tracks[1].remove(); - tracks[0].remove(); - assert_false(isClosedCaptionsButtonVisible(video)); - - addUnloadableHTMLTrackElement(); - assert_true(isClosedCaptionsButtonVisible(video)); - - clickTextTrackAtIndex(video, 0); - }); - - // Captions track should load and captions should become visible after a track is selected. - clickTextTrackAtIndex(video, 0); - }); - - function addUnloadableHTMLTrackElement() { - // Add non-default text track through HTML with unloadable URI. - var track = document.createElement("track"); - track.setAttribute("kind", "captions"); - track.setAttribute("srclang", "en"); - track.setAttribute("src", "invalid.vtt"); - - track.onerror = t.step_func_done(function() { - // Track failed to load. - assert_false(isClosedCaptionsButtonVisible(video)); - // Add a text track through JS to the video element. - var newTrack = video.addTextTrack("captions", "English", "en"); - assert_true(isClosedCaptionsButtonVisible(video)); - }); - - video.appendChild(track); - assert_equals(track.readyState, HTMLTrackElement.NONE); - assert_equals(track.track.mode, "disabled"); - assert_equals(video.textTracks.length, 1); - } - - video.src = findMediaFile("video", "content/counting"); -}); -</script> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt index 66baf38..bba6d777 100644 --- a/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -3171,10 +3171,12 @@ method toJSON interface MediaDevices : EventTarget attribute @@toStringTag + getter ondevicechange method constructor method enumerateDevices method getSupportedConstraints method getUserMedia + setter ondevicechange interface MediaElementAudioSourceNode : AudioSourceNode attribute @@toStringTag getter mediaElement
diff --git a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt index 3c39f18..a995e225 100644 --- a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt +++ b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -532,6 +532,8 @@ method fillRect method getImageData method getLineDash + method isPointInPath + method isPointInStroke method lineTo method moveTo method putImageData
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt index 449dcc0..b87c7a49 100644 --- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -3228,10 +3228,12 @@ method toJSON interface MediaDevices : EventTarget attribute @@toStringTag + getter ondevicechange method constructor method enumerateDevices method getSupportedConstraints method getUserMedia + setter ondevicechange interface MediaElementAudioSourceNode : AudioSourceNode attribute @@toStringTag getter mediaElement
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt index 07db00e7..0fe55af 100644 --- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt +++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -544,6 +544,8 @@ [Worker] method fillRect [Worker] method getImageData [Worker] method getLineDash +[Worker] method isPointInPath +[Worker] method isPointInStroke [Worker] method lineTo [Worker] method moveTo [Worker] method putImageData
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt index 62cb2013..99dd9093 100644 --- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -4400,6 +4400,8 @@ method fillRect method getImageData method getLineDash + method isPointInPath + method isPointInStroke method lineTo method moveTo method putImageData
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt index 3f2c35f6..48a586b 100644 --- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt +++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -539,6 +539,8 @@ [Worker] method fillRect [Worker] method getImageData [Worker] method getLineDash +[Worker] method isPointInPath +[Worker] method isPointInStroke [Worker] method lineTo [Worker] method moveTo [Worker] method putImageData
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScheduledAction.cpp b/third_party/WebKit/Source/bindings/core/v8/ScheduledAction.cpp index 403c3d14..f0c1db8d 100644 --- a/third_party/WebKit/Source/bindings/core/v8/ScheduledAction.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/ScheduledAction.cpp
@@ -61,7 +61,17 @@ visitor->trace(m_code); } -ScheduledAction::~ScheduledAction() {} +ScheduledAction::~ScheduledAction() { + // Verify that owning DOMTimer has eagerly disposed. + DCHECK(m_info.IsEmpty()); +} + +void ScheduledAction::dispose() { + m_code.dispose(); + m_info.Clear(); + m_function.clear(); + m_scriptState.clear(); +} void ScheduledAction::execute(ExecutionContext* context) { if (context->isDocument()) {
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScheduledAction.h b/third_party/WebKit/Source/bindings/core/v8/ScheduledAction.h index 28a80e4..b65d36ee 100644 --- a/third_party/WebKit/Source/bindings/core/v8/ScheduledAction.h +++ b/third_party/WebKit/Source/bindings/core/v8/ScheduledAction.h
@@ -56,6 +56,8 @@ static ScheduledAction* create(ScriptState*, const String& handler); ~ScheduledAction(); + void dispose(); + DECLARE_TRACE(); void execute(ExecutionContext*);
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptSourceCode.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptSourceCode.cpp index 9c7f78f..ef9de04 100644 --- a/third_party/WebKit/Source/bindings/core/v8/ScriptSourceCode.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/ScriptSourceCode.cpp
@@ -36,6 +36,13 @@ ScriptSourceCode::~ScriptSourceCode() {} +void ScriptSourceCode::dispose() { + m_source = String(); + m_resource = nullptr; + m_streamer = nullptr; + m_url = KURL(); +} + DEFINE_TRACE(ScriptSourceCode) { visitor->trace(m_resource); visitor->trace(m_streamer);
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptSourceCode.h b/third_party/WebKit/Source/bindings/core/v8/ScriptSourceCode.h index 3af0431..15651270 100644 --- a/third_party/WebKit/Source/bindings/core/v8/ScriptSourceCode.h +++ b/third_party/WebKit/Source/bindings/core/v8/ScriptSourceCode.h
@@ -56,6 +56,7 @@ ScriptSourceCode(ScriptStreamer*, ScriptResource*); ~ScriptSourceCode(); + void dispose(); DECLARE_TRACE(); bool isEmpty() const { return m_source.isEmpty(); } @@ -65,13 +66,13 @@ bool isNull() const { return m_source.isNull(); } const String& source() const { return m_source; } - ScriptResource* resource() const { return m_resource.get(); } + ScriptResource* resource() const { return m_resource; } const KURL& url() const; int startLine() const { return m_startPosition.m_line.oneBasedInt(); } const TextPosition& startPosition() const { return m_startPosition; } String sourceMapUrl() const; - ScriptStreamer* streamer() const { return m_streamer.get(); } + ScriptStreamer* streamer() const { return m_streamer; } private: void treatNullSourceAsEmpty();
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp b/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp index dcb07ce..5f3cbb3 100644 --- a/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp
@@ -37,7 +37,6 @@ #include "bindings/core/v8/V8ErrorEvent.h" #include "bindings/core/v8/V8ErrorHandler.h" #include "bindings/core/v8/V8GCController.h" -#include "bindings/core/v8/V8History.h" #include "bindings/core/v8/V8IdleTaskRunner.h" #include "bindings/core/v8/V8Location.h" #include "bindings/core/v8/V8PerContextData.h" @@ -81,9 +80,6 @@ return V8Window::toImpl(windowWrapper)->frame(); } - if (V8History::wrapperTypeInfo.equals(type)) - return V8History::toImpl(host)->frame(); - if (V8Location::wrapperTypeInfo.equals(type)) return V8Location::toImpl(host)->frame();
diff --git a/third_party/WebKit/Source/core/frame/DOMTimer.cpp b/third_party/WebKit/Source/core/frame/DOMTimer.cpp index f3cd7206..a6140804 100644 --- a/third_party/WebKit/Source/core/frame/DOMTimer.cpp +++ b/third_party/WebKit/Source/core/frame/DOMTimer.cpp
@@ -107,7 +107,10 @@ startRepeating(intervalMilliseconds, BLINK_FROM_HERE); } -DOMTimer::~DOMTimer() {} +DOMTimer::~DOMTimer() { + if (m_action) + m_action->dispose(); +} void DOMTimer::stop() { InspectorInstrumentation::asyncTaskCanceled(getExecutionContext(), this); @@ -115,6 +118,8 @@ // Need to release JS objects potentially protected by ScheduledAction // because they can form circular references back to the ExecutionContext // which will cause a memory leak. + if (m_action) + m_action->dispose(); m_action = nullptr; SuspendableTimer::stop(); } @@ -172,6 +177,8 @@ executionContext->timers()->setTimerNestingLevel(0); // Eagerly unregister as ExecutionContext observer. clearContext(); + // Eagerly clear out |action|'s resources. + action->dispose(); } WebTaskRunner* DOMTimer::timerTaskRunner() const {
diff --git a/third_party/WebKit/Source/core/frame/FrameView.cpp b/third_party/WebKit/Source/core/frame/FrameView.cpp index 653415b..4419357 100644 --- a/third_party/WebKit/Source/core/frame/FrameView.cpp +++ b/third_party/WebKit/Source/core/frame/FrameView.cpp
@@ -3547,12 +3547,11 @@ const TopDocumentRootScrollerController& controller = m_frame->host()->globalRootScrollerController(); - if (!controller.globalRootScroller()) + if (!layoutViewportScrollableArea()) return false; return RootScrollerUtil::scrollableAreaForRootScroller( - *controller.globalRootScroller()) == - layoutViewportScrollableArea(); + controller.globalRootScroller()) == layoutViewportScrollableArea(); } AXObjectCache* FrameView::axObjectCache() const {
diff --git a/third_party/WebKit/Source/core/frame/csp/SourceListDirective.cpp b/third_party/WebKit/Source/core/frame/csp/SourceListDirective.cpp index 6449cf95..c6784bf0f 100644 --- a/third_party/WebKit/Source/core/frame/csp/SourceListDirective.cpp +++ b/third_party/WebKit/Source/core/frame/csp/SourceListDirective.cpp
@@ -565,8 +565,9 @@ m_hashAlgorithmsUsed |= algorithm; } -void SourceListDirective::addSourceToMap(HashMap<String, CSPSource*>& hashMap, - CSPSource* source) { +void SourceListDirective::addSourceToMap( + HeapHashMap<String, Member<CSPSource>>& hashMap, + CSPSource* source) { hashMap.add(source->getScheme(), source); if (source->getScheme() == "http") hashMap.add("https", source); @@ -648,16 +649,17 @@ return CSPSource::firstSubsumesSecond(normalizedA, normalizedB); } -HashMap<String, CSPSource*> SourceListDirective::getIntersectSchemesOnly( +HeapHashMap<String, Member<CSPSource>> +SourceListDirective::getIntersectSchemesOnly( HeapVector<Member<CSPSource>> other) { - HashMap<String, CSPSource*> schemesA; + HeapHashMap<String, Member<CSPSource>> schemesA; for (const auto& sourceA : m_list) { if (sourceA->isSchemeOnly()) addSourceToMap(schemesA, sourceA); } // Add schemes only sources if they are present in both `this` and `other`, // allowing upgrading `http` to `https` and `ws` to `wss`. - HashMap<String, CSPSource*> intersect; + HeapHashMap<String, Member<CSPSource>> intersect; for (const auto& sourceB : other) { if (sourceB->isSchemeOnly()) { if (schemesA.contains(sourceB->getScheme())) @@ -674,14 +676,14 @@ HeapVector<Member<CSPSource>> SourceListDirective::getIntersectCSPSources( HeapVector<Member<CSPSource>> other) { - HashMap<String, CSPSource*> schemesMap = getIntersectSchemesOnly(other); + auto schemesMap = getIntersectSchemesOnly(other); HeapVector<Member<CSPSource>> normalized; // Add all normalized scheme source expressions. - for (auto it = schemesMap.begin(); it != schemesMap.end(); ++it) { + for (const auto& it : schemesMap) { // We do not add secure versions if insecure schemes are present. - if ((it->key != "https" || !schemesMap.contains("http")) && - (it->key != "wss" || !schemesMap.contains("ws"))) { - normalized.append(it->value); + if ((it.key != "https" || !schemesMap.contains("http")) && + (it.key != "wss" || !schemesMap.contains("ws"))) { + normalized.append(it.value); } }
diff --git a/third_party/WebKit/Source/core/frame/csp/SourceListDirective.h b/third_party/WebKit/Source/core/frame/csp/SourceListDirective.h index fd4aa311..aba676215 100644 --- a/third_party/WebKit/Source/core/frame/csp/SourceListDirective.h +++ b/third_party/WebKit/Source/core/frame/csp/SourceListDirective.h
@@ -93,12 +93,13 @@ void addSourceHash(const ContentSecurityPolicyHashAlgorithm&, const DigestValue& hash); - static void addSourceToMap(HashMap<String, CSPSource*>&, CSPSource*); + static void addSourceToMap(HeapHashMap<String, Member<CSPSource>>&, + CSPSource*); bool hasSourceMatchInList(const KURL&, ResourceRequest::RedirectStatus) const; HeapVector<Member<CSPSource>> getIntersectCSPSources( HeapVector<Member<CSPSource>> other); - HashMap<String, CSPSource*> getIntersectSchemesOnly( + HeapHashMap<String, Member<CSPSource>> getIntersectSchemesOnly( HeapVector<Member<CSPSource>> other); Member<ContentSecurityPolicy> m_policy;
diff --git a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp index 49afa31..3e66e71 100644 --- a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
@@ -1251,9 +1251,14 @@ // clicking the captions button. In this case, a check whether all the // resources have failed loading should be done in order to hide the CC // button. + // TODO(mlamouri): when an HTMLTrackElement fails to load, it is not + // propagated to the TextTrack object in a web exposed fashion. We have to + // keep relying on a custom glue to the controls while this is taken care + // of on the web side. See https://crbug.com/669977 if (mediaControls() && - track->getReadinessState() == TextTrack::FailedToLoad) - mediaControls()->refreshClosedCaptionsButtonVisibility(); + track->getReadinessState() == TextTrack::FailedToLoad) { + mediaControls()->onTrackElementFailedToLoad(); + } } } @@ -1702,11 +1707,8 @@ shouldUpdateDisplayState = true; } - if (shouldUpdateDisplayState) { + if (shouldUpdateDisplayState) updateDisplayState(); - if (mediaControls()) - mediaControls()->refreshClosedCaptionsButtonVisibility(); - } updatePlayState(); cueTimeline().updateActiveCues(currentTime()); @@ -2070,10 +2072,13 @@ return WebMediaPlayer::PreloadNone; } - // Force preload to 'none' on Data Saver and for low end devices. + // If the source scheme is requires network, force preload to 'none' on Data + // Saver and for low end devices. if (document().settings() && (document().settings()->dataSaverEnabled() || - document().settings()->forcePreloadNoneForMediaElements())) { + document().settings()->forcePreloadNoneForMediaElements()) && + (m_currentSrc.protocol() != "blob" && m_currentSrc.protocol() != "data" && + m_currentSrc.protocol() != "file")) { UseCounter::count(document(), UseCounter::HTMLMediaElementPreloadForcedNone); return WebMediaPlayer::PreloadNone; @@ -2609,7 +2614,7 @@ // cancelable, and that uses the TrackEvent interface, with the track // attribute initialized to the text track's TextTrack object, at the media // element's textTracks attribute's TextTrackList object. - addTextTrack(textTrack); + textTracks()->append(textTrack); } void HTMLMediaElement::removeTextTrack(WebInbandTextTrack* webTrack) { @@ -2623,24 +2628,7 @@ if (!textTrack) return; - removeTextTrack(textTrack); -} - -void HTMLMediaElement::textTracksChanged() { - if (mediaControls()) - mediaControls()->refreshClosedCaptionsButtonVisibility(); -} - -void HTMLMediaElement::addTextTrack(TextTrack* track) { - textTracks()->append(track); - - textTracksChanged(); -} - -void HTMLMediaElement::removeTextTrack(TextTrack* track) { - m_textTracks->remove(track); - - textTracksChanged(); + m_textTracks->remove(textTrack); } void HTMLMediaElement::forgetResourceSpecificTracks() { @@ -2650,7 +2638,6 @@ if (m_textTracks) { TrackDisplayUpdateScope scope(this->cueTimeline()); m_textTracks->removeAllInbandTracks(); - textTracksChanged(); } m_audioTracks->removeAll(); @@ -2683,7 +2670,7 @@ // interface, with the track attribute initialised to the new text // track's TextTrack object, at the media element's textTracks // attribute's TextTrackList object. - addTextTrack(textTrack); + textTracks()->append(textTrack); // Note: Due to side effects when changing track parameters, we have to // first append the track to the text track list. @@ -2715,7 +2702,7 @@ if (!textTrack) return; - addTextTrack(textTrack); + textTracks()->append(textTrack); // Do not schedule the track loading until parsing finishes so we don't start // before all tracks in the markup have been added. @@ -2741,7 +2728,7 @@ // When a track element's parent element changes and the old parent was a // media element, then the user agent must remove the track element's // corresponding text track from the media element's list of text tracks. - removeTextTrack(textTrack); + m_textTracks->remove(textTrack); size_t index = m_textTracksWhenResourceSelectionBegan.find(textTrack); if (index != kNotFound) @@ -2768,8 +2755,6 @@ AutomaticTrackSelection trackSelection(configuration); trackSelection.perform(*m_textTracks); - - textTracksChanged(); } bool HTMLMediaElement::havePotentialSourceChild() { @@ -3432,12 +3417,14 @@ } bool HTMLMediaElement::hasClosedCaptions() const { - if (m_textTracks) { - for (unsigned i = 0; i < m_textTracks->length(); ++i) { - if (m_textTracks->anonymousIndexedGetter(i)->canBeRendered()) - return true; - } + if (!m_textTracks) + return false; + + for (unsigned i = 0; i < m_textTracks->length(); ++i) { + if (m_textTracks->anonymousIndexedGetter(i)->canBeRendered()) + return true; } + return false; } @@ -3644,9 +3631,6 @@ if (!haveVisibleTextTrack && !mediaControls()) return; - if (mediaControls()) - mediaControls()->changedClosedCaptionsVisibility(); - cueTimeline().updateActiveCues(currentTime()); // Note: The "time marches on" algorithm (updateActiveCues) runs the "rules
diff --git a/third_party/WebKit/Source/core/html/HTMLMediaElement.h b/third_party/WebKit/Source/core/html/HTMLMediaElement.h index 9ced65c9..36a4468 100644 --- a/third_party/WebKit/Source/core/html/HTMLMediaElement.h +++ b/third_party/WebKit/Source/core/html/HTMLMediaElement.h
@@ -724,6 +724,7 @@ friend class Internals; friend class TrackDisplayUpdateScope; friend class MediaControlsTest; + friend class HTMLMediaElementTest; friend class HTMLVideoElementTest; Member<AutoplayUmaHelper> m_autoplayUmaHelper;
diff --git a/third_party/WebKit/Source/core/html/HTMLMediaElementTest.cpp b/third_party/WebKit/Source/core/html/HTMLMediaElementTest.cpp index 7b04d525..1187ce6 100644 --- a/third_party/WebKit/Source/core/html/HTMLMediaElementTest.cpp +++ b/third_party/WebKit/Source/core/html/HTMLMediaElementTest.cpp
@@ -4,8 +4,10 @@ #include "core/html/HTMLMediaElement.h" +#include "core/frame/Settings.h" #include "core/html/HTMLAudioElement.h" #include "core/html/HTMLVideoElement.h" +#include "core/page/NetworkStateNotifier.h" #include "core/testing/DummyPageHolder.h" #include "testing/gtest/include/gtest/gtest.h" @@ -25,6 +27,10 @@ } HTMLMediaElement* media() { return m_media.get(); } + void setCurrentSrc(const String& src) { + KURL url(ParsedURLString, src); + media()->m_currentSrc = url; + } private: std::unique_ptr<DummyPageHolder> m_dummyPageHolder; @@ -55,4 +61,81 @@ } } +enum class TestURLScheme { + kHttp, + kHttps, + kFtp, + kFile, + kData, + kBlob, +}; + +String srcSchemeToURL(TestURLScheme scheme) { + switch (scheme) { + case TestURLScheme::kHttp: + return "http://example.com/foo.mp4"; + case TestURLScheme::kHttps: + return "https://example.com/foo.mp4"; + case TestURLScheme::kFtp: + return "ftp://example.com/foo.mp4"; + case TestURLScheme::kFile: + return "file:///foo/bar.mp4"; + case TestURLScheme::kData: + return "data:video/mp4;base64,XXXXXXX"; + case TestURLScheme::kBlob: + return "blob:http://example.com/00000000-0000-0000-0000-000000000000"; + default: + NOTREACHED(); + } + return emptyString(); +} + +TEST_P(HTMLMediaElementTest, preloadType) { + struct TestData { + bool dataSaverEnabled; + bool forcePreloadNoneForMediaElements; + bool isCellular; + TestURLScheme srcScheme; + AtomicString preloadToSet; + AtomicString preloadExpected; + } testData[] = { + // Tests for conditions in which preload type should be overriden to + // "none". + {false, true, false, TestURLScheme::kHttp, "auto", "none"}, + {true, true, false, TestURLScheme::kHttps, "auto", "none"}, + {true, true, false, TestURLScheme::kFtp, "metadata", "none"}, + {false, false, false, TestURLScheme::kHttps, "auto", "auto"}, + {false, true, false, TestURLScheme::kFile, "auto", "auto"}, + {false, true, false, TestURLScheme::kData, "metadata", "metadata"}, + {false, true, false, TestURLScheme::kBlob, "auto", "auto"}, + {false, true, false, TestURLScheme::kFile, "none", "none"}, + // Tests for conditions in which preload type should be overriden to + // "metadata". + {false, false, true, TestURLScheme::kHttp, "auto", "metadata"}, + {false, false, true, TestURLScheme::kHttp, "scheme", "metadata"}, + {false, false, true, TestURLScheme::kHttp, "none", "none"}, + // Tests that the preload is overriden to "auto" + {false, false, false, TestURLScheme::kHttp, "foo", "auto"}, + }; + + int index = 0; + for (const auto& data : testData) { + media()->document().settings()->setDataSaverEnabled(data.dataSaverEnabled); + media()->document().settings()->setForcePreloadNoneForMediaElements( + data.forcePreloadNoneForMediaElements); + if (data.isCellular) { + networkStateNotifier().setOverride( + true, WebConnectionType::WebConnectionTypeCellular3G, 2.0); + } else { + networkStateNotifier().clearOverride(); + } + setCurrentSrc(srcSchemeToURL(data.srcScheme)); + media()->setPreload(data.preloadToSet); + + EXPECT_EQ(data.preloadExpected, media()->preload()) + << "preload type differs at index" << index; + ++index; + } +} + } // namespace blink
diff --git a/third_party/WebKit/Source/core/html/parser/CSSPreloadScanner.cpp b/third_party/WebKit/Source/core/html/parser/CSSPreloadScanner.cpp index 920d5b80..217d3898 100644 --- a/third_party/WebKit/Source/core/html/parser/CSSPreloadScanner.cpp +++ b/third_party/WebKit/Source/core/html/parser/CSSPreloadScanner.cpp
@@ -320,6 +320,18 @@ } void CSSPreloaderResourceClient::clearResource() { + // Do not remove the client for unused, speculative markup preloads. This will + // trigger cancellation of the request and potential removal from memory + // cache. Link preloads are an exception because they support dynamic removal + // cancelling the request (and have their own passive resource client). + // Note: Speculative preloads which remain unused for their lifetime will + // never have this client removed. This should be fine because we only hold + // weak references to the resource. + if (m_resource && m_resource->isUnusedPreload() && + !m_resource->isLinkPreload()) { + return; + } + if (m_resource) m_resource->removeClient(this); m_resource.clear();
diff --git a/third_party/WebKit/Source/core/html/shadow/MediaControlElements.cpp b/third_party/WebKit/Source/core/html/shadow/MediaControlElements.cpp index ab7ea8b..290dd313 100644 --- a/third_party/WebKit/Source/core/html/shadow/MediaControlElements.cpp +++ b/third_party/WebKit/Source/core/html/shadow/MediaControlElements.cpp
@@ -887,11 +887,11 @@ if (mediaElement().isFullscreen()) { Platform::current()->recordAction( UserMetricsAction("Media.Controls.ExitFullscreen")); - mediaElement().exitFullscreen(); + mediaControls().exitFullscreen(); } else { Platform::current()->recordAction( UserMetricsAction("Media.Controls.EnterFullscreen")); - mediaElement().enterFullscreen(); + mediaControls().enterFullscreen(); } event->setDefaultHandled(); }
diff --git a/third_party/WebKit/Source/core/html/shadow/MediaControls.cpp b/third_party/WebKit/Source/core/html/shadow/MediaControls.cpp index 5b4b0b7..81c0e66b 100644 --- a/third_party/WebKit/Source/core/html/shadow/MediaControls.cpp +++ b/third_party/WebKit/Source/core/html/shadow/MediaControls.cpp
@@ -339,8 +339,7 @@ m_timeline->setPosition(mediaElement().currentTime()); onVolumeChange(); - - refreshClosedCaptionsButtonVisibility(); + onTextTracksAddedOrRemoved(); m_fullscreenButton->setIsWanted(shouldShowFullscreenButton(mediaElement())); @@ -454,15 +453,6 @@ m_currentTimeDisplay->setCurrentValue(now); } -void MediaControls::changedClosedCaptionsVisibility() { - m_toggleClosedCaptionsButton->updateDisplayType(); -} - -void MediaControls::refreshClosedCaptionsButtonVisibility() { - m_toggleClosedCaptionsButton->setIsWanted(mediaElement().hasClosedCaptions()); - BatchedControlUpdate batch(this); -} - void MediaControls::toggleTextTrackList() { if (!mediaElement().hasClosedCaptions()) { m_textTrackList->setVisible(false); @@ -539,6 +529,16 @@ resetHideMediaControlsTimer(); } +void MediaControls::enterFullscreen() { + // TODO(foolip): switch to Fullscreen::UnprefixedRequest when the unprefixed + // Fullscreen API has launched. + Fullscreen::requestFullscreen(mediaElement(), Fullscreen::PrefixedRequest); +} + +void MediaControls::exitFullscreen() { + Fullscreen::exitFullscreen(document()); +} + void MediaControls::enteredFullscreen() { m_fullscreenButton->setIsFullscreen(true); stopHideMediaControlsTimer(); @@ -724,6 +724,15 @@ stopHideMediaControlsTimer(); } +void MediaControls::onTextTracksAddedOrRemoved() { + m_toggleClosedCaptionsButton->setIsWanted(mediaElement().hasClosedCaptions()); + BatchedControlUpdate batch(this); +} + +void MediaControls::onTextTracksChanged() { + m_toggleClosedCaptionsButton->updateDisplayType(); +} + void MediaControls::notifyPanelWidthChanged(const LayoutUnit& newWidth) { // Don't bother to do any work if this matches the most recent panel // width, since we're called after layout.
diff --git a/third_party/WebKit/Source/core/html/shadow/MediaControls.h b/third_party/WebKit/Source/core/html/shadow/MediaControls.h index f21bf2c..10a1c10 100644 --- a/third_party/WebKit/Source/core/html/shadow/MediaControls.h +++ b/third_party/WebKit/Source/core/html/shadow/MediaControls.h
@@ -53,12 +53,14 @@ void updateCurrentTimeDisplay(); - void changedClosedCaptionsVisibility(); - void refreshClosedCaptionsButtonVisibility(); void toggleTextTrackList(); void showTextTrackAtIndex(unsigned indexToEnable); void disableShowingTextTracks(); + // Called by the fullscreen buttons to toggle fulllscreen on/off. + void enterFullscreen(); + void exitFullscreen(); + void enteredFullscreen(); void exitedFullscreen(); @@ -95,6 +97,11 @@ bool overflowMenuVisible(); + // TODO(mlamouri): this is temporary to notify the controls that an + // HTMLTrackElement failed to load because there is no web exposed way to + // be notified on the TextTrack object. See https://crbug.com/669977 + void onTrackElementFailedToLoad() { onTextTracksAddedOrRemoved(); } + DECLARE_VIRTUAL_TRACE(); private: @@ -148,6 +155,8 @@ void onTimeUpdate(); void onPlay(); void onPause(); + void onTextTracksAddedOrRemoved(); + void onTextTracksChanged(); Member<HTMLMediaElement> m_mediaElement;
diff --git a/third_party/WebKit/Source/core/html/shadow/MediaControlsMediaEventListener.cpp b/third_party/WebKit/Source/core/html/shadow/MediaControlsMediaEventListener.cpp index 154591d..9b6dae1c 100644 --- a/third_party/WebKit/Source/core/html/shadow/MediaControlsMediaEventListener.cpp +++ b/third_party/WebKit/Source/core/html/shadow/MediaControlsMediaEventListener.cpp
@@ -7,6 +7,7 @@ #include "core/events/Event.h" #include "core/html/HTMLMediaElement.h" #include "core/html/shadow/MediaControls.h" +#include "core/html/track/TextTrackList.h" namespace blink { @@ -23,6 +24,12 @@ false); m_mediaControls->m_mediaElement->addEventListener(EventTypeNames::pause, this, false); + + // TextTracks events. + TextTrackList* textTracks = m_mediaControls->m_mediaElement->textTracks(); + textTracks->addEventListener(EventTypeNames::addtrack, this, false); + textTracks->addEventListener(EventTypeNames::change, this, false); + textTracks->addEventListener(EventTypeNames::removetrack, this, false); } bool MediaControlsMediaEventListener::operator==( @@ -54,6 +61,17 @@ return; } + // TextTracks events. + if (event->type() == EventTypeNames::addtrack || + event->type() == EventTypeNames::removetrack) { + m_mediaControls->onTextTracksAddedOrRemoved(); + return; + } + if (event->type() == EventTypeNames::change) { + m_mediaControls->onTextTracksChanged(); + return; + } + NOTREACHED(); }
diff --git a/third_party/WebKit/Source/core/input/MouseEventManager.cpp b/third_party/WebKit/Source/core/input/MouseEventManager.cpp index 1810c69b..80529431 100644 --- a/third_party/WebKit/Source/core/input/MouseEventManager.cpp +++ b/third_party/WebKit/Source/core/input/MouseEventManager.cpp
@@ -732,8 +732,13 @@ m_mouseDownMayStartDrag = false; + m_frame->eventHandler().selectionController().handleMouseDraggedEvent( + event, m_mouseDownPos, m_dragStartPos, m_mousePressNode.get(), + m_lastKnownMousePosition); + if (m_mouseDownMayStartAutoscroll && - !m_scrollManager->middleClickAutoscrollInProgress()) { + !m_scrollManager->middleClickAutoscrollInProgress() && + !m_frame->selection().selectedHTMLForClipboard().isEmpty()) { if (AutoscrollController* controller = m_scrollManager->autoscrollController()) { controller->startAutoscrollForSelection(layoutObject); @@ -741,9 +746,6 @@ } } - m_frame->eventHandler().selectionController().handleMouseDraggedEvent( - event, m_mouseDownPos, m_dragStartPos, m_mousePressNode.get(), - m_lastKnownMousePosition); return WebInputEventResult::HandledSystem; }
diff --git a/third_party/WebKit/Source/core/page/scrolling/RootScrollerController.cpp b/third_party/WebKit/Source/core/page/scrolling/RootScrollerController.cpp index e9e73cf..d288022 100644 --- a/third_party/WebKit/Source/core/page/scrolling/RootScrollerController.cpp +++ b/third_party/WebKit/Source/core/page/scrolling/RootScrollerController.cpp
@@ -126,7 +126,7 @@ if (!element.layoutObject()) return false; - if (!RootScrollerUtil::scrollableAreaForRootScroller(element)) + if (!RootScrollerUtil::scrollableAreaForRootScroller(&element)) return false; if (!fillsViewport(element))
diff --git a/third_party/WebKit/Source/core/page/scrolling/RootScrollerUtil.cpp b/third_party/WebKit/Source/core/page/scrolling/RootScrollerUtil.cpp index 6d80002a..76b11843 100644 --- a/third_party/WebKit/Source/core/page/scrolling/RootScrollerUtil.cpp +++ b/third_party/WebKit/Source/core/page/scrolling/RootScrollerUtil.cpp
@@ -16,23 +16,26 @@ namespace RootScrollerUtil { -ScrollableArea* scrollableAreaForRootScroller(const Element& element) { - if (&element == element.document().documentElement()) { - if (!element.document().view()) +ScrollableArea* scrollableAreaForRootScroller(const Element* element) { + if (!element) + return nullptr; + + if (element == element->document().documentElement()) { + if (!element->document().view()) return nullptr; // For a FrameView, we use the layoutViewport rather than the // getScrollableArea() since that could be the RootFrameViewport. The // rootScroller's ScrollableArea will be swapped in as the layout viewport // in RootFrameViewport so we need to ensure we get the layout viewport. - return element.document().view()->layoutViewportScrollableArea(); + return element->document().view()->layoutViewportScrollableArea(); } - if (!element.layoutObject() || !element.layoutObject()->isBox()) + if (!element->layoutObject() || !element->layoutObject()->isBox()) return nullptr; return static_cast<PaintInvalidationCapableScrollableArea*>( - toLayoutBoxModelObject(element.layoutObject())->getScrollableArea()); + toLayoutBoxModelObject(element->layoutObject())->getScrollableArea()); } PaintLayer* paintLayerForRootScroller(const Element* element) {
diff --git a/third_party/WebKit/Source/core/page/scrolling/RootScrollerUtil.h b/third_party/WebKit/Source/core/page/scrolling/RootScrollerUtil.h index dc76681..56615c8 100644 --- a/third_party/WebKit/Source/core/page/scrolling/RootScrollerUtil.h +++ b/third_party/WebKit/Source/core/page/scrolling/RootScrollerUtil.h
@@ -16,7 +16,7 @@ // Returns the ScrollableArea that's associated with the root scroller element. // For the <html> element this will be the FrameView or root // PaintLayerScrollableArea. -ScrollableArea* scrollableAreaForRootScroller(const Element&); +ScrollableArea* scrollableAreaForRootScroller(const Element*); // Returns the PaintLayer that'll be used as the root scrolling layer. For the // <html> element, this returns the LayoutView's PaintLayer rather than
diff --git a/third_party/WebKit/Source/core/page/scrolling/TopDocumentRootScrollerController.cpp b/third_party/WebKit/Source/core/page/scrolling/TopDocumentRootScrollerController.cpp index 0552d56..2ea0be3 100644 --- a/third_party/WebKit/Source/core/page/scrolling/TopDocumentRootScrollerController.cpp +++ b/third_party/WebKit/Source/core/page/scrolling/TopDocumentRootScrollerController.cpp
@@ -43,11 +43,9 @@ void TopDocumentRootScrollerController::mainFrameViewResized() { Element* rootScroller = globalRootScroller(); - if (!rootScroller) - return; ScrollableArea* area = - RootScrollerUtil::scrollableAreaForRootScroller(*rootScroller); + RootScrollerUtil::scrollableAreaForRootScroller(rootScroller); if (!area) return; @@ -90,11 +88,11 @@ return; Element* target = findGlobalRootScrollerElement(); - if (!target || target == m_globalRootScroller) + if (target == m_globalRootScroller) return; ScrollableArea* targetScroller = - RootScrollerUtil::scrollableAreaForRootScroller(*target); + RootScrollerUtil::scrollableAreaForRootScroller(target); if (!targetScroller) return; @@ -117,9 +115,7 @@ setNeedsCompositingInputsUpdateOnGlobalRootScroller(); ScrollableArea* oldRootScrollerArea = - m_globalRootScroller ? RootScrollerUtil::scrollableAreaForRootScroller( - *m_globalRootScroller.get()) - : nullptr; + RootScrollerUtil::scrollableAreaForRootScroller(m_globalRootScroller); m_globalRootScroller = target; @@ -195,11 +191,8 @@ } GraphicsLayer* TopDocumentRootScrollerController::rootScrollerLayer() const { - if (!m_globalRootScroller) - return nullptr; - ScrollableArea* area = - RootScrollerUtil::scrollableAreaForRootScroller(*m_globalRootScroller); + RootScrollerUtil::scrollableAreaForRootScroller(m_globalRootScroller); if (!area) return nullptr;
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp index 8e0b0ca..be91e8d 100644 --- a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp +++ b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
@@ -1780,11 +1780,8 @@ const TopDocumentRootScrollerController& controller = layoutBox()->document().frameHost()->globalRootScrollerController(); - if (!controller.globalRootScroller()) - return false; - return RootScrollerUtil::scrollableAreaForRootScroller( - *controller.globalRootScroller()) == this; + controller.globalRootScroller()) == this; } Widget* PaintLayerScrollableArea::getWidget() {
diff --git a/third_party/WebKit/Source/core/svg/SVGDocumentExtensions.cpp b/third_party/WebKit/Source/core/svg/SVGDocumentExtensions.cpp index e861800..6e672b2 100644 --- a/third_party/WebKit/Source/core/svg/SVGDocumentExtensions.cpp +++ b/third_party/WebKit/Source/core/svg/SVGDocumentExtensions.cpp
@@ -23,6 +23,7 @@ #include "core/dom/Document.h" #include "core/inspector/ConsoleMessage.h" +#include "core/layout/svg/LayoutSVGResourceContainer.h" #include "core/svg/SVGSVGElement.h" #include "core/svg/animation/SMILTimeContainer.h" #include "wtf/AutoReset.h"
diff --git a/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.idl b/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.idl index bb5bce5..7224955 100644 --- a/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.idl +++ b/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.idl
@@ -60,6 +60,10 @@ void stroke(Path2D path); void clip(); void clip(Path2D path); + boolean isPointInPath(unrestricted double x, unrestricted double y, optional CanvasFillRule winding); + boolean isPointInPath(Path2D path, unrestricted double x, unrestricted double y, optional CanvasFillRule winding); + boolean isPointInStroke(unrestricted double x, unrestricted double y); + boolean isPointInStroke(Path2D path, unrestricted double x, unrestricted double y); // drawing images [CallWith=ExecutionContext, RaisesException] void drawImage(CanvasImageSource image, unrestricted double x, unrestricted double y);
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in index 6aaddde..bf45bbd 100644 --- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in +++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
@@ -155,7 +155,7 @@ NotificationContentImage status=stable NotificationInlineReplies status=experimental Notifications status=stable -OnDeviceChange status=experimental +OnDeviceChange status=stable OrientationEvent OriginTrials status=stable // Define a sample API for testing integration with the Origin Trials Framework. @@ -254,6 +254,7 @@ WebVTTRegions status=experimental V8BasedStructuredClone status=stable V8IdleTasks +VideoFullscreenOrientationLock VisibilityChangeOnUnload status=stable XSLT status=stable smil status=stable
diff --git a/third_party/WebKit/Source/platform/geometry/LayoutRect.cpp b/third_party/WebKit/Source/platform/geometry/LayoutRect.cpp index ba9589cdf..d3421c4 100644 --- a/third_party/WebKit/Source/platform/geometry/LayoutRect.cpp +++ b/third_party/WebKit/Source/platform/geometry/LayoutRect.cpp
@@ -152,13 +152,6 @@ return result; } -IntRect enclosingIntRect(const LayoutRect& rect) { - IntPoint location = flooredIntPoint(rect.minXMinYCorner()); - IntPoint maxPoint = ceiledIntPoint(rect.maxXMaxYCorner()); - - return IntRect(location, maxPoint - location); -} - LayoutRect enclosingLayoutRect(const FloatRect& rect) { LayoutPoint location = flooredLayoutPoint(rect.minXMinYCorner()); LayoutPoint maxPoint = ceiledLayoutPoint(rect.maxXMaxYCorner());
diff --git a/third_party/WebKit/Source/platform/geometry/LayoutRect.h b/third_party/WebKit/Source/platform/geometry/LayoutRect.h index 8a5fe24..545802e 100644 --- a/third_party/WebKit/Source/platform/geometry/LayoutRect.h +++ b/third_party/WebKit/Source/platform/geometry/LayoutRect.h
@@ -278,7 +278,12 @@ snapSizeToPixel(rect.height(), rect.y()))); } -PLATFORM_EXPORT IntRect enclosingIntRect(const LayoutRect&); +inline IntRect enclosingIntRect(const LayoutRect& rect) { + IntPoint location = flooredIntPoint(rect.minXMinYCorner()); + IntPoint maxPoint = ceiledIntPoint(rect.maxXMaxYCorner()); + return IntRect(location, maxPoint - location); +} + PLATFORM_EXPORT LayoutRect enclosingLayoutRect(const FloatRect&); inline IntRect pixelSnappedIntRect(LayoutUnit left,
diff --git a/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.cpp b/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.cpp index 0bc3ea179..99960457 100644 --- a/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.cpp +++ b/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.cpp
@@ -304,6 +304,57 @@ return true; } +void ImageDecoder::correctAlphaWhenFrameBufferSawNoAlpha(size_t index) { + DCHECK(index < m_frameBufferCache.size()); + ImageFrame& buffer = m_frameBufferCache[index]; + + // When this frame spans the entire image rect we can set hasAlpha to false, + // since there are logically no transparent pixels outside of the frame rect. + if (buffer.originalFrameRect().contains(IntRect(IntPoint(), size()))) { + buffer.setHasAlpha(false); + buffer.setRequiredPreviousFrameIndex(kNotFound); + } else if (buffer.requiredPreviousFrameIndex() != kNotFound) { + // When the frame rect does not span the entire image rect, and it does + // *not* have a required previous frame, the pixels outside of the frame + // rect will be fully transparent, so we shoudn't set hasAlpha to false. + // + // It is a tricky case when the frame does have a required previous frame. + // The frame does not have alpha only if everywhere outside its rect + // doesn't have alpha. To know whether this is true, we check the start + // state of the frame -- if it doesn't have alpha, we're safe. + // + // We first check that the required previous frame does not have + // DisposeOverWritePrevious as its disposal method - this should never + // happen, since the required frame should in that case be the required + // frame of this frame's required frame. + // + // If |prevBuffer| is DisposeNotSpecified or DisposeKeep, |buffer| has no + // alpha if |prevBuffer| had no alpha. Since initFrameBuffer() already + // copied the alpha state, there's nothing to do here. + // + // The only remaining case is a DisposeOverwriteBgcolor frame. If + // it had no alpha, and its rect is contained in the current frame's + // rect, we know the current frame has no alpha. + // + // For DisposeNotSpecified, DisposeKeep and DisposeOverwriteBgcolor there + // is one situation that is not taken into account - when |prevBuffer| + // *does* have alpha, but only in the frame rect of |buffer|, we can still + // say that this frame has no alpha. However, to determine this, we + // potentially need to analyze all image pixels of |prevBuffer|, which is + // too computationally expensive. + const ImageFrame* prevBuffer = + &m_frameBufferCache[buffer.requiredPreviousFrameIndex()]; + DCHECK(prevBuffer->getDisposalMethod() != + ImageFrame::DisposeOverwritePrevious); + + if ((prevBuffer->getDisposalMethod() == + ImageFrame::DisposeOverwriteBgcolor) && + !prevBuffer->hasAlpha() && + buffer.originalFrameRect().contains(prevBuffer->originalFrameRect())) + buffer.setHasAlpha(false); + } +} + bool ImageDecoder::initFrameBuffer(size_t frameIndex) { DCHECK(frameIndex < m_frameBufferCache.size());
diff --git a/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.h b/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.h index 9124bb8..815c946c 100644 --- a/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.h +++ b/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.h
@@ -370,6 +370,18 @@ // false otherwise. bool postDecodeProcessing(size_t); + // The GIF and PNG decoders set the default alpha setting of the ImageFrame to + // true. When the frame rect does not contain any (semi-) transparent pixels, + // this may need to be changed to false. This depends on whether the required + // previous frame adds transparency to the image, outside of the frame rect. + // This methods corrects the alpha setting of the frame buffer to false when + // the whole frame is opaque. + // + // This method should be called by the GIF and PNG decoder when the pixels in + // the frame rect do *not* contain any transparent pixels. Before calling + // this method, the caller must verify that the frame exists. + void correctAlphaWhenFrameBufferSawNoAlpha(size_t); + RefPtr<SegmentReader> m_data; // The encoded data. Vector<ImageFrame, 1> m_frameBufferCache; const bool m_premultiplyAlpha;
diff --git a/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageDecoder.cpp b/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageDecoder.cpp index 2693402..54399fc 100644 --- a/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageDecoder.cpp +++ b/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageDecoder.cpp
@@ -192,43 +192,12 @@ bool GIFImageDecoder::frameComplete(size_t frameIndex) { // Initialize the frame if necessary. Some GIFs insert do-nothing frames, // in which case we never reach haveDecodedRow() before getting here. - ImageFrame& buffer = m_frameBufferCache[frameIndex]; if (!initFrameBuffer(frameIndex)) return false; // initFrameBuffer() has already called setFailed(). - buffer.setStatus(ImageFrame::FrameComplete); - - if (!m_currentBufferSawAlpha) { - // The whole frame was non-transparent, so it's possible that the entire - // resulting buffer was non-transparent, and we can setHasAlpha(false). - if (buffer.originalFrameRect().contains(IntRect(IntPoint(), size()))) { - buffer.setHasAlpha(false); - buffer.setRequiredPreviousFrameIndex(kNotFound); - } else if (buffer.requiredPreviousFrameIndex() != kNotFound) { - // Tricky case. This frame does not have alpha only if everywhere - // outside its rect doesn't have alpha. To know whether this is - // true, we check the start state of the frame -- if it doesn't have - // alpha, we're safe. - const ImageFrame* prevBuffer = - &m_frameBufferCache[buffer.requiredPreviousFrameIndex()]; - ASSERT(prevBuffer->getDisposalMethod() != - ImageFrame::DisposeOverwritePrevious); - - // Now, if we're at a DisposeNotSpecified or DisposeKeep frame, then - // we can say we have no alpha if that frame had no alpha. But - // since in initFrameBuffer() we already copied that frame's alpha - // state into the current frame's, we need do nothing at all here. - // - // The only remaining case is a DisposeOverwriteBgcolor frame. If - // it had no alpha, and its rect is contained in the current frame's - // rect, we know the current frame has no alpha. - if ((prevBuffer->getDisposalMethod() == - ImageFrame::DisposeOverwriteBgcolor) && - !prevBuffer->hasAlpha() && - buffer.originalFrameRect().contains(prevBuffer->originalFrameRect())) - buffer.setHasAlpha(false); - } - } + m_frameBufferCache[frameIndex].setStatus(ImageFrame::FrameComplete); + if (!m_currentBufferSawAlpha) + correctAlphaWhenFrameBufferSawNoAlpha(frameIndex); return true; }
diff --git a/third_party/WebKit/Source/web/WebRuntimeFeatures.cpp b/third_party/WebKit/Source/web/WebRuntimeFeatures.cpp index 5d947a1..cdfd51ed 100644 --- a/third_party/WebKit/Source/web/WebRuntimeFeatures.cpp +++ b/third_party/WebKit/Source/web/WebRuntimeFeatures.cpp
@@ -178,6 +178,10 @@ RuntimeEnabledFeatures::setNetworkInformationEnabled(enable); } +void WebRuntimeFeatures::enableOnDeviceChange(bool enable) { + RuntimeEnabledFeatures::setOnDeviceChangeEnabled(enable); +} + void WebRuntimeFeatures::enableOrientationEvent(bool enable) { RuntimeEnabledFeatures::setOrientationEventEnabled(enable); } @@ -356,4 +360,8 @@ RuntimeEnabledFeatures::setRemotePlaybackEnabled(enable); } +void WebRuntimeFeatures::enableVideoFullscreenOrientationLock(bool enable) { + RuntimeEnabledFeatures::setVideoFullscreenOrientationLockEnabled(enable); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/wtf/HashCountedSet.h b/third_party/WebKit/Source/wtf/HashCountedSet.h index fc60257d..6e0db4e 100644 --- a/third_party/WebKit/Source/wtf/HashCountedSet.h +++ b/third_party/WebKit/Source/wtf/HashCountedSet.h
@@ -53,7 +53,13 @@ typedef typename ImplType::const_iterator const_iterator; typedef typename ImplType::AddResult AddResult; - HashCountedSet() {} + HashCountedSet() { + static_assert(Allocator::isGarbageCollected || + !IsPointerToGarbageCollectedType<Value>::value, + "Cannot put raw pointers to garbage-collected classes into " + "an off-heap HashCountedSet. Use " + "HeapHashCountedSet<Member<T>> instead."); + } void swap(HashCountedSet& other) { m_impl.swap(other.m_impl); }
diff --git a/third_party/WebKit/Source/wtf/HashMap.h b/third_party/WebKit/Source/wtf/HashMap.h index b6f381d..b503ec6 100644 --- a/third_party/WebKit/Source/wtf/HashMap.h +++ b/third_party/WebKit/Source/wtf/HashMap.h
@@ -78,12 +78,22 @@ class HashMapValuesProxy; public: + HashMap() { + static_assert(Allocator::isGarbageCollected || + !IsPointerToGarbageCollectedType<KeyArg>::value, + "Cannot put raw pointers to garbage-collected classes into " + "an off-heap HashMap. Use HeapHashMap<> instead."); + static_assert(Allocator::isGarbageCollected || + !IsPointerToGarbageCollectedType<MappedArg>::value, + "Cannot put raw pointers to garbage-collected classes into " + "an off-heap HashMap. Use HeapHashMap<> instead."); + } + typedef HashTableIteratorAdapter<HashTableType, ValueType> iterator; typedef HashTableConstIteratorAdapter<HashTableType, ValueType> const_iterator; typedef typename HashTableType::AddResult AddResult; - public: void swap(HashMap& ref) { m_impl.swap(ref.m_impl); } unsigned size() const;
diff --git a/third_party/WebKit/Source/wtf/HashSet.h b/third_party/WebKit/Source/wtf/HashSet.h index 72b97fc..268ec6a3 100644 --- a/third_party/WebKit/Source/wtf/HashSet.h +++ b/third_party/WebKit/Source/wtf/HashSet.h
@@ -63,7 +63,12 @@ const_iterator; typedef typename HashTableType::AddResult AddResult; - HashSet() = default; + HashSet() { + static_assert(Allocator::isGarbageCollected || + !IsPointerToGarbageCollectedType<ValueArg>::value, + "Cannot put raw pointers to garbage-collected classes into " + "an off-heap HashSet. Use HeapHashSet<Member<T>> instead."); + } HashSet(const HashSet&) = default; HashSet& operator=(const HashSet&) = default; HashSet(HashSet&&) = default;
diff --git a/third_party/WebKit/Source/wtf/LinkedHashSet.h b/third_party/WebKit/Source/wtf/LinkedHashSet.h index 65f5100..0a2235a 100644 --- a/third_party/WebKit/Source/wtf/LinkedHashSet.h +++ b/third_party/WebKit/Source/wtf/LinkedHashSet.h
@@ -598,8 +598,14 @@ friend class LinkedHashSet; }; -template <typename T, typename U, typename V, typename W> -inline LinkedHashSet<T, U, V, W>::LinkedHashSet() {} +template <typename T, typename U, typename V, typename Allocator> +inline LinkedHashSet<T, U, V, Allocator>::LinkedHashSet() { + static_assert( + Allocator::isGarbageCollected || + !IsPointerToGarbageCollectedType<T>::value, + "Cannot put raw pointers to garbage-collected classes into " + "an off-heap LinkedHashSet. Use HeapLinkedHashSet<Member<T>> instead."); +} template <typename T, typename U, typename V, typename W> inline LinkedHashSet<T, U, V, W>::LinkedHashSet(const LinkedHashSet& other)
diff --git a/third_party/WebKit/Source/wtf/ListHashSet.h b/third_party/WebKit/Source/wtf/ListHashSet.h index c939359f..8522861 100644 --- a/third_party/WebKit/Source/wtf/ListHashSet.h +++ b/third_party/WebKit/Source/wtf/ListHashSet.h
@@ -733,9 +733,15 @@ } }; -template <typename T, size_t inlineCapacity, typename U, typename V> -inline ListHashSet<T, inlineCapacity, U, V>::ListHashSet() - : m_head(nullptr), m_tail(nullptr) {} +template <typename T, size_t inlineCapacity, typename U, typename Allocator> +inline ListHashSet<T, inlineCapacity, U, Allocator>::ListHashSet() + : m_head(nullptr), m_tail(nullptr) { + static_assert( + Allocator::isGarbageCollected || + !IsPointerToGarbageCollectedType<T>::value, + "Cannot put raw pointers to garbage-collected classes into " + "an off-heap ListHashSet. Use HeapListHashSet<Member<T>> instead."); +} template <typename T, size_t inlineCapacity, typename U, typename V> inline ListHashSet<T, inlineCapacity, U, V>::ListHashSet(
diff --git a/third_party/WebKit/public/web/WebRuntimeFeatures.h b/third_party/WebKit/public/web/WebRuntimeFeatures.h index fe4b0e0..2f448c9 100644 --- a/third_party/WebKit/public/web/WebRuntimeFeatures.h +++ b/third_party/WebKit/public/web/WebRuntimeFeatures.h
@@ -92,6 +92,7 @@ BLINK_EXPORT static void enableNotificationConstructor(bool); BLINK_EXPORT static void enableNotificationContentImage(bool); BLINK_EXPORT static void enableNotifications(bool); + BLINK_EXPORT static void enableOnDeviceChange(bool); BLINK_EXPORT static void enableOrientationEvent(bool); BLINK_EXPORT static void enableOverlayScrollbars(bool); BLINK_EXPORT static void enablePagePopup(bool); @@ -137,6 +138,7 @@ BLINK_EXPORT static void enableCanvas2dDynamicRenderingModeSwitching(bool); BLINK_EXPORT static void enableSendBeaconThrowForBlobWithNonSimpleType(bool); BLINK_EXPORT static void enableBackgroundVideoTrackOptimization(bool); + BLINK_EXPORT static void enableVideoFullscreenOrientationLock(bool); private: WebRuntimeFeatures();
diff --git a/tools/android/customtabs_benchmark/java/src/org/chromium/customtabs/test/MainActivity.java b/tools/android/customtabs_benchmark/java/src/org/chromium/customtabs/test/MainActivity.java index 25ee24b..b1b336d4 100644 --- a/tools/android/customtabs_benchmark/java/src/org/chromium/customtabs/test/MainActivity.java +++ b/tools/android/customtabs_benchmark/java/src/org/chromium/customtabs/test/MainActivity.java
@@ -109,17 +109,11 @@ break; case CustomTabsCallback.NAVIGATION_FINISHED: mPageLoadFinishedMs = SystemClock.uptimeMillis(); - if (mIntentSentMs != NONE && mPageLoadStartedMs != NONE) { - if (mFirstContentfulPaintMs != NONE) { - logMetricsAndFinish(); - } else { - logMetricsAndFinishDelayed(3000); - } - } break; default: break; } + if (allSet()) logMetricsAndFinish(); } @Override @@ -132,7 +126,12 @@ if (mFirstContentfulPaintMs == NONE) { mFirstContentfulPaintMs = navigationStartMs + firstPaintMs; } - if (mPageLoadFinishedMs != NONE) logMetricsAndFinish(); + if (allSet()) logMetricsAndFinish(); + } + + private boolean allSet() { + return mIntentSentMs != NONE && mPageLoadStartedMs != NONE + && mFirstContentfulPaintMs != NONE && mPageLoadFinishedMs != NONE; } /** Outputs the available metrics, and die. Unavalaible metrics are set to -1. */ @@ -153,7 +152,7 @@ public void run() { logMetricsAndFinish(); } - }, 3000); + }, delayMs); } }
diff --git a/tools/android/customtabs_benchmark/scripts/customtabs_benchmark.py b/tools/android/customtabs_benchmark/scripts/customtabs_benchmark.py index 219a1751..d4222b21 100755 --- a/tools/android/customtabs_benchmark/scripts/customtabs_benchmark.py +++ b/tools/android/customtabs_benchmark/scripts/customtabs_benchmark.py
@@ -37,6 +37,8 @@ _CHROME_PACKAGE = 'com.google.android.apps.chrome' _COMMAND_LINE_PATH = '/data/local/tmp/chrome-command-line' _TEST_APP_PACKAGE_NAME = 'org.chromium.customtabsclient.test' +_INVALID_VALUE = -1 + # Command line arguments for Chrome. CHROME_ARGS = [ @@ -151,8 +153,9 @@ assert len(tokens) == 8 intent_sent_timestamp = int(tokens[4]) return Result(bool(tokens[0]), tokens[1], int(tokens[2]), int(tokens[3]), - int(tokens[5]) - intent_sent_timestamp, - int(tokens[6]) - intent_sent_timestamp, int(tokens[7])) + max(_INVALID_VALUE, int(tokens[5]) - intent_sent_timestamp), + max(_INVALID_VALUE, int(tokens[6]) - intent_sent_timestamp), + max(_INVALID_VALUE, int(tokens[7]) - intent_sent_timestamp)) def LoopOnDevice(device, configs, output_filename, wpr_archive_path=None, @@ -221,9 +224,9 @@ result['speculation_mode'] = data[:, 1] result['delay_to_may_launch_url'] = data[:, 2] result['delay_to_launch_url'] = data[:, 3] - result['commit'] = data[:, 5] - data[:, 4] - result['plt'] = data[:, 6] - data[:, 4] - result['first_contentful_paint'] = data[7] + result['commit'] = data[:, 4] + result['plt'] = data[:, 5] + result['first_contentful_paint'] = data[:, 6] return result
diff --git a/tools/gn/input_file_manager.cc b/tools/gn/input_file_manager.cc index c695655..9fd3def 100644 --- a/tools/gn/input_file_manager.cc +++ b/tools/gn/input_file_manager.cc
@@ -147,9 +147,7 @@ } } } - g_scheduler->pool()->PostWorkerTaskWithShutdownBehavior( - FROM_HERE, schedule_this, - base::SequencedWorkerPool::BLOCK_SHUTDOWN); + g_scheduler->ScheduleWork(schedule_this); return true; }
diff --git a/tools/gn/scheduler.h b/tools/gn/scheduler.h index 67650d8..e20bced 100644 --- a/tools/gn/scheduler.h +++ b/tools/gn/scheduler.h
@@ -33,7 +33,6 @@ scoped_refptr<base::SingleThreadTaskRunner> task_runner() { return main_loop_.task_runner(); } - base::SequencedWorkerPool* pool() { return pool_.get(); } InputFileManager* input_file_manager() { return input_file_manager_.get(); }
diff --git a/tools/gritsettings/resource_ids b/tools/gritsettings/resource_ids index c5005129..626d01fc 100644 --- a/tools/gritsettings/resource_ids +++ b/tools/gritsettings/resource_ids
@@ -352,6 +352,11 @@ "devtools_resources.grd": { "includes": [28450], }, + + "cloud_print/virtual_driver/win/install/virtual_driver_setup_resources.grd": { + "includes": [28600], + "messages": [28650], + }, # END "everything else" section. # Everything but chrome/, components/, content/, and ios/
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl index 8f13b15..8c9ca90 100644 --- a/tools/mb/mb_config.pyl +++ b/tools/mb/mb_config.pyl
@@ -125,7 +125,7 @@ 'CrWinClang(dbg)': 'clang_debug_bot_minimal_symbols_x86', 'CrWinClang64': 'clang_official_release_bot_minimal_symbols', - 'CrWinClang64(dll)': 'clang_minimal_symbols_shared_release_bot', + 'CrWinClang64(dll)': 'clang_shared_release_bot', 'CrWinClangGoma': 'clang_official_optimize_release_bot_minimal_symbols_x86', 'CrWinGoma': 'release_bot_x86', 'CrWinGoma(dll)': 'shared_release_bot_x86', @@ -146,7 +146,7 @@ 'ClangToTWin(dll)': 'clang_tot_minimal_symbols_shared_release_x86', 'ClangToTWin64': 'clang_tot_official_minimal_symbols_static_release', 'ClangToTWin64(dbg)': 'clang_tot_minimal_symbols_shared_debug', - 'ClangToTWin64(dll)': 'clang_tot_minimal_symbols_shared_release', + 'ClangToTWin64(dll)': 'clang_tot_shared_release', 'ClangToTiOS': 'ios', 'Closure Compilation Linux': 'closure_compilation', 'CrWinAsan': 'asan_clang_fuzzer_static_v8_heap_x86_full_symbols_release', @@ -1034,8 +1034,8 @@ 'clang', 'official', 'release_trybot', 'x86', ], - 'clang_minimal_symbols_shared_release_bot': [ - 'clang', 'minimal_symbols', 'shared_release_bot', + 'clang_shared_release_bot': [ + 'clang', 'shared_release_bot', ], 'clang_tot_asan_lsan_static_release': [ @@ -1084,6 +1084,10 @@ 'clang_tot', 'minimal_symbols', 'shared', 'release', ], + 'clang_tot_shared_release': [ + 'clang_tot', 'shared', 'release', + ], + 'clang_tot_minimal_symbols_shared_release_x86': [ 'clang_tot', 'minimal_symbols', 'shared', 'release', 'x86', ],
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 199b3e4..486a2df 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -31341,6 +31341,14 @@ </summary> </histogram> +<histogram name="Net.HttpJob.PrefilterBytesRead" units="bytes"> + <owner>jkarlin@chromium.org</owner> + <summary> + Total prefilter (e.g., before decompression) bytes read for an HttpJob + request. + </summary> +</histogram> + <histogram name="Net.HttpJob.TotalTime" units="ms"> <owner>mmenke@chromium.org</owner> <summary> @@ -92435,6 +92443,7 @@ <int value="-741806604" label="DownloadsUi:disabled"/> <int value="-723224470" label="enable-password-force-saving:enabled"/> <int value="-716953514" label="disable-password-separated-signin-flow"/> + <int value="-714710496" label="VideoFullscreenOrientationLock:disabled"/> <int value="-711890895" label="enable-website-settings-manager"/> <int value="-699767107" label="enable-sync-app-list"/> <int value="-697751423" label="disable-quickoffice-component-app"/> @@ -92641,6 +92650,7 @@ <int value="379326303" label="enable-add-to-shelf"/> <int value="379428799" label="security-chip-animation"/> <int value="385969127" label="disable-win32k-lockdown"/> + <int value="387178525" label="VideoFullscreenOrientationLock:enabled"/> <int value="400322063" label="ash-disable-screen-orientation-lock"/> <int value="401983950" label="enable-spdy4"/> <int value="402143634" label="enable-search-button-in-omnibox-always"/> @@ -109025,6 +109035,12 @@ <affected-histogram name="HttpCache.PercentBeforeSend"/> </histogram_suffixes> +<histogram_suffixes name="HttpJobBytes" separator="."> + <suffix name="Cache" label="For requests served from the cache."/> + <suffix name="Net" label="For requests served from the network."/> + <affected-histogram name="Net.HttpJob.PrefilterBytesRead"/> +</histogram_suffixes> + <histogram_suffixes name="HttpPipeliningCompatibility"> <suffix name="disable_test" label="Do nothing"/> <suffix name="enable_test" label="Test connection for HTTP pipelining"/>
diff --git a/tools/resource_prefetch_predictor/prefetch_benchmark.py b/tools/resource_prefetch_predictor/prefetch_benchmark.py index 95be021..518af04 100755 --- a/tools/resource_prefetch_predictor/prefetch_benchmark.py +++ b/tools/resource_prefetch_predictor/prefetch_benchmark.py
@@ -48,6 +48,8 @@ parser.add_argument('--url', help='URL to load.') parser.add_argument('--prefetch_delay_ms', help='Prefetch delay in ms. -1 to disable prefetch.') + parser.add_argument('--output_filename', + help='CSV file to append the result to.') return parser @@ -97,9 +99,9 @@ result = customtabs_benchmark.RunOnce( device, url, warmup=True, speculation_mode=prefetch_mode, delay_to_may_launch_url=2000, - delay_to_launch_url=max(0, prefetch_delay_ms), cold=False, + delay_to_launch_url=prefetch_delay_ms, cold=False, chrome_args=chrome_args, reset_chrome_state=False) - print customtabs_benchmark.ParseResult(result) + return customtabs_benchmark.ParseResult(result) def main(): @@ -115,7 +117,10 @@ sys.exit(1) _Setup(device, args.database) - _Go(device, args.url, int(args.prefetch_delay_ms)) + result = _Go(device, args.url, int(args.prefetch_delay_ms)) + print result + with open(args.output_filename, 'a') as f: + f.write(','.join(str(x) for x in result) + '\n') if __name__ == '__main__':
diff --git a/ui/aura/mus/window_compositor_frame_sink.cc b/ui/aura/mus/window_compositor_frame_sink.cc index 21f623a..7d252b89 100644 --- a/ui/aura/mus/window_compositor_frame_sink.cc +++ b/ui/aura/mus/window_compositor_frame_sink.cc
@@ -113,7 +113,6 @@ void WindowCompositorFrameSink::WillDrawSurface() { // TODO(fsamuel, staraz): Implement this. - NOTIMPLEMENTED(); } void WindowCompositorFrameSink::OnNeedsBeginFrames(bool needs_begin_frames) {
diff --git a/ui/gfx/vector_icons/BUILD.gn b/ui/gfx/vector_icons/BUILD.gn index 77a55f86..0645973a 100644 --- a/ui/gfx/vector_icons/BUILD.gn +++ b/ui/gfx/vector_icons/BUILD.gn
@@ -2,6 +2,8 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/config/chrome_build.gni") + action("aggregate_vector_icons") { visibility = [ ":*" ] @@ -26,7 +28,6 @@ "check_circle.icon", "checkbox_active.icon", "checkbox_normal.icon", - "chrome_product.icon", "close_all.icon", "code.icon", "combobox_arrow_mac_disabled.icon", @@ -173,6 +174,7 @@ "window_control_right_snapped.icon", "zoom_minus.icon", "zoom_plus.icon", + "${branding_path_component}/product.icon", ] output_cc = "$target_gen_dir/vector_icons.cc"
diff --git a/ui/gfx/vector_icons/chrome_product.icon b/ui/gfx/vector_icons/chromium/product.icon similarity index 100% rename from ui/gfx/vector_icons/chrome_product.icon rename to ui/gfx/vector_icons/chromium/product.icon
diff --git a/ui/gfx/vector_icons/google_chrome/product.icon b/ui/gfx/vector_icons/google_chrome/product.icon new file mode 100644 index 0000000..ec96ab98 --- /dev/null +++ b/ui/gfx/vector_icons/google_chrome/product.icon
@@ -0,0 +1,43 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +CANVAS_DIMENSIONS, 24, +// Red +PATH_COLOR_ARGB, 0xFF, 0xDB, 0x44, 0x37, +MOVE_TO, 12, 7.5f, +R_H_LINE_TO, 8.9f, +CUBIC_TO, 19.3f, 4.2f, 15.9f, 2, 12, 2, +CUBIC_TO, 8.9f, 2, 6.1f, 3.4f, 4.3f, 5.6f, +R_LINE_TO, 3.3f, 5.7f, +R_CUBIC_TO, 0.3f, -2.1f, 2.2f, -3.8f, 4.4f, -3.8f, +CLOSE, +NEW_PATH, +// Green +PATH_COLOR_ARGB, 0xFF, 0x0F, 0x9D, 0x58, +// R_MOVE_TO, 0, 9, +MOVE_TO, 12, 16.5f, +R_CUBIC_TO, -1.7f, 0, -3.1f, -0.9f, -3.9f, -2.3f, +LINE_TO, 3.6f, 6.5f, +CUBIC_TO, 2.6f, 8.1f, 2, 10, 2, 12, +R_CUBIC_TO, 0, 5, 3.6f, 9.1f, 8.4f, 9.9f, +R_LINE_TO, 3.3f, -5.7f, +R_CUBIC_TO, -0.6f, 0.2f, -1.1f, 0.3f, -1.7f, 0.3f, +CLOSE, +NEW_PATH, +// Yellow +PATH_COLOR_ARGB, 0xFF, 0xFF, 0xCD, 0x40, +MOVE_TO, 16.5f, 12, +R_CUBIC_TO, 0, 0.8f, -0.2f, 1.6f, -0.6f, 2.2f, +LINE_TO, 11.4f, 22, +R_H_LINE_TO, 0.6f, +R_CUBIC_TO, 5.5f, 0, 10, -4.5f, 10, -10, +R_CUBIC_TO, 0, -1.2f, -0.2f, -2.4f, -0.6f, -3.5f, +R_H_LINE_TO, -6.6f, +R_CUBIC_TO, 1, 0.8f, 1.7f, 2.1f, 1.7f, 3.5f, +CLOSE, +NEW_PATH, +// Blue +PATH_COLOR_ARGB, 0xFF, 0x42, 0x85, 0xF4, +CIRCLE, 12, 12, 3.5, +END
diff --git a/ui/gl/BUILD.gn b/ui/gl/BUILD.gn index 5050c891..e7705f6 100644 --- a/ui/gl/BUILD.gn +++ b/ui/gl/BUILD.gn
@@ -154,6 +154,8 @@ if (use_egl) { sources += [ + "angle_platform_impl.cc", + "angle_platform_impl.h", "egl_util.cc", "egl_util.h", "gl_bindings_autogen_egl.cc", @@ -219,8 +221,6 @@ } if (is_win) { sources += [ - "angle_platform_impl.cc", - "angle_platform_impl.h", "gl_bindings_autogen_wgl.cc", "gl_bindings_autogen_wgl.h", "gl_context_wgl.cc",
diff --git a/ui/gl/egl_api_unittest.cc b/ui/gl/egl_api_unittest.cc index b9dbd15a..772cf06 100644 --- a/ui/gl/egl_api_unittest.cc +++ b/ui/gl/egl_api_unittest.cc
@@ -25,6 +25,7 @@ g_driver_egl.fn.eglGetCurrentDisplayFn = &FakeGetCurrentDisplay; g_driver_egl.fn.eglGetDisplayFn = &FakeGetDisplay; g_driver_egl.fn.eglGetErrorFn = &FakeGetError; + g_driver_egl.fn.eglGetProcAddressFn = &FakeGetProcAddress; } void TearDown() override { @@ -82,6 +83,11 @@ return EGL_SUCCESS; } + static __eglMustCastToProperFunctionPointerType GL_BINDING_CALL + FakeGetProcAddress(const char* procname) { + return nullptr; + } + std::pair<const char*, const char*> GetExtensions() { return std::make_pair( api_->eglQueryStringFn(EGL_NO_DISPLAY, EGL_EXTENSIONS),
diff --git a/ui/gl/gl_surface_egl.cc b/ui/gl/gl_surface_egl.cc index 54ffb7dd..56032ca9 100644 --- a/ui/gl/gl_surface_egl.cc +++ b/ui/gl/gl_surface_egl.cc
@@ -12,6 +12,7 @@ #include <vector> #include "base/command_line.h" +#include "base/lazy_instance.h" #include "base/logging.h" #include "base/macros.h" #include "base/message_loop/message_loop.h" @@ -21,6 +22,7 @@ #include "base/trace_event/trace_event.h" #include "build/build_config.h" #include "ui/gfx/geometry/rect.h" +#include "ui/gl/angle_platform_impl.h" #include "ui/gl/egl_util.h" #include "ui/gl/gl_context.h" #include "ui/gl/gl_context_egl.h" @@ -134,6 +136,10 @@ bool g_egl_surface_orientation_supported = false; bool g_use_direct_composition = false; +base::LazyInstance<ANGLEPlatformImpl> g_angle_platform_impl = + LAZY_INSTANCE_INITIALIZER; +ANGLEPlatformShutdownFunc g_angle_platform_shutdown = nullptr; + EGLDisplay GetPlatformANGLEDisplay(EGLNativeDisplayType native_display, EGLenum platform_type, bool warpDevice) { @@ -533,7 +539,11 @@ } // static -void GLSurfaceEGL::ResetForTesting() { +void GLSurfaceEGL::ShutdownOneOff() { + if (g_angle_platform_shutdown) { + g_angle_platform_shutdown(); + } + if (g_display != EGL_NO_DISPLAY) eglTerminate(g_display); g_display = EGL_NO_DISPLAY; @@ -607,6 +617,17 @@ g_native_display = native_display; + // Init ANGLE platform here, before we call GetPlatformDisplay(). + ANGLEPlatformInitializeFunc angle_platform_init = + reinterpret_cast<ANGLEPlatformInitializeFunc>( + eglGetProcAddress("ANGLEPlatformInitialize")); + if (angle_platform_init) { + angle_platform_init(&g_angle_platform_impl.Get()); + + g_angle_platform_shutdown = reinterpret_cast<ANGLEPlatformShutdownFunc>( + eglGetProcAddress("ANGLEPlatformShutdown")); + } + // If EGL_EXT_client_extensions not supported this call to eglQueryString // will return NULL. const char* client_extensions =
diff --git a/ui/gl/gl_surface_egl.h b/ui/gl/gl_surface_egl.h index 1a0e7055..dc000eba 100644 --- a/ui/gl/gl_surface_egl.h +++ b/ui/gl/gl_surface_egl.h
@@ -78,7 +78,7 @@ GLSurface::Format GetFormat() override; static bool InitializeOneOff(EGLNativeDisplayType native_display); - static void ResetForTesting(); + static void ShutdownOneOff(); static EGLDisplay GetHardwareDisplay(); static EGLDisplay InitializeDisplay(EGLNativeDisplayType native_display); static EGLNativeDisplayType GetNativeDisplay();
diff --git a/ui/gl/init/gl_initializer_android.cc b/ui/gl/init/gl_initializer_android.cc index d528ad4..f338cc0 100644 --- a/ui/gl/init/gl_initializer_android.cc +++ b/ui/gl/init/gl_initializer_android.cc
@@ -97,6 +97,7 @@ } void ShutdownGLPlatform() { + GLSurfaceEGL::ShutdownOneOff(); ClearBindingsEGL(); ClearBindingsGL(); ClearBindingsOSMESA();
diff --git a/ui/gl/init/gl_initializer_ozone.cc b/ui/gl/init/gl_initializer_ozone.cc index 624e43b..213ef8b 100644 --- a/ui/gl/init/gl_initializer_ozone.cc +++ b/ui/gl/init/gl_initializer_ozone.cc
@@ -92,6 +92,7 @@ } void ShutdownGLPlatform() { + GLSurfaceEGL::ShutdownOneOff(); if (HasGLOzone()) { GetGLOzone()->ShutdownGL(); return;
diff --git a/ui/gl/init/gl_initializer_win.cc b/ui/gl/init/gl_initializer_win.cc index 5b0fc28..89a3586 100644 --- a/ui/gl/init/gl_initializer_win.cc +++ b/ui/gl/init/gl_initializer_win.cc
@@ -11,7 +11,6 @@ #include "base/bind.h" #include "base/command_line.h" #include "base/files/file_path.h" -#include "base/lazy_instance.h" #include "base/logging.h" #include "base/native_library.h" #include "base/path_service.h" @@ -19,8 +18,6 @@ #include "base/threading/thread_restrictions.h" #include "base/trace_event/trace_event.h" #include "base/win/windows_version.h" -// TODO(jmadill): Apply to all platforms eventually -#include "ui/gl/angle_platform_impl.h" #include "ui/gl/gl_bindings.h" #include "ui/gl/gl_egl_api_implementation.h" #include "ui/gl/gl_features.h" @@ -38,12 +35,6 @@ const wchar_t kD3DCompiler[] = L"D3DCompiler_47.dll"; -// TODO(jmadill): Apply to all platforms eventually -base::LazyInstance<ANGLEPlatformImpl> g_angle_platform_impl = - LAZY_INSTANCE_INITIALIZER; - -ANGLEPlatformShutdownFunc g_angle_platform_shutdown = nullptr; - bool LoadD3DXLibrary(const base::FilePath& module_path, const base::FilePath::StringType& name) { base::NativeLibrary library = @@ -152,22 +143,6 @@ } #endif - if (!using_swift_shader) { - // Init ANGLE platform here, before we call GetPlatformDisplay(). - // TODO(jmadill): Apply to all platforms eventually - ANGLEPlatformInitializeFunc angle_platform_init = - reinterpret_cast<ANGLEPlatformInitializeFunc>( - base::GetFunctionPointerFromNativeLibrary( - gles_library, "ANGLEPlatformInitialize")); - if (angle_platform_init) { - angle_platform_init(&g_angle_platform_impl.Get()); - - g_angle_platform_shutdown = reinterpret_cast<ANGLEPlatformShutdownFunc>( - base::GetFunctionPointerFromNativeLibrary(gles_library, - "ANGLEPlatformShutdown")); - } - } - GLGetProcAddressProc get_proc_address = reinterpret_cast<GLGetProcAddressProc>( base::GetFunctionPointerFromNativeLibrary(egl_library, @@ -320,11 +295,7 @@ } void ShutdownGLPlatform() { - // TODO(jmadill): Apply to all platforms eventually - if (g_angle_platform_shutdown) { - g_angle_platform_shutdown(); - } - + GLSurfaceEGL::ShutdownOneOff(); ClearBindingsEGL(); ClearBindingsGL(); ClearBindingsOSMESA();
diff --git a/ui/gl/init/gl_initializer_x11.cc b/ui/gl/init/gl_initializer_x11.cc index a41e5ce..27fca039 100644 --- a/ui/gl/init/gl_initializer_x11.cc +++ b/ui/gl/init/gl_initializer_x11.cc
@@ -186,6 +186,7 @@ } void ShutdownGLPlatform() { + GLSurfaceEGL::ShutdownOneOff(); ClearBindingsEGL(); ClearBindingsGL(); ClearBindingsGLX();
diff --git a/ui/ozone/common/gl_ozone_egl.cc b/ui/ozone/common/gl_ozone_egl.cc index d63b305..7abf320 100644 --- a/ui/ozone/common/gl_ozone_egl.cc +++ b/ui/ozone/common/gl_ozone_egl.cc
@@ -41,7 +41,7 @@ } void GLOzoneEGL::ShutdownGL() { - gl::GLSurfaceEGL::ResetForTesting(); + gl::GLSurfaceEGL::ShutdownOneOff(); gl::ClearBindingsGL(); gl::ClearBindingsEGL(); }
diff --git a/ui/views/views_delegate.h b/ui/views/views_delegate.h index 7d61c8c5..5eb80096 100644 --- a/ui/views/views_delegate.h +++ b/ui/views/views_delegate.h
@@ -193,7 +193,9 @@ // Returns a blocking pool task runner given a TaskRunnerType. virtual scoped_refptr<base::TaskRunner> GetBlockingPoolTaskRunner(); - // Returns the insets that should be applied around a DialogClientView. + // Returns the insets that should be applied around a DialogClientView. Note + // that the top inset is used for the distance between the buttons and the + // DialogClientView's content view. virtual gfx::Insets GetDialogButtonInsets(); // Returns the spacing between a pair of related horizontal buttons, used for
diff --git a/ui/views/window/dialog_client_view.cc b/ui/views/window/dialog_client_view.cc index 2950d2a0..cf50c1c6 100644 --- a/ui/views/window/dialog_client_view.cc +++ b/ui/views/window/dialog_client_view.cc
@@ -170,7 +170,7 @@ int buttons_height = GetButtonsAndExtraViewRowHeight(); if (buttons_height != 0) { - size.Enlarge(0, buttons_height + kRelatedControlVerticalSpacing); + size.Enlarge(0, buttons_height + GetButtonsAndExtraViewRowTopPadding()); // Inset the buttons and extra view. const gfx::Insets insets = GetButtonRowInsets(); size.Enlarge(insets.width(), insets.height()); @@ -212,7 +212,7 @@ GetDialogDelegate()->GetExtraViewPadding(&custom_padding)) { // The call to LayoutButton() will already have accounted for some of // the padding. - custom_padding -= kRelatedButtonHSpacing; + custom_padding -= GetButtonsAndExtraViewRowTopPadding(); row_bounds.set_width(row_bounds.width() - custom_padding); } row_bounds.set_width(std::min(row_bounds.width(), @@ -220,17 +220,8 @@ extra_view_->SetBoundsRect(row_bounds); } - if (height > 0) { - // If the ViewsDelegate supplies a non-zero top inset, use that; - // otherwise, use kRelatedControlVerticalSpacing. - int spacing = - ViewsDelegate::GetInstance() - ? ViewsDelegate::GetInstance()->GetDialogButtonInsets().top() - : 0; - if (!spacing) - spacing = kRelatedControlVerticalSpacing; - bounds.Inset(0, 0, 0, height + spacing); - } + if (height > 0) + bounds.Inset(0, 0, 0, height + GetButtonsAndExtraViewRowTopPadding()); } // Layout the contents view to the top and side edges of the contents bounds. @@ -365,6 +356,18 @@ : button_row_insets_; } +int DialogClientView::GetButtonsAndExtraViewRowTopPadding() const { + int spacing = button_row_insets_.top(); + // Some subclasses of DialogClientView, in order to do their own layout, set + // button_row_insets_ to gfx::Insets(). To avoid breaking behavior of those + // dialogs, supplying 0 for the top inset of the row falls back to + // kRelatedControlVerticalSpacing. + // TODO(ellyjones): Figure out a more principled way to approach that issue. + if (!spacing) + spacing = kRelatedControlVerticalSpacing; + return spacing; +} + void DialogClientView::SetupFocusChain() { // Create a vector of child views in the order of intended focus. std::vector<View*> child_views;
diff --git a/ui/views/window/dialog_client_view.h b/ui/views/window/dialog_client_view.h index 3fb88c08b..1d2b3de 100644 --- a/ui/views/window/dialog_client_view.h +++ b/ui/views/window/dialog_client_view.h
@@ -99,6 +99,10 @@ // Returns the insets for the buttons and extra view. gfx::Insets GetButtonRowInsets() const; + // Returns the vertical padding to place between the contents view and the + // buttons/extra view. + int GetButtonsAndExtraViewRowTopPadding() const; + // How much to inset the button row. gfx::Insets button_row_insets_;