diff --git a/ash/wm/panels/panel_frame_view.cc b/ash/wm/panels/panel_frame_view.cc index 733af9ad..87e6f34 100644 --- a/ash/wm/panels/panel_frame_view.cc +++ b/ash/wm/panels/panel_frame_view.cc
@@ -32,6 +32,11 @@ PanelFrameView::~PanelFrameView() { } +void PanelFrameView::SetFrameColors(SkColor active_frame_color, + SkColor inactive_frame_color) { + header_painter_->SetFrameColors(active_frame_color, inactive_frame_color); +} + const char* PanelFrameView::GetClassName() const { return kViewClassName; }
diff --git a/ash/wm/panels/panel_frame_view.h b/ash/wm/panels/panel_frame_view.h index f4ba33be..d51a72a 100644 --- a/ash/wm/panels/panel_frame_view.h +++ b/ash/wm/panels/panel_frame_view.h
@@ -31,6 +31,10 @@ PanelFrameView(views::Widget* frame, FrameType frame_type); ~PanelFrameView() override; + // Sets the active and inactive frame colors. Note the inactive frame color + // will have some transparency added when the frame is drawn. + void SetFrameColors(SkColor active_frame_color, SkColor inactive_frame_color); + // Overridden from views::View: const char* GetClassName() const override;
diff --git a/build/android/gyp/create_java_binary_script.py b/build/android/gyp/create_java_binary_script.py index b73144b8..324361d4 100755 --- a/build/android/gyp/create_java_binary_script.py +++ b/build/android/gyp/create_java_binary_script.py
@@ -30,13 +30,15 @@ self_dir = os.path.dirname(__file__) classpath = [{classpath}] -extra_java_args = {extra_java_args} +bootclasspath = [{bootclasspath}] extra_program_args = {extra_program_args} if os.getcwd() != self_dir: offset = os.path.relpath(self_dir, os.getcwd()) classpath = [os.path.join(offset, p) for p in classpath] + bootclasspath = [os.path.join(offset, p) for p in bootclasspath] java_cmd = ["java"] -java_cmd.extend(extra_java_args) +if bootclasspath: + java_cmd.append("-Xbootclasspath/p:" + ":".join(bootclasspath)) java_cmd.extend( ["-classpath", ":".join(classpath), "-enableassertions", \"{main_class}\"]) java_cmd.extend(extra_program_args) @@ -52,28 +54,28 @@ parser.add_option('--jar-path', help='Path to the main jar.') parser.add_option('--main-class', help='Name of the java class with the "main" entry point.') - parser.add_option('--classpath', action='append', + parser.add_option('--classpath', action='append', default=[], help='Classpath for running the jar.') - parser.add_option('--extra-java-args', - help='Extra args passed to the "java" cmd') + parser.add_option('--bootclasspath', action='append', default=[], + help='zip/jar files to add to bootclasspath for java cmd.') options, extra_program_args = parser.parse_args(argv) classpath = [options.jar_path] for cp_arg in options.classpath: classpath += build_utils.ParseGypList(cp_arg) - if options.extra_java_args: - extra_java_args = build_utils.ParseGypList(options.extra_java_args) - else: - extra_java_args = [] + bootclasspath = [] + for bootcp_arg in options.bootclasspath: + bootclasspath += build_utils.ParseGypList(bootcp_arg) run_dir = os.path.dirname(options.output) classpath = [os.path.relpath(p, run_dir) for p in classpath] with open(options.output, 'w') as script: script.write(script_template.format( - extra_java_args=repr(extra_java_args), classpath=('"%s"' % '", "'.join(classpath)), + bootclasspath=('"%s"' % '", "'.join(bootclasspath) + if bootclasspath else ''), main_class=options.main_class, extra_program_args=repr(extra_program_args)))
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni index 95a2420..57b3a1b 100644 --- a/build/config/android/internal_rules.gni +++ b/build/config/android/internal_rules.gni
@@ -166,10 +166,10 @@ if (defined(invoker.wrapper_script_args)) { args += [ "--" ] + invoker.wrapper_script_args } - if (defined(invoker.extra_java_args)) { + if (defined(invoker.bootclasspath)) { args += [ - "--extra-java-args", - invoker.extra_java_args, + "--bootclasspath", + invoker.bootclasspath, ] } } @@ -1033,7 +1033,7 @@ java_binary_script(binary_script_target_name) { forward_variables_from(invoker, [ - "extra_java_args", + "bootclasspath", "main_class", "wrapper_script_args", ]) @@ -1383,7 +1383,7 @@ java_binary_script("${_template_name}__java_binary_script") { forward_variables_from(invoker, [ - "extra_java_args", + "bootclasspath", "main_class", "wrapper_script_args", ])
diff --git a/cc/trees/layer_tree_host_common.cc b/cc/trees/layer_tree_host_common.cc index c9e88ac..4d14ff7 100644 --- a/cc/trees/layer_tree_host_common.cc +++ b/cc/trees/layer_tree_host_common.cc
@@ -1893,9 +1893,6 @@ accumulated_surface_state->push_back(AccumulatedSurfaceState(layer)); - // Don't clip if the layer has copy requests. - if (layer->HasCopyRequest()) - subtree_is_clipped_by_surface_bounds = false; render_surface->SetIsClipped(subtree_is_clipped_by_surface_bounds); if (!subtree_is_clipped_by_surface_bounds) { render_surface->SetClipRect(gfx::Rect());
diff --git a/cc/trees/layer_tree_host_common_unittest.cc b/cc/trees/layer_tree_host_common_unittest.cc index 9e8786a9..5ecd1b8 100644 --- a/cc/trees/layer_tree_host_common_unittest.cc +++ b/cc/trees/layer_tree_host_common_unittest.cc
@@ -5448,13 +5448,13 @@ inputs.can_adjust_raster_scales = true; LayerTreeHostCommon::CalculateDrawProperties(&inputs); - // We should have two render surface, as the others are clipped out. - ASSERT_EQ(2u, render_surface_layer_list.size()); + // We should have one render surface, as the others are clipped out. + ASSERT_EQ(1u, render_surface_layer_list.size()); EXPECT_EQ(root->id(), render_surface_layer_list.at(0)->id()); - // The root render surface should only have 2 contributing layer, since the + // The root render surface should only have 1 contributing layer, since the // other layers are empty/clipped away. - ASSERT_EQ(2u, root->render_surface()->layer_list().size()); + ASSERT_EQ(1u, root->render_surface()->layer_list().size()); EXPECT_EQ(root->id(), root->render_surface()->layer_list().at(0)->id()); }
diff --git a/cc/trees/layer_tree_host_unittest_copyrequest.cc b/cc/trees/layer_tree_host_unittest_copyrequest.cc index 0ddc7b7..802a014 100644 --- a/cc/trees/layer_tree_host_unittest_copyrequest.cc +++ b/cc/trees/layer_tree_host_unittest_copyrequest.cc
@@ -473,10 +473,10 @@ } void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) { - // We should still get the content even if the copy requested layer was - // completely clipped away. + // We should still get a callback with no output if the copy requested layer + // was completely clipped away. EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread()); - EXPECT_EQ(gfx::Size(10, 10).ToString(), result->size().ToString()); + EXPECT_EQ(gfx::Size().ToString(), result->size().ToString()); EndTest(); }
diff --git a/cc/trees/property_tree_builder.cc b/cc/trees/property_tree_builder.cc index 435503c..2f1d954 100644 --- a/cc/trees/property_tree_builder.cc +++ b/cc/trees/property_tree_builder.cc
@@ -101,9 +101,7 @@ bool is_root = !layer->parent(); // Whether we have an ancestor clip that we might need to apply. - // Don't apply ancestor clip when the layer has copy requests. - bool ancestor_clips_subtree = - (is_root || parent->data.layers_are_clipped) && !layer->HasCopyRequest(); + bool ancestor_clips_subtree = is_root || parent->data.layers_are_clipped; bool layers_are_clipped = false; bool has_unclipped_surface = false; @@ -122,6 +120,7 @@ // of its own, but clips from ancestor nodes don't need to be considered // when computing clip rects or visibility. has_unclipped_surface = true; + DCHECK(!parent->data.applies_local_clip); } // A surface with unclipped descendants cannot be clipped by its ancestor // clip at draw time since the unclipped descendants aren't affected by the
diff --git a/chrome/VERSION b/chrome/VERSION index 0035e287..c104260 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=48 MINOR=0 -BUILD=2555 +BUILD=2556 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java index c5c1564..df3d8bb8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java
@@ -7,6 +7,7 @@ import android.content.Context; import android.content.SharedPreferences; import android.preference.PreferenceManager; +import android.util.Base64; import android.util.Log; import org.chromium.base.ThreadUtils; @@ -219,6 +220,45 @@ } } + // TODO(agulenko): Move this piece of code to a separate class. + + private static final String VARIATIONS_FIRST_RUN_SEED_BASE64 = "variations_seed_base64"; + private static final String VARIATIONS_FIRST_RUN_SEED_SIGNATURE = "variations_seed_signature"; + private static final String VARIATIONS_FIRST_RUN_SEED_COUNTRY = "variations_seed_country"; + + private static String getVariationsFirstRunSeedPref(Context context, String prefName) { + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + return prefs.getString(prefName, ""); + } + + public static void setVariationsFirstRunSeed( + Context context, byte[] rawSeed, String signature, String country) { + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); + prefs.edit() + .putString(VARIATIONS_FIRST_RUN_SEED_BASE64, + Base64.encodeToString(rawSeed, Base64.NO_WRAP)) + .putString(VARIATIONS_FIRST_RUN_SEED_SIGNATURE, signature) + .putString(VARIATIONS_FIRST_RUN_SEED_COUNTRY, country) + .apply(); + } + + @CalledByNative + private static byte[] getVariationsFirstRunSeedData(Context context) { + return Base64.decode( + getVariationsFirstRunSeedPref(context, VARIATIONS_FIRST_RUN_SEED_BASE64), + Base64.NO_WRAP); + } + + @CalledByNative + private static String getVariationsFirstRunSeedSignature(Context context) { + return getVariationsFirstRunSeedPref(context, VARIATIONS_FIRST_RUN_SEED_SIGNATURE); + } + + @CalledByNative + private static String getVariationsFirstRunSeedCountry(Context context) { + return getVariationsFirstRunSeedPref(context, VARIATIONS_FIRST_RUN_SEED_COUNTRY); + } + public boolean isAcceptCookiesEnabled() { return nativeGetAcceptCookiesEnabled(); }
diff --git a/chrome/browser/android/preferences/pref_service_bridge.cc b/chrome/browser/android/preferences/pref_service_bridge.cc index 5b5f4b5..96e721b 100644 --- a/chrome/browser/android/preferences/pref_service_bridge.cc +++ b/chrome/browser/android/preferences/pref_service_bridge.cc
@@ -5,13 +5,16 @@ #include "chrome/browser/android/preferences/pref_service_bridge.h" #include <jni.h> +#include <vector> #include "base/android/build_info.h" #include "base/android/jni_android.h" +#include "base/android/jni_array.h" #include "base/android/jni_string.h" #include "base/android/jni_weak_ref.h" #include "base/files/file_path.h" #include "base/files/file_util.h" +#include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "base/prefs/pref_service.h" #include "base/strings/string_util.h" @@ -36,6 +39,7 @@ #include "components/signin/core/common/signin_pref_names.h" #include "components/translate/core/browser/translate_prefs.h" #include "components/translate/core/common/translate_pref_names.h" +#include "components/variations/pref_names.h" #include "components/version_info/version_info.h" #include "components/web_resource/web_resource_pref_names.h" #include "content/public/browser/browser_thread.h" @@ -47,6 +51,7 @@ using base::android::CheckException; using base::android::ConvertJavaStringToUTF8; using base::android::ConvertUTF8ToJavaString; +using base::android::GetApplicationContext; using base::android::ScopedJavaLocalRef; using base::android::ScopedJavaGlobalRef; using content::BrowserThread; @@ -111,6 +116,14 @@ return GetOriginalProfile()->GetPrefs(); } +std::string JavaByteArrayToString(JNIEnv* env, jbyteArray byte_array) { + if (!byte_array) + return std::string(); + std::vector<uint8> array_data; + base::android::JavaByteArrayToByteVector(env, byte_array, &array_data); + return std::string(array_data.begin(), array_data.end()); +} + } // namespace // ---------------------------------------------------------------------------- @@ -948,3 +961,22 @@ return ConvertJavaStringToUTF8(android_permission); } + +// static +void PrefServiceBridge::GetVariationsFirstRunSeed(std::string* seed_data, + std::string* seed_signature, + std::string* seed_country) { + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jbyteArray> j_seed_data = + Java_PrefServiceBridge_getVariationsFirstRunSeedData( + env, GetApplicationContext()); + ScopedJavaLocalRef<jstring> j_seed_signature = + Java_PrefServiceBridge_getVariationsFirstRunSeedSignature( + env, GetApplicationContext()); + ScopedJavaLocalRef<jstring> j_seed_country = + Java_PrefServiceBridge_getVariationsFirstRunSeedCountry( + env, GetApplicationContext()); + *seed_data = JavaByteArrayToString(env, j_seed_data.obj()); + *seed_signature = ConvertJavaStringToUTF8(j_seed_signature); + *seed_country = ConvertJavaStringToUTF8(j_seed_country); +}
diff --git a/chrome/browser/android/preferences/pref_service_bridge.h b/chrome/browser/android/preferences/pref_service_bridge.h index 656a0fec..282364b 100644 --- a/chrome/browser/android/preferences/pref_service_bridge.h +++ b/chrome/browser/android/preferences/pref_service_bridge.h
@@ -26,6 +26,11 @@ // ContentSettingsType specified (or an empty string if no permission exists). static std::string GetAndroidPermissionForContentSetting( ContentSettingsType content_type); + + // Return the first run seed data pulled from the Java side of application. + static void GetVariationsFirstRunSeed(std::string* seed_data, + std::string* seed_signature, + std::string* seed_country); }; #endif // CHROME_BROWSER_ANDROID_PREFERENCES_PREF_SERVICE_BRIDGE_H_
diff --git a/chrome/browser/devtools/BUILD.gn b/chrome/browser/devtools/BUILD.gn index b1a1eed8..9b8f6ea 100644 --- a/chrome/browser/devtools/BUILD.gn +++ b/chrome/browser/devtools/BUILD.gn
@@ -121,6 +121,8 @@ "devtools_file_helper.h", "devtools_file_system_indexer.cc", "devtools_file_system_indexer.h", + "devtools_file_watcher.cc", + "devtools_file_watcher.h", "devtools_target_impl.cc", "devtools_target_impl.h", "devtools_targets_ui.cc",
diff --git a/chrome/browser/devtools/devtools_file_helper.cc b/chrome/browser/devtools/devtools_file_helper.cc index 361d739..d3a9312ba 100644 --- a/chrome/browser/devtools/devtools_file_helper.cc +++ b/chrome/browser/devtools/devtools_file_helper.cc
@@ -17,6 +17,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/value_conversions.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/devtools/devtools_file_watcher.h" #include "chrome/browser/download/download_prefs.h" #include "chrome/browser/platform_util.h" #include "chrome/browser/profiles/profile.h" @@ -212,9 +213,14 @@ pref_change_registrar_.Add(prefs::kDevToolsFileSystemPaths, base::Bind(&DevToolsFileHelper::FileSystemPathsSettingChanged, base::Unretained(this))); + file_watcher_.reset(new DevToolsFileWatcher( + base::Bind(&DevToolsFileHelper::FilePathsChanged, + weak_factory_.GetWeakPtr()))); } DevToolsFileHelper::~DevToolsFileHelper() { + BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, + file_watcher_.release()); } void DevToolsFileHelper::Save(const std::string& url, @@ -392,6 +398,9 @@ file_system_id, file_system_path); file_systems.push_back(filesystem); + BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, + Bind(&DevToolsFileWatcher::AddWatch, + base::Unretained(file_watcher_.get()), path)); } return file_systems; } @@ -426,12 +435,26 @@ file_system_id, file_system_path); delegate_->FileSystemAdded(filesystem); + BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, + Bind(&DevToolsFileWatcher::AddWatch, + base::Unretained(file_watcher_.get()), + path)); } else { remaining.erase(file_system_path); } file_system_paths_.insert(file_system_path); } - for (auto file_system_path : remaining) + for (auto file_system_path : remaining) { delegate_->FileSystemRemoved(file_system_path); + base::FilePath path = base::FilePath::FromUTF8Unsafe(file_system_path); + BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, + Bind(&DevToolsFileWatcher::RemoveWatch, + base::Unretained(file_watcher_.get()), path)); + } +} + +void DevToolsFileHelper::FilePathsChanged( + const std::vector<std::string>& paths) { + delegate_->FilePathsChanged(paths); }
diff --git a/chrome/browser/devtools/devtools_file_helper.h b/chrome/browser/devtools/devtools_file_helper.h index d7f63c30..550a19d 100644 --- a/chrome/browser/devtools/devtools_file_helper.h +++ b/chrome/browser/devtools/devtools_file_helper.h
@@ -17,6 +17,7 @@ #include "base/prefs/pref_change_registrar.h" #include "base/strings/string16.h" +class DevToolsFileWatcher; class Profile; namespace base { @@ -45,6 +46,7 @@ virtual ~Delegate() {} virtual void FileSystemAdded(const FileSystem& file_system) = 0; virtual void FileSystemRemoved(const std::string& file_system_path) = 0; + virtual void FilePathsChanged(const std::vector<std::string>& paths) = 0; }; DevToolsFileHelper(content::WebContents* web_contents, Profile* profile, @@ -129,6 +131,7 @@ const base::FilePath& path, bool allowed); void FileSystemPathsSettingChanged(); + void FilePathsChanged(const std::vector<std::string>& paths); content::WebContents* web_contents_; Profile* profile_; @@ -137,6 +140,7 @@ PathsMap saved_files_; PrefChangeRegistrar pref_change_registrar_; std::set<std::string> file_system_paths_; + scoped_ptr<DevToolsFileWatcher> file_watcher_; base::WeakPtrFactory<DevToolsFileHelper> weak_factory_; DISALLOW_COPY_AND_ASSIGN(DevToolsFileHelper); };
diff --git a/chrome/browser/devtools/devtools_file_watcher.cc b/chrome/browser/devtools/devtools_file_watcher.cc new file mode 100644 index 0000000..bfc4906 --- /dev/null +++ b/chrome/browser/devtools/devtools_file_watcher.cc
@@ -0,0 +1,180 @@ +// Copyright (c) 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/devtools/devtools_file_watcher.h" + +#include <map> +#include <set> + +#include "base/bind.h" +#include "base/files/file_enumerator.h" +#include "base/files/file_path.h" +#include "base/files/file_path_watcher.h" +#include "base/memory/ref_counted.h" +#include "content/public/browser/browser_thread.h" + +using content::BrowserThread; + +static int kFirstThrottleTimeout = 10; +static int kDefaultThrottleTimeout = 200; + +// DevToolsFileWatcher::SharedFileWatcher -------------------------------------- + +class DevToolsFileWatcher::SharedFileWatcher : + public base::RefCounted<SharedFileWatcher> { + public: + SharedFileWatcher(); + + void AddListener(DevToolsFileWatcher* watcher); + void RemoveListener(DevToolsFileWatcher* watcher); + void AddWatch(const base::FilePath& path); + void RemoveWatch(const base::FilePath& path); + + private: + friend class base::RefCounted< + DevToolsFileWatcher::SharedFileWatcher>; + ~SharedFileWatcher(); + + void DirectoryChanged(const base::FilePath& path, bool error); + void DispatchNotifications(); + + std::vector<DevToolsFileWatcher*> listeners_; + std::map<base::FilePath, scoped_ptr<base::FilePathWatcher>> watchers_; + using FilePathTimesMap = std::map<base::FilePath, base::Time>; + FilePathTimesMap file_path_times_; + std::set<base::FilePath> pending_paths_; + base::Time last_event_time_; + base::TimeDelta last_dispatch_cost_; +}; + +DevToolsFileWatcher::SharedFileWatcher::SharedFileWatcher() + : last_dispatch_cost_( + base::TimeDelta::FromMilliseconds(kDefaultThrottleTimeout)) { + DevToolsFileWatcher::s_shared_watcher_ = this; +} + +DevToolsFileWatcher::SharedFileWatcher::~SharedFileWatcher() { + DevToolsFileWatcher::s_shared_watcher_ = nullptr; +} + +void DevToolsFileWatcher::SharedFileWatcher::AddListener( + DevToolsFileWatcher* watcher) { + listeners_.push_back(watcher); +} + +void DevToolsFileWatcher::SharedFileWatcher::RemoveListener( + DevToolsFileWatcher* watcher) { + auto it = std::find(listeners_.begin(), listeners_.end(), watcher); + listeners_.erase(it); +} + +void DevToolsFileWatcher::SharedFileWatcher::AddWatch( + const base::FilePath& path) { + if (watchers_.find(path) != watchers_.end()) + return; + if (!base::FilePathWatcher::RecursiveWatchAvailable()) + return; + watchers_[path].reset(new base::FilePathWatcher()); + bool success = watchers_[path]->Watch( + path, true, + base::Bind(&SharedFileWatcher::DirectoryChanged, base::Unretained(this))); + if (!success) + return; + + base::FileEnumerator enumerator(path, true, base::FileEnumerator::FILES); + base::FilePath file_path = enumerator.Next(); + while (!file_path.empty()) { + base::FileEnumerator::FileInfo file_info = enumerator.GetInfo(); + file_path_times_[file_path] = file_info.GetLastModifiedTime(); + file_path = enumerator.Next(); + } +} + +void DevToolsFileWatcher::SharedFileWatcher::RemoveWatch( + const base::FilePath& path) { + watchers_.erase(path); +} + +void DevToolsFileWatcher::SharedFileWatcher::DirectoryChanged( + const base::FilePath& path, + bool error) { + DCHECK_CURRENTLY_ON(BrowserThread::FILE); + pending_paths_.insert(path); + if (pending_paths_.size() > 1) + return; // PostDelayedTask is already pending. + + base::Time now = base::Time::Now(); + // Quickly dispatch first chunk. + base::TimeDelta shedule_for = + now - last_event_time_ > last_dispatch_cost_ ? + base::TimeDelta::FromMilliseconds(kFirstThrottleTimeout) : + last_dispatch_cost_ * 2; + + BrowserThread::PostDelayedTask( + BrowserThread::FILE, FROM_HERE, + base::Bind(&DevToolsFileWatcher::SharedFileWatcher::DispatchNotifications, + this), shedule_for); + last_event_time_ = now; +} + +void DevToolsFileWatcher::SharedFileWatcher::DispatchNotifications() { + base::Time start = base::Time::Now(); + std::vector<std::string> changed_paths; + for (auto path : pending_paths_) { + base::FileEnumerator enumerator(path, true, base::FileEnumerator::FILES); + base::FilePath file_path = enumerator.Next(); + while (!file_path.empty()) { + base::FileEnumerator::FileInfo file_info = enumerator.GetInfo(); + base::Time new_time = file_info.GetLastModifiedTime(); + if (file_path_times_[file_path] != new_time) { + file_path_times_[file_path] = new_time; + changed_paths.push_back(file_path.AsUTF8Unsafe()); + } + file_path = enumerator.Next(); + } + } + pending_paths_.clear(); + + for (auto watcher : listeners_) { + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, + base::Bind(watcher->callback_, changed_paths)); + } + last_dispatch_cost_ = base::Time::Now() - start; +} + +// static +DevToolsFileWatcher::SharedFileWatcher* +DevToolsFileWatcher::s_shared_watcher_ = nullptr; + +// DevToolsFileWatcher --------------------------------------------------------- + +DevToolsFileWatcher::DevToolsFileWatcher(const WatchCallback& callback) + : callback_(callback) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, + base::Bind(&DevToolsFileWatcher::InitSharedWatcher, + base::Unretained(this))); +} + +DevToolsFileWatcher::~DevToolsFileWatcher() { + DCHECK_CURRENTLY_ON(BrowserThread::FILE); + shared_watcher_->RemoveListener(this); +} + +void DevToolsFileWatcher::InitSharedWatcher() { + if (!DevToolsFileWatcher::s_shared_watcher_) + new SharedFileWatcher(); + shared_watcher_ = DevToolsFileWatcher::s_shared_watcher_; + shared_watcher_->AddListener(this); +} + +void DevToolsFileWatcher::AddWatch(const base::FilePath& path) { + DCHECK_CURRENTLY_ON(BrowserThread::FILE); + shared_watcher_->AddWatch(path); +} + +void DevToolsFileWatcher::RemoveWatch(const base::FilePath& path) { + DCHECK_CURRENTLY_ON(BrowserThread::FILE); + shared_watcher_->RemoveWatch(path); +}
diff --git a/chrome/browser/devtools/devtools_file_watcher.h b/chrome/browser/devtools/devtools_file_watcher.h new file mode 100644 index 0000000..b753af4 --- /dev/null +++ b/chrome/browser/devtools/devtools_file_watcher.h
@@ -0,0 +1,39 @@ +// Copyright (c) 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_DEVTOOLS_DEVTOOLS_FILE_WATCHER_H_ +#define CHROME_BROWSER_DEVTOOLS_DEVTOOLS_FILE_WATCHER_H_ + +#include <vector> + +#include "base/callback.h" +#include "base/macros.h" + +namespace base { +class FilePath; +class FilePathWatcher; +} + +class DevToolsFileWatcher { + public: + using WatchCallback = base::Callback<void(const std::vector<std::string>&)>; + explicit DevToolsFileWatcher(const WatchCallback& callback); + ~DevToolsFileWatcher(); + + void AddWatch(const base::FilePath& path); + void RemoveWatch(const base::FilePath& path); + + private: + class SharedFileWatcher; + static SharedFileWatcher* s_shared_watcher_; + + void InitSharedWatcher(); + void FileChanged(const base::FilePath&, int); + + scoped_refptr<SharedFileWatcher> shared_watcher_; + WatchCallback callback_; + DISALLOW_COPY_AND_ASSIGN(DevToolsFileWatcher); +}; + +#endif // CHROME_BROWSER_DEVTOOLS_DEVTOOLS_FILE_WATCHER_H_
diff --git a/chrome/browser/devtools/devtools_ui_bindings.cc b/chrome/browser/devtools/devtools_ui_bindings.cc index 1cb42bd..66ff96fb 100644 --- a/chrome/browser/devtools/devtools_ui_bindings.cc +++ b/chrome/browser/devtools/devtools_ui_bindings.cc
@@ -14,6 +14,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/values.h" #include "chrome/browser/chrome_notification_types.h" +#include "chrome/browser/devtools/devtools_file_watcher.h" #include "chrome/browser/devtools/devtools_protocol.h" #include "chrome/browser/devtools/devtools_target_impl.h" #include "chrome/browser/devtools/global_confirm_info_bar.h" @@ -995,6 +996,15 @@ &file_system_path_value, NULL, NULL); } +void DevToolsUIBindings::FilePathsChanged( + const std::vector<std::string>& file_paths) { + base::ListValue list; + for (auto path : file_paths) + list.AppendString(path); + CallClientFunction("DevToolsAPI.fileSystemFilesChanged", + &list, NULL, NULL); +} + void DevToolsUIBindings::IndexingTotalWorkCalculated( int request_id, const std::string& file_system_path,
diff --git a/chrome/browser/devtools/devtools_ui_bindings.h b/chrome/browser/devtools/devtools_ui_bindings.h index e9486924..e44545b3 100644 --- a/chrome/browser/devtools/devtools_ui_bindings.h +++ b/chrome/browser/devtools/devtools_ui_bindings.h
@@ -173,6 +173,7 @@ void FileSystemAdded( const DevToolsFileHelper::FileSystem& file_system) override; void FileSystemRemoved(const std::string& file_system_path) override; + void FilePathsChanged(const std::vector<std::string>& file_paths) override; // DevToolsFileHelper callbacks. void FileSavedAs(const std::string& url);
diff --git a/chrome/browser/extensions/api/gcd_private/gcd_private_api.cc b/chrome/browser/extensions/api/gcd_private/gcd_private_api.cc index 50d24d6..0d6a8508 100644 --- a/chrome/browser/extensions/api/gcd_private/gcd_private_api.cc +++ b/chrome/browser/extensions/api/gcd_private/gcd_private_api.cc
@@ -7,6 +7,7 @@ #include "base/command_line.h" #include "base/lazy_instance.h" #include "base/memory/linked_ptr.h" +#include "base/thread_task_runner_handle.h" #include "chrome/browser/local_discovery/privet_http.h" #include "chrome/browser/local_discovery/privet_http_asynchronous_factory.h" #include "chrome/browser/local_discovery/privetv3_session.h"
diff --git a/chrome/browser/metrics/variations/chrome_variations_service_client.cc b/chrome/browser/metrics/variations/chrome_variations_service_client.cc index ed7ceff..8e6b4be 100644 --- a/chrome/browser/metrics/variations/chrome_variations_service_client.cc +++ b/chrome/browser/metrics/variations/chrome_variations_service_client.cc
@@ -10,6 +10,10 @@ #include "components/version_info/version_info.h" #include "content/public/browser/browser_thread.h" +#if defined(OS_ANDROID) +#include "chrome/browser/android/preferences/pref_service_bridge.h" +#endif // OS_ANDROID + #if !defined(OS_ANDROID) && !defined(OS_IOS) && !defined(OS_CHROMEOS) #include "chrome/browser/upgrade_detector_impl.h" #endif @@ -79,6 +83,15 @@ #endif } +variations::VariationsFirstRunSeedCallback +ChromeVariationsServiceClient::GetVariationsFirstRunSeedCallback() { +#if defined(OS_ANDROID) + return base::Bind(&PrefServiceBridge::GetVariationsFirstRunSeed); +#else // OS_ANDROID + return variations::VariationsFirstRunSeedCallback(); +#endif // OS_ANDROID +} + void ChromeVariationsServiceClient::OnInitialStartup() { #if defined(OS_WIN) StartGoogleUpdateRegistrySync();
diff --git a/chrome/browser/metrics/variations/chrome_variations_service_client.h b/chrome/browser/metrics/variations/chrome_variations_service_client.h index 8abe72ef..d38b170 100644 --- a/chrome/browser/metrics/variations/chrome_variations_service_client.h +++ b/chrome/browser/metrics/variations/chrome_variations_service_client.h
@@ -5,8 +5,12 @@ #ifndef CHROME_BROWSER_METRICS_VARIATIONS_CHROME_VARIATIONS_SERVICE_CLIENT_H_ #define CHROME_BROWSER_METRICS_VARIATIONS_CHROME_VARIATIONS_SERVICE_CLIENT_H_ +#include <string> + #include "base/basictypes.h" +#include "base/bind.h" #include "components/variations/service/variations_service_client.h" +#include "components/variations/variations_seed_store.h" #if defined(OS_WIN) #include "chrome/browser/metrics/variations/variations_registry_syncer_win.h" @@ -30,6 +34,8 @@ version_info::Channel GetChannel() override; bool OverridesRestrictParameter(std::string* parameter) override; void OnInitialStartup() override; + variations::VariationsFirstRunSeedCallback GetVariationsFirstRunSeedCallback() + override; private: #if defined(OS_WIN)
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura.cc b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura.cc index 2adfb24e..5c6dad7 100644 --- a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura.cc +++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura.cc
@@ -325,9 +325,11 @@ return CreateNonStandardAppFrame(); if (app_window()->window_type_is_panel()) { - views::NonClientFrameView* frame_view = + ash::PanelFrameView* frame_view = new ash::PanelFrameView(widget, ash::PanelFrameView::FRAME_ASH); frame_view->set_context_menu_controller(this); + if (HasFrameColor()) + frame_view->SetFrameColors(ActiveFrameColor(), InactiveFrameColor()); return frame_view; }
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc index c2d651c..c2cc048a 100644 --- a/chrome/browser/ui/views/tabs/tab.cc +++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -1129,8 +1129,12 @@ } void Tab::PaintTabBackground(gfx::Canvas* canvas) { + const int kActiveTabFillId = IDR_THEME_TOOLBAR; + const bool has_custom_image = + GetThemeProvider()->HasCustomImage(kActiveTabFillId); if (IsActive()) { - PaintActiveTabBackground(canvas); + PaintTabBackgroundUsingFillId(canvas, true, kActiveTabFillId, + has_custom_image, 0); } else { if (pinned_title_change_animation_ && pinned_title_change_animation_->is_animating()) @@ -1142,7 +1146,8 @@ if (throb_value > 0) { canvas->SaveLayerAlpha(gfx::ToRoundedInt(throb_value * 0xff), GetLocalBounds()); - PaintActiveTabBackground(canvas); + PaintTabBackgroundUsingFillId(canvas, true, kActiveTabFillId, + has_custom_image, 0); canvas->Restore(); } } @@ -1174,98 +1179,74 @@ } void Tab::PaintInactiveTabBackground(gfx::Canvas* canvas) { - int tab_id, frame_id; - GetTabIdAndFrameId(GetWidget(), &tab_id, &frame_id); - // HasCustomImage() is only true if the theme provides the image. However, - // even if the theme does not provide a tab background, the theme machinery - // will make one if given a frame image. - ui::ThemeProvider* theme_provider = GetThemeProvider(); - const bool has_custom_image = theme_provider->HasCustomImage(tab_id) || - (frame_id != 0 && theme_provider->HasCustomImage(frame_id)); - + bool has_custom_image; + int fill_id = controller_->GetBackgroundResourceId(&has_custom_image); // Explicitly map the id so we cache correctly. const chrome::HostDesktopType host_desktop_type = GetHostDesktopType(this); - tab_id = chrome::MapThemeImage(host_desktop_type, tab_id); + fill_id = chrome::MapThemeImage(host_desktop_type, fill_id); + + // If the theme is providing a custom background image, then its top edge + // should be at the top of the tab. Otherwise, we assume that the background + // image is a composited foreground + frame image. + const int y_offset = GetThemeProvider()->HasCustomImage(fill_id) ? + 0 : background_offset_.y(); // We only cache the image when it's the default image and we're not hovered, // to avoid caching a background image that isn't the same for all tabs. if (!has_custom_image && !hover_controller_.ShouldDraw()) { ui::ScaleFactor scale_factor = ui::GetSupportedScaleFactor(canvas->image_scale()); - gfx::ImageSkia cached_image(GetCachedImage(tab_id, size(), scale_factor)); + gfx::ImageSkia cached_image(GetCachedImage(fill_id, size(), scale_factor)); if (cached_image.width() == 0) { gfx::Canvas tmp_canvas(size(), canvas->image_scale(), false); - PaintInactiveTabBackgroundUsingResourceId(&tmp_canvas, tab_id); + PaintTabBackgroundUsingFillId(&tmp_canvas, false, fill_id, false, + y_offset); cached_image = gfx::ImageSkia(tmp_canvas.ExtractImageRep()); - SetCachedImage(tab_id, scale_factor, cached_image); + SetCachedImage(fill_id, scale_factor, cached_image); } canvas->DrawImageInt(cached_image, 0, 0); } else { - PaintInactiveTabBackgroundUsingResourceId(canvas, tab_id); + PaintTabBackgroundUsingFillId(canvas, false, fill_id, has_custom_image, + y_offset); } } -void Tab::PaintInactiveTabBackgroundUsingResourceId(gfx::Canvas* canvas, - int tab_id) { - gfx::ImageSkia* tab_background = - GetThemeProvider()->GetImageSkiaNamed(tab_id); +void Tab::PaintTabBackgroundUsingFillId(gfx::Canvas* canvas, + bool is_active, + int fill_id, + bool has_custom_image, + int y_offset) { + gfx::ImageSkia* fill_image = GetThemeProvider()->GetImageSkiaNamed(fill_id); // The tab image needs to be lined up with the background image // so that it feels partially transparent. These offsets represent the tab // position within the frame background image. const int x_offset = GetMirroredX() + background_offset_.x(); - // If the theme is providing a custom background image, then its top edge - // should be at the top of the tab. Otherwise, we assume that the background - // image is a composited foreground + frame image. - const int y_offset = GetThemeProvider()->HasCustomImage(tab_id) ? - 0 : background_offset_.y(); + const SkScalar radius = SkFloatToScalar(width() / 3.f); + const bool draw_hover = + !is_active && hover_controller_.ShouldDraw() && radius > 0; + SkPoint hover_location(PointToSkPoint(hover_controller_.location())); + const SkAlpha hover_alpha = hover_controller_.GetAlpha(); - const gfx::Insets tab_insets(GetLayoutInsets(TAB)); - // Don't draw over the toolbar, but do include the 1 px divider stroke at the - // bottom. - const int toolbar_overlap = tab_insets.bottom() - 1; + if (draw_hover) { + // Draw everything to a temporary canvas so we can extract an image for use + // in masking the hover glow. + gfx::Canvas background_canvas(size(), canvas->image_scale(), false); + PaintTabFill(&background_canvas, fill_image, x_offset, y_offset, is_active); + gfx::ImageSkia background_image(background_canvas.ExtractImageRep()); + canvas->DrawImageInt(background_image, 0, 0); - // Draw everything to a temporary canvas so we can extract an image for use in - // masking the hover glow. - gfx::Canvas background_canvas(size(), canvas->image_scale(), false); - - // Draw left edge. - gfx::ImageSkia tab_l = gfx::ImageSkiaOperations::CreateTiledImage( - *tab_background, x_offset, y_offset, mask_images_.l_width, height()); - gfx::ImageSkia theme_l = - gfx::ImageSkiaOperations::CreateMaskedImage(tab_l, *mask_images_.image_l); - background_canvas.DrawImageInt( - theme_l, 0, 0, theme_l.width(), theme_l.height() - toolbar_overlap, 0, 0, - theme_l.width(), theme_l.height() - toolbar_overlap, false); - - // Draw right edge. - gfx::ImageSkia tab_r = gfx::ImageSkiaOperations::CreateTiledImage( - *tab_background, x_offset + width() - mask_images_.r_width, y_offset, - mask_images_.r_width, height()); - gfx::ImageSkia theme_r = - gfx::ImageSkiaOperations::CreateMaskedImage(tab_r, *mask_images_.image_r); - background_canvas.DrawImageInt(theme_r, 0, 0, theme_r.width(), - theme_r.height() - toolbar_overlap, - width() - theme_r.width(), 0, theme_r.width(), - theme_r.height() - toolbar_overlap, false); - - // Draw center. Instead of masking out the top portion we simply skip over - // it by incrementing by the top padding, since it's a simple rectangle. - background_canvas.TileImageInt( - *tab_background, x_offset + mask_images_.l_width, - y_offset + tab_insets.top(), mask_images_.l_width, tab_insets.top(), - width() - mask_images_.l_width - mask_images_.r_width, - height() - tab_insets.top() - toolbar_overlap); - - gfx::ImageSkia background_image(background_canvas.ExtractImageRep()); - canvas->DrawImageInt(background_image, 0, 0); - - if (!GetThemeProvider()->HasCustomImage(tab_id) && - hover_controller_.ShouldDraw()) - hover_controller_.Draw(canvas, background_image); + gfx::Canvas hover_canvas(size(), canvas->image_scale(), false); + DrawHighlight(&hover_canvas, hover_location, radius, hover_alpha); + gfx::ImageSkia result = gfx::ImageSkiaOperations::CreateMaskedImage( + gfx::ImageSkia(hover_canvas.ExtractImageRep()), background_image); + canvas->DrawImageInt(result, 0, 0); + } else { + PaintTabFill(canvas, fill_image, x_offset, y_offset, is_active); + } // Now draw the stroke, highlights, and shadows around the tab edge. - TabImages* stroke_images = &inactive_images_; + TabImages* stroke_images = is_active ? &active_images_ : &inactive_images_; canvas->DrawImageInt(*stroke_images->image_l, 0, 0); canvas->TileImageInt( *stroke_images->image_c, stroke_images->l_width, 0, @@ -1274,47 +1255,43 @@ width() - stroke_images->r_width, 0); } -void Tab::PaintActiveTabBackground(gfx::Canvas* canvas) { - gfx::ImageSkia* tab_background = - GetThemeProvider()->GetImageSkiaNamed(IDR_THEME_TOOLBAR); - int x_offset = GetMirroredX() + background_offset_.x(); - +void Tab::PaintTabFill(gfx::Canvas* canvas, + gfx::ImageSkia* fill_image, + int x_offset, + int y_offset, + bool is_active) { const gfx::Insets tab_insets(GetLayoutInsets(TAB)); + // If this isn't the foreground tab, don't draw over the toolbar, but do + // include the 1 px divider stroke at the bottom. + const int toolbar_overlap = is_active ? 0 : (tab_insets.bottom() - 1); // Draw left edge. gfx::ImageSkia tab_l = gfx::ImageSkiaOperations::CreateTiledImage( - *tab_background, x_offset, 0, mask_images_.l_width, height()); + *fill_image, x_offset, y_offset, mask_images_.l_width, height()); gfx::ImageSkia theme_l = gfx::ImageSkiaOperations::CreateMaskedImage(tab_l, *mask_images_.image_l); canvas->DrawImageInt( - theme_l, 0, 0, theme_l.width(), theme_l.height(), 0, 0, theme_l.width(), - theme_l.height(), false); + theme_l, 0, 0, theme_l.width(), theme_l.height() - toolbar_overlap, 0, 0, + theme_l.width(), theme_l.height() - toolbar_overlap, false); // Draw right edge. gfx::ImageSkia tab_r = gfx::ImageSkiaOperations::CreateTiledImage( - *tab_background, x_offset + width() - mask_images_.r_width, 0, + *fill_image, x_offset + width() - mask_images_.r_width, y_offset, mask_images_.r_width, height()); gfx::ImageSkia theme_r = gfx::ImageSkiaOperations::CreateMaskedImage(tab_r, *mask_images_.image_r); - canvas->DrawImageInt(theme_r, 0, 0, theme_r.width(), theme_r.height(), + canvas->DrawImageInt(theme_r, 0, 0, theme_r.width(), + theme_r.height() - toolbar_overlap, width() - theme_r.width(), 0, theme_r.width(), - theme_r.height(), false); + theme_r.height() - toolbar_overlap, false); // Draw center. Instead of masking out the top portion we simply skip over it // by incrementing by the top padding, since it's a simple rectangle. - canvas->TileImageInt(*tab_background, x_offset + mask_images_.l_width, - tab_insets.top(), mask_images_.l_width, tab_insets.top(), + canvas->TileImageInt(*fill_image, x_offset + mask_images_.l_width, + y_offset + tab_insets.top(), mask_images_.l_width, + tab_insets.top(), width() - mask_images_.l_width - mask_images_.r_width, - height() - tab_insets.top()); - - // Now draw the stroke, highlights, and shadows around the tab edge. - TabImages* stroke_images = &active_images_; - canvas->DrawImageInt(*stroke_images->image_l, 0, 0); - canvas->TileImageInt( - *stroke_images->image_c, stroke_images->l_width, 0, - width() - stroke_images->l_width - stroke_images->r_width, height()); - canvas->DrawImageInt(*stroke_images->image_r, - width() - stroke_images->r_width, 0); + height() - tab_insets.top() - toolbar_overlap); } void Tab::PaintIcon(gfx::Canvas* canvas) { @@ -1507,22 +1484,6 @@ main_bar_left, 0, main_bar_right - main_bar_left, kImmersiveBarHeight); } -void Tab::GetTabIdAndFrameId(views::Widget* widget, - int* tab_id, - int* frame_id) const { - if (widget && - widget->GetTopLevelWidget()->ShouldWindowContentsBeTransparent()) { - *tab_id = IDR_THEME_TAB_BACKGROUND_V; - *frame_id = 0; - } else if (data().incognito) { - *tab_id = IDR_THEME_TAB_BACKGROUND_INCOGNITO; - *frame_id = IDR_THEME_FRAME_INCOGNITO; - } else { - *tab_id = IDR_THEME_TAB_BACKGROUND; - *frame_id = IDR_THEME_FRAME; - } -} - //////////////////////////////////////////////////////////////////////////////// // Tab, private static:
diff --git a/chrome/browser/ui/views/tabs/tab.h b/chrome/browser/ui/views/tabs/tab.h index be601119..38ea62c 100644 --- a/chrome/browser/ui/views/tabs/tab.h +++ b/chrome/browser/ui/views/tabs/tab.h
@@ -239,9 +239,16 @@ void PaintTabBackground(gfx::Canvas* canvas); void PaintInactiveTabBackgroundWithTitleChange(gfx::Canvas* canvas); void PaintInactiveTabBackground(gfx::Canvas* canvas); - void PaintInactiveTabBackgroundUsingResourceId(gfx::Canvas* canvas, - int tab_id); - void PaintActiveTabBackground(gfx::Canvas* canvas); + void PaintTabBackgroundUsingFillId(gfx::Canvas* canvas, + bool is_active, + int fill_id, + bool has_custom_image, + int y_offset); + void PaintTabFill(gfx::Canvas* canvas, + gfx::ImageSkia* fill_image, + int x_offset, + int y_offset, + bool is_active); // Paints the favicon, mirrored for RTL if needed. void PaintIcon(gfx::Canvas* canvas); @@ -291,11 +298,6 @@ // Returns the rectangle for the light bar in immersive mode. gfx::Rect GetImmersiveBarRect() const; - // Gets the tab id and frame id. - void GetTabIdAndFrameId(views::Widget* widget, - int* tab_id, - int* frame_id) const; - // Performs a one-time initialization of static resources such as tab images. static void InitTabResources();
diff --git a/chrome/browser/ui/views/tabs/tab_controller.h b/chrome/browser/ui/views/tabs/tab_controller.h index 23de038..f8485e07 100644 --- a/chrome/browser/ui/views/tabs/tab_controller.h +++ b/chrome/browser/ui/views/tabs/tab_controller.h
@@ -96,6 +96,11 @@ // Returns true if tabs painted in the rectangular light-bar style. virtual bool IsImmersiveStyle() const = 0; + // Returns the resource ID for the image to use as the tab background. + // |custom_image| is an outparam set to true if either the tab or the frame + // background images have been customized; see implementation comments. + virtual int GetBackgroundResourceId(bool* custom_image) const = 0; + // Adds private information to the tab's accessibility state. virtual void UpdateTabAccessibilityState(const Tab* tab, ui::AXViewState* state) = 0;
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc index da4e53b1..5fe10f19 100644 --- a/chrome/browser/ui/views/tabs/tab_strip.cc +++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -398,11 +398,8 @@ double hover_value, float scale, gfx::Canvas* canvas) const { - int bg_id = IDR_THEME_TAB_BACKGROUND_V; - if (!GetWidget()->ShouldWindowContentsBeTransparent()) { - bg_id = tab_strip_->controller()->IsIncognito() ? - IDR_THEME_TAB_BACKGROUND_INCOGNITO : IDR_THEME_TAB_BACKGROUND; - } + bool custom_image; + const int bg_id = tab_strip_->GetBackgroundResourceId(&custom_image); // Draw the fill background image. const gfx::Size size(GetNewTabButtonSize()); @@ -1208,6 +1205,28 @@ return immersive_style_; } +int TabStrip::GetBackgroundResourceId(bool* custom_image) const { + ui::ThemeProvider* theme_provider = GetThemeProvider(); + + if (GetWidget()->ShouldWindowContentsBeTransparent()) { + const int kBackgroundIdGlass = IDR_THEME_TAB_BACKGROUND_V; + *custom_image = theme_provider->HasCustomImage(kBackgroundIdGlass); + return kBackgroundIdGlass; + } + + // If a custom theme does not provide a replacement tab background, but does + // provide a replacement frame image, HasCustomImage() on the tab background + // ID will return false, but the theme provider will make a custom image from + // the frame image. + const bool incognito = controller()->IsIncognito(); + const int id = incognito ? + IDR_THEME_TAB_BACKGROUND_INCOGNITO : IDR_THEME_TAB_BACKGROUND; + *custom_image = theme_provider->HasCustomImage(id) || + theme_provider->HasCustomImage( + incognito ? IDR_THEME_FRAME_INCOGNITO : IDR_THEME_FRAME); + return id; +} + void TabStrip::UpdateTabAccessibilityState(const Tab* tab, ui::AXViewState* state) { state->count = tab_count();
diff --git a/chrome/browser/ui/views/tabs/tab_strip.h b/chrome/browser/ui/views/tabs/tab_strip.h index 4f62593..9bd8882 100644 --- a/chrome/browser/ui/views/tabs/tab_strip.h +++ b/chrome/browser/ui/views/tabs/tab_strip.h
@@ -231,6 +231,7 @@ const ui::MouseEvent& event) override; bool ShouldPaintTab(const Tab* tab, gfx::Rect* clip) override; bool IsImmersiveStyle() const override; + int GetBackgroundResourceId(bool* custom_image) const override; void UpdateTabAccessibilityState(const Tab* tab, ui::AXViewState* state) override;
diff --git a/chrome/browser/ui/views/tabs/tab_unittest.cc b/chrome/browser/ui/views/tabs/tab_unittest.cc index 621fbca..27dacf94 100644 --- a/chrome/browser/ui/views/tabs/tab_unittest.cc +++ b/chrome/browser/ui/views/tabs/tab_unittest.cc
@@ -9,6 +9,7 @@ #include "chrome/browser/ui/tabs/tab_utils.h" #include "chrome/browser/ui/views/tabs/media_indicator_button.h" #include "chrome/browser/ui/views/tabs/tab_controller.h" +#include "grit/theme_resources.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/models/list_selection_model.h" #include "ui/views/controls/button/image_button.h" @@ -60,6 +61,10 @@ const ui::MouseEvent& event) override {} bool ShouldPaintTab(const Tab* tab, gfx::Rect* clip) override { return true; } bool IsImmersiveStyle() const override { return immersive_style_; } + int GetBackgroundResourceId(bool* custom_image) const override { + *custom_image = false; + return IDR_THEME_TAB_BACKGROUND; + } void UpdateTabAccessibilityState(const Tab* tab, ui::AXViewState* state) override{};
diff --git a/chrome/chrome_debugger.gypi b/chrome/chrome_debugger.gypi index 3a717779..50f17ab 100644 --- a/chrome/chrome_debugger.gypi +++ b/chrome/chrome_debugger.gypi
@@ -101,6 +101,8 @@ 'browser/devtools/devtools_file_helper.h', 'browser/devtools/devtools_file_system_indexer.cc', 'browser/devtools/devtools_file_system_indexer.h', + 'browser/devtools/devtools_file_watcher.cc', + 'browser/devtools/devtools_file_watcher.h', 'browser/devtools/devtools_target_impl.cc', 'browser/devtools/devtools_target_impl.h', 'browser/devtools/devtools_targets_ui.cc',
diff --git a/chrome/test/chromedriver/session_commands.cc b/chrome/test/chromedriver/session_commands.cc index 7ee2509..816c2195 100644 --- a/chrome/test/chromedriver/session_commands.cc +++ b/chrome/test/chromedriver/session_commands.cc
@@ -316,8 +316,8 @@ const base::DictionaryValue& params, scoped_ptr<base::Value>* value) { std::string name; - if (!params.GetString("name", &name) || name.empty()) - return Status(kUnknownError, "'name' must be a nonempty string"); + if (!params.GetString("name", &name)) + return Status(kUnknownError, "'name' must be a string"); std::list<std::string> web_view_ids; Status status = session->chrome->GetWebViewIds(&web_view_ids);
diff --git a/chromeos/BUILD.gn b/chromeos/BUILD.gn index 268a5b2..d66f80e5 100644 --- a/chromeos/BUILD.gn +++ b/chromeos/BUILD.gn
@@ -33,6 +33,7 @@ "//crypto", "//crypto:platform", "//google_apis", + "//ipc", "//third_party/icu", "//third_party/libxml", "//third_party/protobuf:protobuf_lite",
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM index 6558c09..9ab9baf 100644 --- a/chromeos/CHROMEOS_LKGM +++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@ -7609.0.0 \ No newline at end of file +7611.0.0 \ No newline at end of file
diff --git a/chromeos/arc/OWNERS b/chromeos/arc/OWNERS new file mode 100644 index 0000000..e67f9dff --- /dev/null +++ b/chromeos/arc/OWNERS
@@ -0,0 +1,3 @@ +elijahtaylor@chromium.org +lhchavez@chromium.org +dgreid@chromium.org
diff --git a/chromeos/arc/bridge/common/OWNERS b/chromeos/arc/bridge/common/OWNERS new file mode 100644 index 0000000..78ef284 --- /dev/null +++ b/chromeos/arc/bridge/common/OWNERS
@@ -0,0 +1,12 @@ + # Changes to IPC messages require a security review to avoid introducing + # new sandbox escapes. + per-file *_messages*.h=set noparent + per-file *_messages*.h=dcheng@chromium.org + per-file *_messages*.h=inferno@chromium.org + per-file *_messages*.h=jln@chromium.org + per-file *_messages*.h=jschuh@chromium.org + per-file *_messages*.h=kenrb@chromium.org + per-file *_messages*.h=mkwst@chromium.org + per-file *_messages*.h=nasko@chromium.org + per-file *_messages*.h=tsepez@chromium.org + per-file *_messages*.h=wfh@chromium.org
diff --git a/chromeos/arc/bridge/common/arc_host_messages.h b/chromeos/arc/bridge/common/arc_host_messages.h new file mode 100644 index 0000000..a04efd2 --- /dev/null +++ b/chromeos/arc/bridge/common/arc_host_messages.h
@@ -0,0 +1,12 @@ +// 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. + +// Messages sent from the host to the ARC instance +// Multiply-included message file, hence no include guard. + +#include "ipc/ipc_message_macros.h" + +#define IPC_MESSAGE_START ArcInstanceHostMsgStart + +IPC_MESSAGE_CONTROL0(ArcInstanceHostMsg_InstanceReady)
diff --git a/chromeos/arc/bridge/common/arc_instance_messages.h b/chromeos/arc/bridge/common/arc_instance_messages.h new file mode 100644 index 0000000..607718d1 --- /dev/null +++ b/chromeos/arc/bridge/common/arc_instance_messages.h
@@ -0,0 +1,24 @@ +// 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. + +// Messages sent from the ARC instance to the host +// Multiply-included message file, hence no include guard. + +#include <stdint.h> + +#include "base/file_descriptor_posix.h" +#include "ipc/ipc_message_macros.h" + +#define IPC_MESSAGE_START ArcInstanceMsgStart + +// Registers a virtual input device on the container side. +// |name| is the device name, like "Chrome OS Keyboard". +// |device_type| is the device type, like "keyboard". +// The virtual device will be reading 'struct input_event's from |fd|. The +// ownership of |fd| will be transferred to the receiver, so the sender must +// not close it. +IPC_MESSAGE_CONTROL3(ArcInstanceMsg_RegisterInputDevice, + std::string, /* name */ + std::string, /* device_type */ + base::FileDescriptor /* fd */)
diff --git a/chromeos/arc/bridge/common/arc_message_generator.cc b/chromeos/arc/bridge/common/arc_message_generator.cc new file mode 100644 index 0000000..910d433f --- /dev/null +++ b/chromeos/arc/bridge/common/arc_message_generator.cc
@@ -0,0 +1,33 @@ +// 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. + +// Get basic type definitions. +#define IPC_MESSAGE_IMPL +#include "arc_message_generator.h" + +// Generate constructors. +#include "ipc/struct_constructor_macros.h" +#include "arc_message_generator.h" + +// Generate destructors. +#include "ipc/struct_destructor_macros.h" +#include "arc_message_generator.h" + +// Generate param traits write methods. +#include "ipc/param_traits_write_macros.h" +namespace IPC { +#include "arc_message_generator.h" +} // namespace IPC + +// Generate param traits read methods. +#include "ipc/param_traits_read_macros.h" +namespace IPC { +#include "arc_message_generator.h" +} // namespace IPC + +// Generate param traits log methods. +#include "ipc/param_traits_log_macros.h" +namespace IPC { +#include "arc_message_generator.h" +} // namespace IPC
diff --git a/chromeos/arc/bridge/common/arc_message_generator.h b/chromeos/arc/bridge/common/arc_message_generator.h new file mode 100644 index 0000000..2b302a6 --- /dev/null +++ b/chromeos/arc/bridge/common/arc_message_generator.h
@@ -0,0 +1,9 @@ +// 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. + +// Multiply-included message file, hence no include guard. + +// Not using the full path since this is also expected to be compiled in ARC. +#include "arc_host_messages.h" +#include "arc_instance_messages.h"
diff --git a/chromeos/chromeos.gyp b/chromeos/chromeos.gyp index d2f05119..2f93d9ed 100644 --- a/chromeos/chromeos.gyp +++ b/chromeos/chromeos.gyp
@@ -13,6 +13,7 @@ 'accelerometer/accelerometer_types.h', 'app_mode/kiosk_oem_manifest_parser.cc', 'app_mode/kiosk_oem_manifest_parser.h', + 'arc/bridge/common/arc_message_generator.cc', 'attestation/attestation_constants.cc', 'attestation/attestation_constants.h', 'attestation/attestation_flow.cc', @@ -478,6 +479,7 @@ '../crypto/crypto.gyp:crypto', '../dbus/dbus.gyp:dbus', '../google_apis/google_apis.gyp:google_apis', + '../ipc/ipc.gyp:ipc', '../net/net.gyp:net', '../third_party/icu/icu.gyp:icui18n', '../third_party/libxml/libxml.gyp:libxml',
diff --git a/components/autofill/content/browser/content_autofill_driver_factory.cc b/components/autofill/content/browser/content_autofill_driver_factory.cc index d19bd574..565c58b 100644 --- a/components/autofill/content/browser/content_autofill_driver_factory.cc +++ b/components/autofill/content/browser/content_autofill_driver_factory.cc
@@ -57,11 +57,7 @@ base::Unretained(this))); } -ContentAutofillDriverFactory::~ContentAutofillDriverFactory() { - STLDeleteContainerPairSecondPointers(frame_driver_map_.begin(), - frame_driver_map_.end()); - frame_driver_map_.clear(); -} +ContentAutofillDriverFactory::~ContentAutofillDriverFactory() {} ContentAutofillDriver* ContentAutofillDriverFactory::DriverForFrame( content::RenderFrameHost* render_frame_host) { @@ -72,19 +68,19 @@ bool ContentAutofillDriverFactory::OnMessageReceived( const IPC::Message& message, content::RenderFrameHost* render_frame_host) { - return frame_driver_map_[render_frame_host]->HandleMessage(message); + return frame_driver_map_.find(render_frame_host) + ->second->HandleMessage(message); } void ContentAutofillDriverFactory::RenderFrameCreated( content::RenderFrameHost* render_frame_host) { // RenderFrameCreated is called more than once for the main frame. - if (!frame_driver_map_[render_frame_host]) + if (!ContainsKey(frame_driver_map_, render_frame_host)) CreateDriverForFrame(render_frame_host); } void ContentAutofillDriverFactory::RenderFrameDeleted( content::RenderFrameHost* render_frame_host) { - delete frame_driver_map_[render_frame_host]; frame_driver_map_.erase(render_frame_host); } @@ -92,7 +88,7 @@ content::RenderFrameHost* rfh, const content::LoadCommittedDetails& details, const content::FrameNavigateParams& params) { - frame_driver_map_[rfh]->DidNavigateFrame(details, params); + frame_driver_map_.find(rfh)->second->DidNavigateFrame(details, params); } void ContentAutofillDriverFactory::NavigationEntryCommitted( @@ -106,9 +102,11 @@ void ContentAutofillDriverFactory::CreateDriverForFrame( content::RenderFrameHost* render_frame_host) { - DCHECK(!frame_driver_map_[render_frame_host]); - frame_driver_map_[render_frame_host] = new ContentAutofillDriver( - render_frame_host, client_, app_locale_, enable_download_manager_); + DCHECK(!ContainsKey(frame_driver_map_, render_frame_host)); + frame_driver_map_.set( + render_frame_host, + make_scoped_ptr(new ContentAutofillDriver( + render_frame_host, client_, app_locale_, enable_download_manager_))); } } // namespace autofill
diff --git a/components/autofill/content/browser/content_autofill_driver_factory.h b/components/autofill/content/browser/content_autofill_driver_factory.h index c0b1aa1..95f8df6 100644 --- a/components/autofill/content/browser/content_autofill_driver_factory.h +++ b/components/autofill/content/browser/content_autofill_driver_factory.h
@@ -7,6 +7,7 @@ #include <string> +#include "base/containers/scoped_ptr_map.h" #include "base/memory/scoped_ptr.h" #include "base/supports_user_data.h" #include "components/autofill/content/browser/request_autocomplete_manager.h" @@ -74,7 +75,8 @@ std::string app_locale_; AutofillManager::AutofillDownloadManagerState enable_download_manager_; - std::map<content::RenderFrameHost*, ContentAutofillDriver*> frame_driver_map_; + base::ScopedPtrMap<content::RenderFrameHost*, + scoped_ptr<ContentAutofillDriver>> frame_driver_map_; }; } // namespace autofill
diff --git a/components/mus/example/wm/BUILD.gn b/components/mus/example/wm/BUILD.gn index faf1b6c..82df07e 100644 --- a/components/mus/example/wm/BUILD.gn +++ b/components/mus/example/wm/BUILD.gn
@@ -22,6 +22,10 @@ "layout_manager.h", "move_loop.cc", "move_loop.h", + "non_client_frame_controller.cc", + "non_client_frame_controller.h", + "non_client_frame_view_impl.cc", + "non_client_frame_view_impl.h", "property_util.cc", "property_util.h", "shelf_layout.cc", @@ -42,6 +46,10 @@ "//mojo/application/public/cpp", "//mojo/common:common_base", "//mojo/converters/geometry", + "//skia", + "//ui/mojo/init", + "//ui/views", + "//ui/views/mus", ] } @@ -53,11 +61,14 @@ deps = [ ":example_wm_lib", "//mojo/application/public/cpp", + "//ui/views/mus:resources", ] data_deps = [ "//components/mus", ] + + resources = [ "$root_out_dir/views_mus_resources.pak" ] } mojo_native_application("apptests") {
diff --git a/components/mus/example/wm/move_loop.cc b/components/mus/example/wm/move_loop.cc index 28e33bc..926855e9 100644 --- a/components/mus/example/wm/move_loop.cc +++ b/components/mus/example/wm/move_loop.cc
@@ -31,6 +31,12 @@ mus::mojom::EVENT_FLAGS_RIGHT_MOUSE_BUTTON)); } +gfx::Rect ClientAreaBounds(const mus::Window* window) { + gfx::Rect client_area(window->bounds().size()); + client_area.Inset(window->client_area()); + return client_area; +} + } // namespace MoveLoop::~MoveLoop() { @@ -44,7 +50,7 @@ DCHECK_EQ(event.action, mus::mojom::EVENT_TYPE_POINTER_DOWN); const gfx::Point location(EventLocationToPoint(event)); if (!gfx::Rect(target->bounds().size()).Contains(location) || - target->client_area().Contains(location)) { + ClientAreaBounds(target).Contains(location)) { return nullptr; } @@ -123,16 +129,17 @@ kResizeSize * std::max(1.f, target->viewport_metrics().device_pixel_ratio)); - if (location.x() < target->client_area().x()) + const gfx::Rect client_area(ClientAreaBounds(target)); + if (location.x() < client_area.x()) *h_loc = HorizontalLocation::LEFT; - else if (location.x() >= target->client_area().right()) + else if (location.x() >= client_area.right()) *h_loc = HorizontalLocation::RIGHT; else *h_loc = HorizontalLocation::OTHER; if (location.y() < resize_size) *v_loc = VerticalLocation::TOP; - else if (location.y() >= target->client_area().bottom()) + else if (location.y() >= client_area.bottom()) *v_loc = VerticalLocation::BOTTOM; else *v_loc = VerticalLocation::OTHER;
diff --git a/components/mus/example/wm/move_loop_unittest.cc b/components/mus/example/wm/move_loop_unittest.cc index 175e6cf8..13229a4 100644 --- a/components/mus/example/wm/move_loop_unittest.cc +++ b/components/mus/example/wm/move_loop_unittest.cc
@@ -22,10 +22,9 @@ if (window->bounds().IsEmpty()) window->SetBounds(gfx::Rect(100, 200, 300, 400)); - gfx::Rect client_area(window->bounds().size()); - client_area.Inset(MoveLoop::kResizeSize, MoveLoop::kResizeSize + 10, - MoveLoop::kResizeSize, MoveLoop::kResizeSize); - window->SetClientArea(client_area); + window->SetClientArea( + gfx::Insets(MoveLoop::kResizeSize + 10, MoveLoop::kResizeSize, + MoveLoop::kResizeSize, MoveLoop::kResizeSize)); } mus::mojom::EventPtr CreatePointerDownEvent(const gfx::Point& location) {
diff --git a/components/mus/example/wm/non_client_frame_controller.cc b/components/mus/example/wm/non_client_frame_controller.cc new file mode 100644 index 0000000..8cd5add --- /dev/null +++ b/components/mus/example/wm/non_client_frame_controller.cc
@@ -0,0 +1,53 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/mus/example/wm/non_client_frame_controller.h" + +#include "components/mus/example/wm/non_client_frame_view_impl.h" +#include "components/mus/public/cpp/window.h" +#include "ui/views/mus/native_widget_mus.h" +#include "ui/views/widget/widget.h" + +namespace { + +class WmNativeWidgetMus : public views::NativeWidgetMus { + public: + WmNativeWidgetMus(views::internal::NativeWidgetDelegate* delegate, + mojo::Shell* shell, + mus::Window* window) + : NativeWidgetMus(delegate, + shell, + window, + mus::mojom::SURFACE_TYPE_UNDERLAY) {} + ~WmNativeWidgetMus() override {} + + // NativeWidgetMus: + views::NonClientFrameView* CreateNonClientFrameView() override { + NonClientFrameViewImpl* frame_view = new NonClientFrameViewImpl(window()); + frame_view->Init( + static_cast<views::internal::NativeWidgetPrivate*>(this)->GetWidget()); + return frame_view; + } + + private: + DISALLOW_COPY_AND_ASSIGN(WmNativeWidgetMus); +}; + +} // namespace + +NonClientFrameController::NonClientFrameController(mojo::Shell* shell, + mus::Window* window) { + views::Widget* widget = new views::Widget; + views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW); + params.delegate = this; + params.native_widget = new WmNativeWidgetMus(widget, shell, window); + widget->Init(params); + widget->Show(); +} + +NonClientFrameController::~NonClientFrameController() {} + +views::View* NonClientFrameController::GetContentsView() { + return this; +}
diff --git a/components/mus/example/wm/non_client_frame_controller.h b/components/mus/example/wm/non_client_frame_controller.h new file mode 100644 index 0000000..914f7eb --- /dev/null +++ b/components/mus/example/wm/non_client_frame_controller.h
@@ -0,0 +1,34 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_MUS_EXAMPLE_WM_NON_CLIENT_FRAME_CONTROLLER_H_ +#define COMPONENTS_MUS_EXAMPLE_WM_NON_CLIENT_FRAME_CONTROLLER_H_ + +#include "base/macros.h" +#include "ui/views/widget/widget_delegate.h" + +namespace mojo { +class Shell; +} + +namespace mus { +class Window; +} + +// Provides the non-client frame for mus Windows. +class NonClientFrameController : public views::WidgetDelegateView { + public: + // NonClientFrameController deletes itself when |window| is destroyed. + NonClientFrameController(mojo::Shell* shell, mus::Window* window); + + private: + ~NonClientFrameController() override; + + // views::WidgetDelegateView: + views::View* GetContentsView() override; + + DISALLOW_COPY_AND_ASSIGN(NonClientFrameController); +}; + +#endif // COMPONENTS_MUS_EXAMPLE_WM_NON_CLIENT_FRAME_CONTROLLER_H_
diff --git a/components/mus/example/wm/non_client_frame_view_impl.cc b/components/mus/example/wm/non_client_frame_view_impl.cc new file mode 100644 index 0000000..7ca7a223 --- /dev/null +++ b/components/mus/example/wm/non_client_frame_view_impl.cc
@@ -0,0 +1,58 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/mus/example/wm/non_client_frame_view_impl.h" + +#include "components/mus/public/cpp/window.h" +#include "ui/compositor/paint_recorder.h" +#include "ui/gfx/canvas.h" + +NonClientFrameViewImpl::NonClientFrameViewImpl(mus::Window* window) + : window_(window) { + window_->AddObserver(this); +} + +NonClientFrameViewImpl::~NonClientFrameViewImpl() { + if (window_) + window_->RemoveObserver(this); +} + +gfx::Rect NonClientFrameViewImpl::GetBoundsForClientView() const { + gfx::Rect result(GetLocalBounds()); + result.Inset(window_->client_area()); + return result; +} + +void NonClientFrameViewImpl::OnPaint(gfx::Canvas* canvas) { + canvas->Save(); + CustomFrameView::OnPaint(canvas); + canvas->Restore(); + + // The client app draws the client area. Make ours totally transparent so + // we only see the client apps client area. + canvas->FillRect(GetBoundsForClientView(), SK_ColorBLACK, + SkXfermode::kSrc_Mode); +} + +void NonClientFrameViewImpl::PaintChildren(const ui::PaintContext& context) { + CustomFrameView::PaintChildren(context); + + // The client app draws the client area. Make ours totally transparent so + // we only see the client apps client area. + ui::PaintRecorder recorder(context, size(), &paint_cache_); + recorder.canvas()->FillRect(GetBoundsForClientView(), SK_ColorBLACK, + SkXfermode::kSrc_Mode); +} + +void NonClientFrameViewImpl::OnWindowClientAreaChanged( + mus::Window* window, + const gfx::Insets& old_client_area) { + Layout(); + SchedulePaint(); +} + +void NonClientFrameViewImpl::OnWindowDestroyed(mus::Window* window) { + window_->RemoveObserver(this); + window_ = nullptr; +}
diff --git a/components/mus/example/wm/non_client_frame_view_impl.h b/components/mus/example/wm/non_client_frame_view_impl.h new file mode 100644 index 0000000..b5a9d319 --- /dev/null +++ b/components/mus/example/wm/non_client_frame_view_impl.h
@@ -0,0 +1,37 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_MUS_EXAMPLE_WM_NON_CLIENT_FRAME_VIEW_IMPL_H_ +#define COMPONENTS_MUS_EXAMPLE_WM_NON_CLIENT_FRAME_VIEW_IMPL_H_ + +#include "base/macros.h" +#include "components/mus/public/cpp/window_observer.h" +#include "ui/compositor/paint_cache.h" +#include "ui/views/window/custom_frame_view.h" + +class NonClientFrameViewImpl : public views::CustomFrameView, + public mus::WindowObserver { + public: + explicit NonClientFrameViewImpl(mus::Window* window); + ~NonClientFrameViewImpl() override; + + private: + // CustomFrameView: + gfx::Rect GetBoundsForClientView() const override; + void OnPaint(gfx::Canvas* canvas) override; + void PaintChildren(const ui::PaintContext& context) override; + + // mus::WindowObserver: + void OnWindowClientAreaChanged(mus::Window* window, + const gfx::Insets& old_client_area) override; + void OnWindowDestroyed(mus::Window* window) override; + + private: + mus::Window* window_; + ui::PaintCache paint_cache_; + + DISALLOW_COPY_AND_ASSIGN(NonClientFrameViewImpl); +}; + +#endif // COMPONENTS_MUS_EXAMPLE_WM_NON_CLIENT_FRAME_VIEW_IMPL_H_
diff --git a/components/mus/example/wm/window_manager_application.cc b/components/mus/example/wm/window_manager_application.cc index f5cfee7d..67e56ee 100644 --- a/components/mus/example/wm/window_manager_application.cc +++ b/components/mus/example/wm/window_manager_application.cc
@@ -13,9 +13,12 @@ #include "components/mus/public/cpp/window_tree_connection.h" #include "components/mus/public/cpp/window_tree_host_factory.h" #include "mojo/application/public/cpp/application_connection.h" +#include "ui/mojo/init/ui_init.h" +#include "ui/views/mus/aura_init.h" +#include "ui/views/mus/display_converter.h" WindowManagerApplication::WindowManagerApplication() - : root_(nullptr), window_count_(0) {} + : root_(nullptr), window_count_(0), app_(nullptr) {} WindowManagerApplication::~WindowManagerApplication() {} mus::Window* WindowManagerApplication::GetWindowForContainer( @@ -30,6 +33,7 @@ } void WindowManagerApplication::Initialize(mojo::ApplicationImpl* app) { + app_ = app; mus::mojom::WindowManagerPtr window_manager; requests_.push_back(new mojo::InterfaceRequest<mus::mojom::WindowManager>( mojo::GetProxy(&window_manager))); @@ -54,6 +58,10 @@ GetWindowForContainer(ash::mojom::CONTAINER_USER_WINDOWS))); window_manager_.reset(new WindowManagerImpl(this)); + + ui_init_.reset(new ui::mojo::UIInit(views::GetDisplaysFromWindow(root))); + aura_init_.reset(new views::AuraInit(app_, "views_mus_resources.pak")); + for (auto request : requests_) window_manager_binding_.AddBinding(window_manager_.get(), request->Pass()); requests_.clear();
diff --git a/components/mus/example/wm/window_manager_application.h b/components/mus/example/wm/window_manager_application.h index 65be459..635e1004 100644 --- a/components/mus/example/wm/window_manager_application.h +++ b/components/mus/example/wm/window_manager_application.h
@@ -21,9 +21,18 @@ class BackgroundLayout; class ShelfLayout; class WindowLayout; - class WindowManagerImpl; +namespace ui { +namespace mojo { +class UIInit; +} +} + +namespace views { +class AuraInit; +} + class WindowManagerApplication : public mojo::ApplicationDelegate, public mus::WindowObserver, @@ -41,6 +50,8 @@ mus::Window* GetWindowForContainer(ash::mojom::Container container); mus::Window* GetWindowById(mus::Id id); + mojo::ApplicationImpl* app() { return app_; } + private: // ApplicationDelegate: void Initialize(mojo::ApplicationImpl* app) override; @@ -66,8 +77,13 @@ mus::Window* root_; int window_count_; + mojo::ApplicationImpl* app_; + mus::mojom::WindowTreeHostPtr host_; + scoped_ptr<ui::mojo::UIInit> ui_init_; + scoped_ptr<views::AuraInit> aura_init_; + // |window_manager_| is created once OnEmbed() is called. Until that time // |requests_| stores any pending WindowManager interface requests. scoped_ptr<WindowManagerImpl> window_manager_;
diff --git a/components/mus/example/wm/window_manager_impl.cc b/components/mus/example/wm/window_manager_impl.cc index 9525f26..6039472 100644 --- a/components/mus/example/wm/window_manager_impl.cc +++ b/components/mus/example/wm/window_manager_impl.cc
@@ -5,6 +5,7 @@ #include "components/mus/example/wm/window_manager_impl.h" #include "components/mus/example/wm/move_loop.h" +#include "components/mus/example/wm/non_client_frame_controller.h" #include "components/mus/example/wm/property_util.h" #include "components/mus/example/wm/public/interfaces/container.mojom.h" #include "components/mus/example/wm/window_manager_application.h" @@ -14,6 +15,7 @@ #include "components/mus/public/cpp/window_property.h" #include "components/mus/public/cpp/window_tree_connection.h" #include "components/mus/public/interfaces/input_events.mojom.h" +#include "mojo/application/public/cpp/application_impl.h" #include "mojo/converters/geometry/geometry_type_converters.h" namespace { @@ -73,6 +75,9 @@ child_window->Embed(client.Pass()); child_window->AddObserver(this); + // NonClientFrameController deletes itself when the window is destroyed. + new NonClientFrameController(state_->app()->shell(), child_window); + state_->IncrementWindowCount(); } @@ -105,18 +110,36 @@ callback.Run(mus::mojom::WINDOW_MANAGER_ERROR_CODE_SUCCESS); } -void WindowManagerImpl::GetDisplays(const GetDisplaysCallback& callback) { - mojo::Array<mus::mojom::DisplayPtr> displays(1); - displays[0] = mus::mojom::Display::New(); - displays[0]->id = 2001; - displays[0]->bounds = mojo::Rect::New(); - displays[0]->bounds->y = 0; - displays[0]->bounds->width = state_->root()->bounds().width(); - displays[0]->bounds->height = state_->root()->bounds().width(); - displays[0]->work_area = displays[0]->bounds.Clone(); - displays[0]->device_pixel_ratio = +void WindowManagerImpl::GetConfig(const GetConfigCallback& callback) { + mus::mojom::WindowManagerConfigPtr config( + mus::mojom::WindowManagerConfig::New()); + config->displays = mojo::Array<mus::mojom::DisplayPtr>::New(1); + config->displays[0] = mus::mojom::Display::New(); + config->displays[0]->id = 2001; + config->displays[0]->bounds = mojo::Rect::New(); + config->displays[0]->bounds->y = 0; + config->displays[0]->bounds->width = state_->root()->bounds().width(); + config->displays[0]->bounds->height = state_->root()->bounds().width(); + config->displays[0]->work_area = config->displays[0]->bounds.Clone(); + config->displays[0]->device_pixel_ratio = state_->root()->viewport_metrics().device_pixel_ratio; - callback.Run(displays.Pass()); + + // The insets are roughly what is needed by CustomFrameView. The expectation + // is at some point we'll write our own NonClientFrameView and get the insets + // from it. + config->normal_client_area_insets = mojo::Insets::New(); + config->normal_client_area_insets->top = 23; + config->normal_client_area_insets->left = 5; + config->normal_client_area_insets->right = 5; + config->normal_client_area_insets->bottom = 5; + + config->maximized_client_area_insets = mojo::Insets::New(); + config->maximized_client_area_insets->top = 21; + config->maximized_client_area_insets->left = 0; + config->maximized_client_area_insets->right = 0; + config->maximized_client_area_insets->bottom = 0; + + callback.Run(config.Pass()); } void WindowManagerImpl::OnWindowDestroyed(mus::Window* window) {
diff --git a/components/mus/example/wm/window_manager_impl.h b/components/mus/example/wm/window_manager_impl.h index 5551a47..3df0aa2 100644 --- a/components/mus/example/wm/window_manager_impl.h +++ b/components/mus/example/wm/window_manager_impl.h
@@ -39,7 +39,7 @@ void SetShowState(mus::Id window_id, mus::mojom::ShowState show_state, const WindowManagerErrorCodeCallback& callback) override; - void GetDisplays(const GetDisplaysCallback& callback) override; + void GetConfig(const GetConfigCallback& callback) override; // mus::WindowObserver: void OnWindowDestroyed(mus::Window* window) override;
diff --git a/components/mus/public/cpp/lib/window.cc b/components/mus/public/cpp/lib/window.cc index 13f5009..a8cd5219 100644 --- a/components/mus/public/cpp/lib/window.cc +++ b/components/mus/public/cpp/lib/window.cc
@@ -214,7 +214,7 @@ LocalSetBounds(bounds_, bounds); } -void Window::SetClientArea(const gfx::Rect& client_area) { +void Window::SetClientArea(const gfx::Insets& client_area) { if (!OwnsWindow(connection_, this) && !IsConnectionRoot(this)) return; @@ -535,13 +535,11 @@ // the bounds. DCHECK(!OwnsWindow(connection_, this) || old_bounds == bounds_); ScopedSetBoundsNotifier notifier(this, old_bounds, new_bounds); - if (bounds_.size() != new_bounds.size()) - client_area_ = gfx::Rect(new_bounds.size()); bounds_ = new_bounds; } -void Window::LocalSetClientArea(const gfx::Rect& new_client_area) { - const gfx::Rect old_client_area = client_area_; +void Window::LocalSetClientArea(const gfx::Insets& new_client_area) { + const gfx::Insets old_client_area = client_area_; client_area_ = new_client_area; FOR_EACH_OBSERVER(WindowObserver, observers_, OnWindowClientAreaChanged(this, old_client_area));
diff --git a/components/mus/public/cpp/lib/window_private.h b/components/mus/public/cpp/lib/window_private.h index 4f9b57f..d566a60 100644 --- a/components/mus/public/cpp/lib/window_private.h +++ b/components/mus/public/cpp/lib/window_private.h
@@ -54,7 +54,7 @@ const gfx::Rect& new_bounds) { window_->LocalSetBounds(old_bounds, new_bounds); } - void LocalSetClientArea(const gfx::Rect& new_client_area) { + void LocalSetClientArea(const gfx::Insets& new_client_area) { window_->LocalSetClientArea(new_client_area); } void LocalSetDrawn(bool drawn) { window_->LocalSetDrawn(drawn); }
diff --git a/components/mus/public/cpp/lib/window_tree_client_impl.cc b/components/mus/public/cpp/lib/window_tree_client_impl.cc index fff7f2d..b869e442 100644 --- a/components/mus/public/cpp/lib/window_tree_client_impl.cc +++ b/components/mus/public/cpp/lib/window_tree_client_impl.cc
@@ -15,6 +15,7 @@ #include "mojo/application/public/cpp/service_provider_impl.h" #include "mojo/application/public/interfaces/service_provider.mojom.h" #include "mojo/converters/geometry/geometry_type_converters.h" +#include "ui/gfx/geometry/insets.h" #include "ui/gfx/geometry/size.h" namespace mus { @@ -182,9 +183,9 @@ } void WindowTreeClientImpl::SetClientArea(Id window_id, - const gfx::Rect& client_area) { + const gfx::Insets& client_area) { DCHECK(tree_); - tree_->SetClientArea(window_id, mojo::Rect::From(client_area)); + tree_->SetClientArea(window_id, mojo::Insets::From(client_area)); } void WindowTreeClientImpl::SetFocus(Id window_id) { @@ -361,12 +362,13 @@ .LocalSetBounds(old_bounds.To<gfx::Rect>(), new_bounds.To<gfx::Rect>()); } -void WindowTreeClientImpl::OnClientAreaChanged(uint32_t window_id, - mojo::RectPtr old_client_area, - mojo::RectPtr new_client_area) { +void WindowTreeClientImpl::OnClientAreaChanged( + uint32_t window_id, + mojo::InsetsPtr old_client_area, + mojo::InsetsPtr new_client_area) { Window* window = GetWindowById(window_id); if (window) - WindowPrivate(window).LocalSetClientArea(new_client_area.To<gfx::Rect>()); + WindowPrivate(window).LocalSetClientArea(new_client_area.To<gfx::Insets>()); } namespace {
diff --git a/components/mus/public/cpp/lib/window_tree_client_impl.h b/components/mus/public/cpp/lib/window_tree_client_impl.h index c6ce955b..4b8baeac 100644 --- a/components/mus/public/cpp/lib/window_tree_client_impl.h +++ b/components/mus/public/cpp/lib/window_tree_client_impl.h
@@ -12,6 +12,7 @@ #include "third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h" namespace gfx { +class Insets; class Size; } @@ -52,7 +53,7 @@ bool OwnsWindow(Id id) const; void SetBounds(Id window_id, const gfx::Rect& bounds); - void SetClientArea(Id window_id, const gfx::Rect& client_area); + void SetClientArea(Id window_id, const gfx::Insets& client_area); void SetFocus(Id window_id); void SetVisible(Id window_id, bool visible); void SetProperty(Id window_id, @@ -123,8 +124,8 @@ mojo::RectPtr old_bounds, mojo::RectPtr new_bounds) override; void OnClientAreaChanged(uint32_t window_id, - mojo::RectPtr old_client_area, - mojo::RectPtr new_client_area) override; + mojo::InsetsPtr old_client_area, + mojo::InsetsPtr new_client_area) override; void OnWindowViewportMetricsChanged( mojom::ViewportMetricsPtr old_metrics, mojom::ViewportMetricsPtr new_metrics) override;
diff --git a/components/mus/public/cpp/window.h b/components/mus/public/cpp/window.h index 1e4f1d6..f3e39e8a 100644 --- a/components/mus/public/cpp/window.h +++ b/components/mus/public/cpp/window.h
@@ -17,6 +17,7 @@ #include "mojo/application/public/interfaces/service_provider.mojom.h" #include "third_party/mojo/src/mojo/public/cpp/bindings/array.h" #include "third_party/mojo/src/mojo/public/cpp/system/macros.h" +#include "ui/gfx/geometry/insets.h" #include "ui/gfx/geometry/rect.h" namespace gfx { @@ -63,8 +64,8 @@ const gfx::Rect& bounds() const { return bounds_; } void SetBounds(const gfx::Rect& bounds); - const gfx::Rect& client_area() const { return client_area_; } - void SetClientArea(const gfx::Rect& client_area); + const gfx::Insets& client_area() const { return client_area_; } + void SetClientArea(const gfx::Insets& new_client_area); // Visibility (also see IsDrawn()). When created windows are hidden. bool visible() const { return visible_; } @@ -199,7 +200,7 @@ // Returns true if the order actually changed. bool LocalReorder(Window* relative, mojom::OrderDirection direction); void LocalSetBounds(const gfx::Rect& old_bounds, const gfx::Rect& new_bounds); - void LocalSetClientArea(const gfx::Rect& new_client_area); + void LocalSetClientArea(const gfx::Insets& new_client_area); void LocalSetViewportMetrics(const mojom::ViewportMetrics& old_metrics, const mojom::ViewportMetrics& new_metrics); void LocalSetDrawn(bool drawn); @@ -231,7 +232,7 @@ base::ObserverList<WindowObserver> observers_; gfx::Rect bounds_; - gfx::Rect client_area_; + gfx::Insets client_area_; mojom::ViewportMetricsPtr viewport_metrics_;
diff --git a/components/mus/public/cpp/window_observer.h b/components/mus/public/cpp/window_observer.h index 91fd666..979428ad 100644 --- a/components/mus/public/cpp/window_observer.h +++ b/components/mus/public/cpp/window_observer.h
@@ -55,7 +55,7 @@ const gfx::Rect& old_bounds, const gfx::Rect& new_bounds) {} virtual void OnWindowClientAreaChanged(Window* window, - const gfx::Rect& old_client_area) {} + const gfx::Insets& old_client_area) {} virtual void OnWindowViewportMetricsChanged( Window* window,
diff --git a/components/mus/public/interfaces/window_manager.mojom b/components/mus/public/interfaces/window_manager.mojom index c7881f4..140e455a 100644 --- a/components/mus/public/interfaces/window_manager.mojom +++ b/components/mus/public/interfaces/window_manager.mojom
@@ -8,6 +8,12 @@ import "components/mus/public/interfaces/window_tree.mojom"; import "ui/mojo/geometry/geometry.mojom"; +struct WindowManagerConfig { + array<Display> displays; + mojo.Insets normal_client_area_insets; + mojo.Insets maximized_client_area_insets; +}; + // Represents a core interface that should be implemented by any window manager // built on top of Mus. // For security reasons, methods that take window_ids can only pass window ids @@ -35,5 +41,5 @@ SetShowState(uint32 window_id, ShowState show_state) => (WindowManagerErrorCode result); - GetDisplays() => (array<Display> displays); + GetConfig() => (WindowManagerConfig config); };
diff --git a/components/mus/public/interfaces/window_tree.mojom b/components/mus/public/interfaces/window_tree.mojom index 345f571..67a2f3a 100644 --- a/components/mus/public/interfaces/window_tree.mojom +++ b/components/mus/public/interfaces/window_tree.mojom
@@ -90,9 +90,8 @@ // Sets the specified bounds of the specified window. SetWindowBounds(uint32 window_id, mojo.Rect bounds) => (bool success); - // Sets the client area of the specified window. Areas outside the client - // area are treated specially. - SetClientArea(uint32 window_id, mojo.Rect rect); + // Sets the insets of the client area of the specified window. + SetClientArea(uint32 window_id, mojo.Insets insets); // Sets the visibility of the specified window to |visible|. Connections are // allowed to change the visibility of any window they have created, as well @@ -197,7 +196,6 @@ (WindowManagerErrorCode result); SetShowState(uint32 window_id, ShowState show_state) => (WindowManagerErrorCode result); - GetDisplays() => (array<Display> displays); }; // Changes to windows are not sent to the connection that originated the @@ -231,8 +229,8 @@ mojo.Rect new_bounds); OnClientAreaChanged(uint32 window_id, - mojo.Rect old_client_area, - mojo.Rect new_client_area); + mojo.Insets old_client_area, + mojo.Insets new_client_area); // Invoked when the viewport metrics for the window have changed. // Clients are expected to propagate this to the window tree.
diff --git a/components/mus/ws/connection_manager.cc b/components/mus/ws/connection_manager.cc index e4ee980..ede74e9 100644 --- a/components/mus/ws/connection_manager.cc +++ b/components/mus/ws/connection_manager.cc
@@ -255,8 +255,8 @@ void ConnectionManager::ProcessClientAreaChanged( const ServerWindow* window, - const gfx::Rect& old_client_area, - const gfx::Rect& new_client_area) { + const gfx::Insets& old_client_area, + const gfx::Insets& new_client_area) { for (auto& pair : connection_map_) { pair.second->service()->ProcessClientAreaChanged( window, old_client_area, new_client_area, IsChangeSource(pair.first)); @@ -387,8 +387,8 @@ void ConnectionManager::OnWindowClientAreaChanged( ServerWindow* window, - const gfx::Rect& old_client_area, - const gfx::Rect& new_client_area) { + const gfx::Insets& old_client_area, + const gfx::Insets& new_client_area) { if (in_destructor_) return;
diff --git a/components/mus/ws/connection_manager.h b/components/mus/ws/connection_manager.h index 088bd1a..4fca836e 100644 --- a/components/mus/ws/connection_manager.h +++ b/components/mus/ws/connection_manager.h
@@ -160,8 +160,8 @@ const gfx::Rect& old_bounds, const gfx::Rect& new_bounds); void ProcessClientAreaChanged(const ServerWindow* window, - const gfx::Rect& old_client_area, - const gfx::Rect& new_client_area); + const gfx::Insets& old_client_area, + const gfx::Insets& new_client_area); void ProcessViewportMetricsChanged(const mojom::ViewportMetrics& old_metrics, const mojom::ViewportMetrics& new_metrics); void ProcessWillChangeWindowHierarchy(const ServerWindow* window, @@ -216,8 +216,8 @@ const gfx::Rect& old_bounds, const gfx::Rect& new_bounds) override; void OnWindowClientAreaChanged(ServerWindow* window, - const gfx::Rect& old_client_area, - const gfx::Rect& new_client_area) override; + const gfx::Insets& old_client_area, + const gfx::Insets& new_client_area) override; void OnWindowReordered(ServerWindow* window, ServerWindow* relative, mojom::OrderDirection direction) override;
diff --git a/components/mus/ws/event_dispatcher.cc b/components/mus/ws/event_dispatcher.cc index aa06ec4..2df70ca 100644 --- a/components/mus/ws/event_dispatcher.cc +++ b/components/mus/ws/event_dispatcher.cc
@@ -34,8 +34,12 @@ bool IsLocationInNonclientArea(const ServerWindow* target, const gfx::Point& location) { - return target->parent() && - !target->client_area().Contains(location); + if (!target->parent()) + return false; + + gfx::Rect client_area(target->bounds().size()); + client_area.Inset(target->client_area()); + return !client_area.Contains(location); } gfx::Point EventLocationToPoint(const mojom::Event& event) {
diff --git a/components/mus/ws/event_dispatcher_unittest.cc b/components/mus/ws/event_dispatcher_unittest.cc index 2dec66c..2cfbf29 100644 --- a/components/mus/ws/event_dispatcher_unittest.cc +++ b/components/mus/ws/event_dispatcher_unittest.cc
@@ -303,7 +303,7 @@ root.SetBounds(gfx::Rect(0, 0, 100, 100)); child.SetBounds(gfx::Rect(10, 10, 20, 20)); - child.SetClientArea(gfx::Rect(5, 5, 10, 10)); + child.SetClientArea(gfx::Insets(5, 5, 5, 5)); TestEventDispatcherDelegate event_dispatcher_delegate(&root); EventDispatcher dispatcher(&event_dispatcher_delegate);
diff --git a/components/mus/ws/server_window.cc b/components/mus/ws/server_window.cc index 49a4d91..b0348d40 100644 --- a/components/mus/ws/server_window.cc +++ b/components/mus/ws/server_window.cc
@@ -122,26 +122,20 @@ // TODO(fsamuel): figure out how will this work with CompositorFrames. - // |client_area_| is relative to the bounds. If the size of bounds change - // we have to reset the client area. We assume any size change is quicky - // followed by a client area change. - if (bounds_.size() != bounds.size()) - client_area_ = gfx::Rect(bounds.size()); - const gfx::Rect old_bounds = bounds_; bounds_ = bounds; FOR_EACH_OBSERVER(ServerWindowObserver, observers_, OnWindowBoundsChanged(this, old_bounds, bounds)); } -void ServerWindow::SetClientArea(const gfx::Rect& bounds) { - if (client_area_ == bounds) +void ServerWindow::SetClientArea(const gfx::Insets& insets) { + if (client_area_ == insets) return; - const gfx::Rect old_client_area = client_area_; - client_area_ = bounds; + const gfx::Insets old_client_area = client_area_; + client_area_ = insets; FOR_EACH_OBSERVER(ServerWindowObserver, observers_, - OnWindowClientAreaChanged(this, old_client_area, bounds)); + OnWindowClientAreaChanged(this, old_client_area, insets)); } const ServerWindow* ServerWindow::GetRoot() const {
diff --git a/components/mus/ws/server_window.h b/components/mus/ws/server_window.h index 0fa7810c..614c082 100644 --- a/components/mus/ws/server_window.h +++ b/components/mus/ws/server_window.h
@@ -15,12 +15,12 @@ #include "components/mus/ws/ids.h" #include "components/mus/ws/server_window_surface.h" #include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h" +#include "ui/gfx/geometry/insets.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/transform.h" #include "ui/platform_window/text_input_state.h" namespace mus { - namespace ws { class ServerWindowDelegate; @@ -66,8 +66,8 @@ // area to fill the whole bounds. void SetBounds(const gfx::Rect& bounds); - const gfx::Rect& client_area() const { return client_area_; } - void SetClientArea(const gfx::Rect& bounds); + const gfx::Insets& client_area() const { return client_area_; } + void SetClientArea(const gfx::Insets& insets); const ServerWindow* parent() const { return parent_; } ServerWindow* parent() { return parent_; } @@ -137,7 +137,7 @@ Windows children_; bool visible_; gfx::Rect bounds_; - gfx::Rect client_area_; + gfx::Insets client_area_; scoped_ptr<ServerWindowSurfaceManager> surface_manager_; float opacity_; gfx::Transform transform_; @@ -151,7 +151,6 @@ }; } // namespace ws - } // namespace mus #endif // COMPONENTS_MUS_WS_SERVER_WINDOW_H_
diff --git a/components/mus/ws/server_window_observer.h b/components/mus/ws/server_window_observer.h index f963ceb..be51d04 100644 --- a/components/mus/ws/server_window_observer.h +++ b/components/mus/ws/server_window_observer.h
@@ -8,6 +8,7 @@ #include "components/mus/public/interfaces/mus_constants.mojom.h" namespace gfx { +class Insets; class Rect; } @@ -46,8 +47,8 @@ const gfx::Rect& new_bounds) {} virtual void OnWindowClientAreaChanged(ServerWindow* window, - const gfx::Rect& old_client_area, - const gfx::Rect& new_client_area) {} + const gfx::Insets& old_client_area, + const gfx::Insets& new_client_area) {} virtual void OnWindowReordered(ServerWindow* window, ServerWindow* relative,
diff --git a/components/mus/ws/window_manager_client_apptest.cc b/components/mus/ws/window_manager_client_apptest.cc index b204b6cd..6105047 100644 --- a/components/mus/ws/window_manager_client_apptest.cc +++ b/components/mus/ws/window_manager_client_apptest.cc
@@ -61,7 +61,7 @@ private: // Overridden from WindowObserver: void OnWindowClientAreaChanged(Window* window, - const gfx::Rect& old_client_area) override { + const gfx::Insets& old_client_area) override { DCHECK_EQ(window, window_); EXPECT_TRUE(WindowServerTestBase::QuitRunLoop()); } @@ -879,16 +879,16 @@ WindowTreeConnection* embedded_connection = Embed(embed_window).connection; // Verify change from embedded makes it to parent. - embedded_connection->GetRoot()->SetClientArea(gfx::Rect(1, 2, 3, 4)); + embedded_connection->GetRoot()->SetClientArea(gfx::Insets(1, 2, 3, 4)); ASSERT_TRUE(WaitForClientAreaToChange(embed_window)); - EXPECT_TRUE(gfx::Rect(1, 2, 3, 4) == embed_window->client_area()); + EXPECT_TRUE(gfx::Insets(1, 2, 3, 4) == embed_window->client_area()); - // Verify bounds change results in resetting client area in embedded. + // Changing bounds shouldn't effect client area. embed_window->SetBounds(gfx::Rect(21, 22, 23, 24)); WaitForBoundsToChange(embedded_connection->GetRoot()); EXPECT_TRUE(gfx::Rect(21, 22, 23, 24) == embedded_connection->GetRoot()->bounds()); - EXPECT_TRUE(gfx::Rect(0, 0, 23, 24) == + EXPECT_TRUE(gfx::Insets(1, 2, 3, 4) == embedded_connection->GetRoot()->client_area()); }
diff --git a/components/mus/ws/window_tree_apptest.cc b/components/mus/ws/window_tree_apptest.cc index 46862937..3cc0ca0 100644 --- a/components/mus/ws/window_tree_apptest.cc +++ b/components/mus/ws/window_tree_apptest.cc
@@ -330,8 +330,8 @@ new_bounds.Pass()); } void OnClientAreaChanged(uint32_t window_id, - mojo::RectPtr old_client_area, - mojo::RectPtr new_client_area) override {} + mojo::InsetsPtr old_client_area, + mojo::InsetsPtr new_client_area) override {} void OnWindowViewportMetricsChanged(ViewportMetricsPtr old_metrics, ViewportMetricsPtr new_metrics) override { // Don't track the metrics as they are available at an indeterministic time
diff --git a/components/mus/ws/window_tree_impl.cc b/components/mus/ws/window_tree_impl.cc index 38740b9..d8872fd 100644 --- a/components/mus/ws/window_tree_impl.cc +++ b/components/mus/ws/window_tree_impl.cc
@@ -187,15 +187,16 @@ Rect::From(new_bounds)); } -void WindowTreeImpl::ProcessClientAreaChanged(const ServerWindow* window, - const gfx::Rect& old_client_area, - const gfx::Rect& new_client_area, - bool originated_change) { +void WindowTreeImpl::ProcessClientAreaChanged( + const ServerWindow* window, + const gfx::Insets& old_client_area, + const gfx::Insets& new_client_area, + bool originated_change) { if (originated_change || !IsWindowKnown(window)) return; client()->OnClientAreaChanged(WindowIdToTransportId(window->id()), - Rect::From(old_client_area), - Rect::From(new_client_area)); + mojo::Insets::From(old_client_area), + mojo::Insets::From(new_client_area)); } void WindowTreeImpl::ProcessViewportMetricsChanged( @@ -702,16 +703,14 @@ } } -void WindowTreeImpl::SetClientArea(Id transport_window_id, mojo::RectPtr rect) { +void WindowTreeImpl::SetClientArea(Id transport_window_id, + mojo::InsetsPtr insets) { ServerWindow* window = GetWindow(WindowIdFromTransportId(transport_window_id)); if (!window || !access_policy_->CanSetClientArea(window)) return; - if (rect.is_null()) - window->SetClientArea(gfx::Rect(window->bounds().size())); - else - window->SetClientArea(rect.To<gfx::Rect>()); + window->SetClientArea(insets.To<gfx::Insets>()); } void WindowTreeImpl::Embed(Id transport_window_id, @@ -758,13 +757,6 @@ GetHost()->window_manager()->SetShowState(window_id, show_state, callback); } -void WindowTreeImpl::GetDisplays(const GetDisplaysCallback& callback) { - if (!GetHost() || !GetHost()->window_manager()) - return; - - GetHost()->window_manager()->GetDisplays(callback); -} - bool WindowTreeImpl::IsRootForAccessPolicy(const WindowId& id) const { return IsRoot(id); }
diff --git a/components/mus/ws/window_tree_impl.h b/components/mus/ws/window_tree_impl.h index c38486e..c8c7f8c 100644 --- a/components/mus/ws/window_tree_impl.h +++ b/components/mus/ws/window_tree_impl.h
@@ -19,6 +19,7 @@ #include "components/mus/ws/ids.h" namespace gfx { +class Insets; class Rect; } @@ -91,8 +92,8 @@ const gfx::Rect& new_bounds, bool originated_change); void ProcessClientAreaChanged(const ServerWindow* window, - const gfx::Rect& old_client_area, - const gfx::Rect& new_client_area, + const gfx::Insets& old_client_area, + const gfx::Insets& new_client_area, bool originated_change); void ProcessViewportMetricsChanged(const mojom::ViewportMetrics& old_metrics, const mojom::ViewportMetrics& new_metrics, @@ -220,14 +221,13 @@ void SetImeVisibility(Id transport_window_id, bool visible, mojo::TextInputStatePtr state) override; - void SetClientArea(Id transport_window_id, mojo::RectPtr rect) override; + void SetClientArea(Id transport_window_id, mojo::InsetsPtr insets) override; void SetPreferredSize(uint32_t window_id, mojo::SizePtr size, const SetPreferredSizeCallback& callback) override; void SetShowState(uint32_t window_id, mus::mojom::ShowState show_state, const SetShowStateCallback& callback) override; - void GetDisplays(const GetDisplaysCallback& callback) override; // AccessPolicyDelegate: bool IsRootForAccessPolicy(const WindowId& id) const override;
diff --git a/components/mus/ws/window_tree_unittest.cc b/components/mus/ws/window_tree_unittest.cc index 399a38ca..19cdff1 100644 --- a/components/mus/ws/window_tree_unittest.cc +++ b/components/mus/ws/window_tree_unittest.cc
@@ -77,8 +77,8 @@ new_bounds.Pass()); } void OnClientAreaChanged(uint32_t window_id, - mojo::RectPtr old_client_area, - mojo::RectPtr new_client_area) override {} + mojo::InsetsPtr old_client_area, + mojo::InsetsPtr new_client_area) override {} void OnWindowViewportMetricsChanged( mojom::ViewportMetricsPtr old_metrics, mojom::ViewportMetricsPtr new_metrics) override {
diff --git a/components/test_runner/test_runner.cc b/components/test_runner/test_runner.cc index 996cd35..2ffbee56 100644 --- a/components/test_runner/test_runner.cc +++ b/components/test_runner/test_runner.cc
@@ -7,6 +7,7 @@ #include <limits> #include "base/logging.h" +#include "base/strings/stringprintf.h" #include "build/build_config.h" #include "components/test_runner/mock_credential_manager_client.h" #include "components/test_runner/mock_web_speech_recognizer.h" @@ -39,6 +40,7 @@ #include "third_party/WebKit/public/web/WebInputElement.h" #include "third_party/WebKit/public/web/WebKit.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" +#include "third_party/WebKit/public/web/WebPageImportanceSignals.h" #include "third_party/WebKit/public/web/WebScriptSource.h" #include "third_party/WebKit/public/web/WebSecurityPolicy.h" #include "third_party/WebKit/public/web/WebSerializedScriptValue.h" @@ -258,6 +260,7 @@ void WaitUntilExternalURLLoad(); void DumpDragImage(); void DumpNavigationPolicy(); + void DumpPageImportanceSignals(); void ShowWebInspector(gin::Arguments* args); void CloseWebInspector(); bool IsChooserShown(); @@ -524,6 +527,8 @@ .SetMethod("dumpDragImage", &TestRunnerBindings::DumpDragImage) .SetMethod("dumpNavigationPolicy", &TestRunnerBindings::DumpNavigationPolicy) + .SetMethod("dumpPageImportanceSignals", + &TestRunnerBindings::DumpPageImportanceSignals) .SetMethod("showWebInspector", &TestRunnerBindings::ShowWebInspector) .SetMethod("closeWebInspector", &TestRunnerBindings::CloseWebInspector) .SetMethod("isChooserShown", &TestRunnerBindings::IsChooserShown) @@ -1270,6 +1275,11 @@ runner_->DumpNavigationPolicy(); } +void TestRunnerBindings::DumpPageImportanceSignals() { + if (runner_) + runner_->DumpPageImportanceSignals(); +} + void TestRunnerBindings::ShowWebInspector(gin::Arguments* args) { if (runner_) { std::string settings; @@ -2789,6 +2799,22 @@ dump_navigation_policy_ = true; } +void TestRunner::DumpPageImportanceSignals() { + blink::WebPageImportanceSignals* signals = + web_view_->pageImportanceSignals(); + if (!signals) + return; + + std::string message = base::StringPrintf( + "WebPageImportanceSignals:\n" + " hadFormInteraction: %s\n" + " issuedNonGetFetchFromScript: %s\n", + signals->hadFormInteraction() ? "true" : "false", + signals->issuedNonGetFetchFromScript() ? "true" : "false"); + if (delegate_) + delegate_->PrintMessage(message); +} + void TestRunner::CloseWebInspector() { delegate_->CloseDevTools(); }
diff --git a/components/test_runner/test_runner.h b/components/test_runner/test_runner.h index 1b03a30..f459954 100644 --- a/components/test_runner/test_runner.h +++ b/components/test_runner/test_runner.h
@@ -478,6 +478,9 @@ // policy passed to the decidePolicyForNavigation callback. void DumpNavigationPolicy(); + // Dump current PageImportanceSignals for the page. + void DumpPageImportanceSignals(); + /////////////////////////////////////////////////////////////////////////// // Methods interacting with the WebTestProxy
diff --git a/components/variations.gypi b/components/variations.gypi index d1fc8c6..4d9ce3f 100644 --- a/components/variations.gypi +++ b/components/variations.gypi
@@ -113,6 +113,7 @@ 'variations/service/variations_service.cc', 'variations/service/variations_service.h', 'variations/service/variations_service_client.h', + 'variations/service/variations_service_client.cc', ], }, {
diff --git a/components/variations/service/BUILD.gn b/components/variations/service/BUILD.gn index c6cf5b11..a1fa0a2 100644 --- a/components/variations/service/BUILD.gn +++ b/components/variations/service/BUILD.gn
@@ -8,6 +8,7 @@ "ui_string_overrider.h", "variations_service.cc", "variations_service.h", + "variations_service_client.cc", "variations_service_client.h", ]
diff --git a/components/variations/service/variations_service.cc b/components/variations/service/variations_service.cc index 8d3ced5c..2c19983 100644 --- a/components/variations/service/variations_service.cc +++ b/components/variations/service/variations_service.cc
@@ -4,6 +4,8 @@ #include "components/variations/service/variations_service.h" +#include <vector> + #include "base/build_time.h" #include "base/command_line.h" #include "base/metrics/histogram.h" @@ -288,6 +290,8 @@ DCHECK(resource_request_allowed_notifier_.get()); resource_request_allowed_notifier_->Init(this); + seed_store_.SetVariationsFirstRunSeedCallback( + client_->GetVariationsFirstRunSeedCallback()); } VariationsService::~VariationsService() {
diff --git a/components/variations/service/variations_service_client.cc b/components/variations/service/variations_service_client.cc new file mode 100644 index 0000000..688bb1f --- /dev/null +++ b/components/variations/service/variations_service_client.cc
@@ -0,0 +1,14 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/variations/service/variations_service_client.h" + +namespace variations { + +VariationsFirstRunSeedCallback +VariationsServiceClient::GetVariationsFirstRunSeedCallback() { + return VariationsFirstRunSeedCallback(); +} + +} // namespace variations
diff --git a/components/variations/service/variations_service_client.h b/components/variations/service/variations_service_client.h index b3758a6..fabaee83 100644 --- a/components/variations/service/variations_service_client.h +++ b/components/variations/service/variations_service_client.h
@@ -10,6 +10,7 @@ #include "base/callback.h" #include "base/strings/string16.h" #include "base/version.h" +#include "components/variations/variations_seed_store.h" #include "components/version_info/version_info.h" namespace base { @@ -59,6 +60,10 @@ // Called from VariationsService::PerformPreMainMessageLoopStartup(). virtual void OnInitialStartup() {} + + // Get callback for pulling variations first run seed from Java applicaton + // in Chrome for Android. + virtual VariationsFirstRunSeedCallback GetVariationsFirstRunSeedCallback(); }; } // namespace variations
diff --git a/components/variations/variations_seed_store.cc b/components/variations/variations_seed_store.cc index 89e1af2..edd3df3 100644 --- a/components/variations/variations_seed_store.cc +++ b/components/variations/variations_seed_store.cc
@@ -152,6 +152,11 @@ bool VariationsSeedStore::LoadSeed(variations::VariationsSeed* seed) { invalid_base64_signature_.clear(); +#if defined(OS_ANDROID) + if (!local_state_->HasPrefPath(prefs::kVariationsSeedSignature)) + ImportFirstRunJavaSeed(); +#endif // OS_ANDROID + std::string seed_data; if (!ReadSeedData(&seed_data)) return false; @@ -336,6 +341,36 @@ local_state_->ClearPref(prefs::kVariationsSeedSignature); } +#if defined(OS_ANDROID) +void VariationsSeedStore::ImportFirstRunJavaSeed() { + DVLOG(1) << "Importing first run seed from Java preferences."; + std::string seed_data; + std::string seed_signature; + std::string seed_country; + if (!get_variations_first_run_seed_.is_null()) { + get_variations_first_run_seed_.Run(&seed_data, &seed_signature, + &seed_country); + } + + if (seed_data.empty()) { + // TODO(agulenko): add a new UMA histogram for the state of failing + // to import seed from Java preferences during Chrome first run. + return; + } + + // TODO(agulenko): Pull actual time from the response. + base::Time current_time = base::Time::Now(); + + // TODO(agulenko): Support gzip compressed seed. + if (!StoreSeedData(seed_data, seed_signature, seed_country, current_time, + false, false, nullptr)) { + LOG(WARNING) << "First run variations seed is invalid."; + return; + } + // TODO(agulenko): Clear Java prefs. +} +#endif // OS_ANDROID + bool VariationsSeedStore::ReadSeedData(std::string* seed_data) { std::string base64_seed_data = local_state_->GetString(prefs::kVariationsCompressedSeed);
diff --git a/components/variations/variations_seed_store.h b/components/variations/variations_seed_store.h index cc743d88..42a6a59 100644 --- a/components/variations/variations_seed_store.h +++ b/components/variations/variations_seed_store.h
@@ -7,6 +7,7 @@ #include <string> +#include "base/callback.h" #include "base/compiler_specific.h" #include "base/gtest_prod_util.h" #include "base/time/time.h" @@ -20,6 +21,9 @@ namespace variations { +typedef base::Callback<void(std::string*, std::string*, std::string*)> + VariationsFirstRunSeedCallback; + // VariationsSeedStore is a helper class for reading and writing the variations // seed from Local State. class VariationsSeedStore { @@ -75,6 +79,13 @@ // Registers Local State prefs used by this class. static void RegisterPrefs(PrefRegistrySimple* registry); + // Registers callback for pulling variations first run seed from Java side + // in Chrome for Android. + void SetVariationsFirstRunSeedCallback( + const VariationsFirstRunSeedCallback& callback) { + get_variations_first_run_seed_ = callback; + } + protected: // Note: UMA histogram enum - don't re-order or remove entries. enum VerifySignatureResult { @@ -103,6 +114,12 @@ // Clears all prefs related to variations seed storage. void ClearPrefs(); +#if defined(OS_ANDROID) + // Imports the variations seed data from Java side during the first + // Chrome for Android run. + void ImportFirstRunJavaSeed(); +#endif // OS_ANDROID + // Reads the variations seed data from prefs; returns true on success. bool ReadSeedData(std::string* seed_data); @@ -134,6 +151,8 @@ // Keeps track of an invalid signature. std::string invalid_base64_signature_; + VariationsFirstRunSeedCallback get_variations_first_run_seed_; + DISALLOW_COPY_AND_ASSIGN(VariationsSeedStore); };
diff --git a/content/browser/bluetooth/bluetooth_dispatcher_host.cc b/content/browser/bluetooth/bluetooth_dispatcher_host.cc index 8c6c7d8..bc13e95 100644 --- a/content/browser/bluetooth/bluetooth_dispatcher_host.cc +++ b/content/browser/bluetooth/bluetooth_dispatcher_host.cc
@@ -944,14 +944,18 @@ VLOG(1) << "\t" << uuid.canonical_value(); content::BluetoothDevice device_ipc( - device->GetAddress(), // id - device->GetName(), // name - device->GetBluetoothClass(), // device_class - device->GetVendorIDSource(), // vendor_id_source - device->GetVendorID(), // vendor_id - device->GetProductID(), // product_id - device->GetDeviceID(), // product_version - device->IsPaired(), // paired + device->GetAddress(), // id + device->GetName(), // name + content::BluetoothDevice::ValidatePower( + device->GetInquiryTxPower()), // tx_power + content::BluetoothDevice::ValidatePower( + device->GetInquiryRSSI()), // rssi + device->GetBluetoothClass(), // device_class + device->GetVendorIDSource(), // vendor_id_source + device->GetVendorID(), // vendor_id + device->GetProductID(), // product_id + device->GetDeviceID(), // product_version + device->IsPaired(), // paired content::BluetoothDevice::UUIDsFromBluetoothUUIDs( device->GetUUIDs())); // uuids RecordRequestDeviceOutcome(UMARequestDeviceOutcome::SUCCESS);
diff --git a/content/common/bluetooth/bluetooth_device.cc b/content/common/bluetooth/bluetooth_device.cc index baf930c..ece3ce4d 100644 --- a/content/common/bluetooth/bluetooth_device.cc +++ b/content/common/bluetooth/bluetooth_device.cc
@@ -11,6 +11,8 @@ BluetoothDevice::BluetoothDevice() : id(""), name(base::string16()), + tx_power(device::BluetoothDevice::kUnknownPower), + rssi(device::BluetoothDevice::kUnknownPower), device_class(0), vendor_id_source( device::BluetoothDevice::VendorIDSource::VENDOR_ID_UNKNOWN), @@ -23,6 +25,8 @@ BluetoothDevice::BluetoothDevice( const std::string& id, const base::string16& name, + int8_t tx_power, + int8_t rssi, uint32 device_class, device::BluetoothDevice::VendorIDSource vendor_id_source, uint16 vendor_id, @@ -32,6 +36,8 @@ const std::vector<std::string>& uuids) : id(id), name(name), + tx_power(tx_power), + rssi(rssi), device_class(device_class), vendor_id_source(vendor_id_source), vendor_id(vendor_id), @@ -53,4 +59,10 @@ return uuids; } +// static +int8_t BluetoothDevice::ValidatePower(int16_t power) { + return ((power < -127) || (power > 127)) ? BluetoothDevice::kUnknownPower + : power; +} + } // namespace content
diff --git a/content/common/bluetooth/bluetooth_device.h b/content/common/bluetooth/bluetooth_device.h index 73aef99..575f43a 100644 --- a/content/common/bluetooth/bluetooth_device.h +++ b/content/common/bluetooth/bluetooth_device.h
@@ -20,6 +20,8 @@ BluetoothDevice(); BluetoothDevice(const std::string& id, const base::string16& name, + int8_t tx_power, + int8_t rssi, uint32 device_class, device::BluetoothDevice::VendorIDSource vendor_id_source, uint16 vendor_id, @@ -31,9 +33,18 @@ static std::vector<std::string> UUIDsFromBluetoothUUIDs( const device::BluetoothDevice::UUIDList& uuid_list); + // 127 is used as Unknown Power. According to the Bluetooth spec valid powers + // are between [-127, 127]. Anything outside this range will be considered + // Unknown Power. + static int8_t ValidatePower(int16_t power); + // TODO(ortuno): RSSI Unknown and Tx Power Unknown should have different + // values. Add kUnknownTxPower when implemented: http://crbug.com/551572 + const static int8_t kUnknownPower = 127; std::string id; base::string16 name; + int8_t tx_power; + int8_t rssi; uint32 device_class; device::BluetoothDevice::VendorIDSource vendor_id_source; uint16 vendor_id;
diff --git a/content/common/bluetooth/bluetooth_messages.h b/content/common/bluetooth/bluetooth_messages.h index 85100ff..b7518c1 100644 --- a/content/common/bluetooth/bluetooth_messages.h +++ b/content/common/bluetooth/bluetooth_messages.h
@@ -92,6 +92,8 @@ IPC_STRUCT_TRAITS_BEGIN(content::BluetoothDevice) IPC_STRUCT_TRAITS_MEMBER(id) IPC_STRUCT_TRAITS_MEMBER(name) + IPC_STRUCT_TRAITS_MEMBER(tx_power) + IPC_STRUCT_TRAITS_MEMBER(rssi) IPC_STRUCT_TRAITS_MEMBER(device_class) IPC_STRUCT_TRAITS_MEMBER(vendor_id_source) IPC_STRUCT_TRAITS_MEMBER(vendor_id)
diff --git a/content/renderer/bluetooth/bluetooth_dispatcher.cc b/content/renderer/bluetooth/bluetooth_dispatcher.cc index a5097d8..5687bf7 100644 --- a/content/renderer/bluetooth/bluetooth_dispatcher.cc +++ b/content/renderer/bluetooth/bluetooth_dispatcher.cc
@@ -551,9 +551,9 @@ pending_requests_.Lookup(request_id) ->onSuccess(blink::adoptWebPtr(new WebBluetoothDevice( WebString::fromUTF8(device.id), WebString(device.name), - device.device_class, GetWebVendorIdSource(device.vendor_id_source), - device.vendor_id, device.product_id, device.product_version, - device.paired, uuids))); + device.tx_power, device.rssi, device.device_class, + GetWebVendorIdSource(device.vendor_id_source), device.vendor_id, + device.product_id, device.product_version, device.paired, uuids))); pending_requests_.Remove(request_id); }
diff --git a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc index 054fb95..fc35b28 100644 --- a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc +++ b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc
@@ -8,6 +8,9 @@ #include "base/bind_helpers.h" #include "base/format_macros.h" #include "base/location.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_split.h" +#include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/thread_task_runner_handle.h" #include "device/bluetooth/bluetooth_adapter.h" @@ -20,6 +23,7 @@ #include "device/bluetooth/test/mock_bluetooth_gatt_notify_session.h" #include "testing/gmock/include/gmock/gmock.h" +using base::StringPiece; using device::BluetoothAdapter; using device::BluetoothDevice; using device::BluetoothGattCharacteristic; @@ -62,6 +66,10 @@ const char kBodySensorLocation[] = "2a38"; const char kDeviceNameUUID[] = "2a00"; +const int kDefaultTxPower = -10; // TxPower of a device broadcasting at 0.1mW. +const int kDefaultRssi = -51; // RSSI at 1m from a device broadcasting at + // 0.1mW. + // Invokes Run() on the k-th argument of the function with no arguments. ACTION_TEMPLATE(RunCallback, HAS_1_TEMPLATE_PARAMS(int, k), @@ -143,6 +151,40 @@ else if (fake_adapter_name == "") return NULL; + if (base::StartsWith(fake_adapter_name, "PowerValueAdapter", + base::CompareCase::SENSITIVE)) { + std::vector<StringPiece> args = + base::SplitStringPiece(fake_adapter_name, ":", base::KEEP_WHITESPACE, + base::SPLIT_WANT_NONEMPTY); + DCHECK(args[0] == "PowerValueAdapter"); + DCHECK(args.size() == 3) << "Should contain AdapterName:TxPower:RSSI"; + + int tx_power; + base::StringToInt(args[1], &tx_power); + DCHECK(tx_power >= INT8_MIN && tx_power <= INT8_MAX) + << "Must be between [-128, 127]"; + int rssi; + base::StringToInt(args[2], &rssi); + DCHECK(rssi >= INT8_MIN && rssi <= INT8_MAX) + << "Must be between [-128, 127]"; + return GetPowerValueAdapter(tx_power, rssi); + } + + if (base::StartsWith(fake_adapter_name, "PowerPresenceAdapter", + base::CompareCase::SENSITIVE)) { + std::vector<StringPiece> args = + base::SplitStringPiece(fake_adapter_name, ":", base::KEEP_WHITESPACE, + base::SPLIT_WANT_NONEMPTY); + DCHECK(args[0] == "PowerPresenceAdapter"); + DCHECK(args.size() == 3) + << "Should contain AdapterName:TxPowerPresent:RSSIPResent"; + DCHECK(args[1] == "true" || args[1] == "false"); + DCHECK(args[2] == "true" || args[2] == "false"); + + return GetPowerPresenceAdapter(args[1] == "true" /* tx_power_present */, + args[2] == "true" /* rssi_present */); + } + NOTREACHED() << fake_adapter_name; return NULL; } @@ -257,6 +299,35 @@ // static scoped_refptr<NiceMockBluetoothAdapter> +LayoutTestBluetoothAdapterProvider::GetPowerValueAdapter(int8_t tx_power, + int8_t rssi) { + scoped_refptr<NiceMockBluetoothAdapter> adapter(GetEmptyAdapter()); + scoped_ptr<NiceMockBluetoothDevice> device(GetHeartRateDevice(adapter.get())); + + ON_CALL(*device, GetInquiryTxPower()).WillByDefault(Return(tx_power)); + ON_CALL(*device, GetInquiryRSSI()).WillByDefault(Return(rssi)); + + adapter->AddMockDevice(device.Pass()); + + return adapter; +} + +// static +scoped_refptr<NiceMockBluetoothAdapter> +LayoutTestBluetoothAdapterProvider::GetPowerPresenceAdapter( + bool tx_power_present, + bool rssi_present) { + // TODO(ortuno): RSSI Unknown and Tx Power Unknown should have different + // values. Add kUnknownTxPower when implemented: http://crbug.com/551572 + int tx_power = + tx_power_present ? kDefaultTxPower : BluetoothDevice::kUnknownPower; + int rssi = rssi_present ? kDefaultRssi : BluetoothDevice::kUnknownPower; + + return GetPowerValueAdapter(tx_power, rssi); +} + +// static +scoped_refptr<NiceMockBluetoothAdapter> LayoutTestBluetoothAdapterProvider::GetGlucoseHeartRateAdapter() { scoped_refptr<NiceMockBluetoothAdapter> adapter(GetEmptyAdapter());
diff --git a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.h b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.h index ca23237..39431b26 100644 --- a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.h +++ b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.h
@@ -114,6 +114,32 @@ static scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>> GetEmptyAdapter(); + // |PowerValueAdapter|(tx_power, rssi) + // Inherits from |EmptyAdapter| + // Internal Structure: + // - |HeartRateDevice| + // - Mock Functions: + // - GetInquiryTxPower(): Returns tx_power + // - GetInquiryRSSI(): Returns rssi + static scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>> + GetPowerValueAdapter(int8_t tx_power, int8_t rssi); + + // |PowerPresenceAdapter|(tx_power_present, rssi_present) + // Inherits from |EmptyAdapter| + // Internal Structure: + // - |HeartRateDevice| + // - Mock Functions: + // - GetInquiryTxPower(): If tx_power_present is true, returns -10, + // the TxPower of a device broadcasting at 0.1mW. Otherwise + // returns 127 which denotes a missing Tx Power. + // TODO(ortuno): Change 127 to -128 when Tx Power Unknown value gets + // fixed: http://crbug.com/551572 + // - GetInquiryRSSI(): If rssi_present is true returns -51, + // the RSSI at 1m from a device broadcasting at 0.1mW. Otherwise + // returns 127 which denotes a missing RSSI. + static scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>> + GetPowerPresenceAdapter(bool tx_power_present, bool rssi_present); + // |GlucoseHeartRateAdapter| // Inherits from |EmptyAdapter| // Devices added:
diff --git a/ios/chrome/browser/chrome_switches.cc b/ios/chrome/browser/chrome_switches.cc index 4af3f01..ae18f94 100644 --- a/ios/chrome/browser/chrome_switches.cc +++ b/ios/chrome/browser/chrome_switches.cc
@@ -12,17 +12,68 @@ // all work out. // ----------------------------------------------------------------------------- +// Disables Contextual Search. +const char kDisableContextualSearch[] = "disable-contextual-search"; + +// Disables a workaround for fast inset updates for UIWebView.scrollView. +const char kDisableIOSFastWebScrollViewInsets[] = + "disable-fast-web-scroll-view-insets"; + +// Disable password generation for iOS. +const char kDisableIOSPasswordGeneration[] = "disable-ios-password-generation"; + +// Disable showing available password credentials in the keyboard accessory +// view when focused on form fields. +const char kDisableIOSPasswordSuggestions[] = + "disable-ios-password-suggestions"; + // Disables the use of WKWebView instead of UIWebView. const char kDisableIOSWKWebView[] = "disable-wkwebview"; +// Disables support for keyboard commands. +const char kDisableKeyboardCommands[] = "disable-keyboard-commands"; + +// Disables NTP favicons. +const char kDisableNTPFavicons[] = "disable-ntp-favicons"; + +// Disable auto-reload of error pages if offline. +const char kDisableOfflineAutoReload[] = "disable-offline-auto-reload"; + +// Disables the tab switcher. +const char kDisableTabSwitcher[] = "disable-tab-switcher"; + +// Enables Contextual Search. +const char kEnableContextualSearch[] = "enable-contextual-search"; + +// Enable the experimental Credential Manager JavaScript API. +const char kEnableCredentialManagerAPI[] = "enable-credential-manager-api"; + +// Enables a workaround for fast inset updates for UIWebView.scrollView. +const char kEnableIOSFastWebScrollViewInsets[] = + "enable-fast-web-scroll-view-insets"; + +// Enables support for Handoff from Chrome on iOS to the default browser of +// other Apple devices. +const char kEnableIOSHandoffToOtherDevices[] = + "enable-ios-handoff-to-other-devices"; + +// Enable password generation for iOS. +const char kEnableIOSPasswordGeneration[] = "enable-ios-password-generation"; + // Enables the use of WKWebView instead of UIWebView. const char kEnableIOSWKWebView[] = "enable-wkwebview"; +// Enables NTP favicons. +const char kEnableNTPFavicons[] = "enable-ntp-favicons"; + +// Enable auto-reload of error pages if offline. +const char kEnableOfflineAutoReload[] = "enable-offline-auto-reload"; + // Enables context-sensitive reader mode button in the toolbar. const char kEnableReaderModeToolbarIcon[] = "enable-reader-mode-toolbar-icon"; -// Disables support for keyboard commands. -const char kDisableKeyboardCommands[] = "disable-keyboard-commands"; +// Enables the tab switcher. +const char kEnableTabSwitcher[] = "enable-tab-switcher"; // Enables the recording of metrics reports but disables reporting. In contrast // to kDisableMetrics, this executes all the code that a normal client would @@ -31,4 +82,7 @@ // performance tests. const char kIOSMetricsRecordingOnly[] = "metrics-recording-only"; +// A string used to override the default user agent with a custom one. +const char kUserAgent[] = "user-agent"; + } // namespace switches
diff --git a/ios/chrome/browser/chrome_switches.h b/ios/chrome/browser/chrome_switches.h index e6df544c..f1c590ef 100644 --- a/ios/chrome/browser/chrome_switches.h +++ b/ios/chrome/browser/chrome_switches.h
@@ -9,11 +9,29 @@ namespace switches { +extern const char kDisableContextualSearch[]; +extern const char kDisableIOSFastWebScrollViewInsets[]; +extern const char kDisableIOSPasswordGeneration[]; +extern const char kDisableIOSPasswordSuggestions[]; extern const char kDisableIOSWKWebView[]; -extern const char kEnableIOSWKWebView[]; -extern const char kEnableReaderModeToolbarIcon[]; extern const char kDisableKeyboardCommands[]; +extern const char kDisableNTPFavicons[]; +extern const char kDisableOfflineAutoReload[]; +extern const char kDisableTabSwitcher[]; + +extern const char kEnableContextualSearch[]; +extern const char kEnableCredentialManagerAPI[]; +extern const char kEnableIOSFastWebScrollViewInsets[]; +extern const char kEnableIOSHandoffToOtherDevices[]; +extern const char kEnableIOSPasswordGeneration[]; +extern const char kEnableIOSWKWebView[]; +extern const char kEnableNTPFavicons[]; +extern const char kEnableOfflineAutoReload[]; +extern const char kEnableReaderModeToolbarIcon[]; +extern const char kEnableTabSwitcher[]; + extern const char kIOSMetricsRecordingOnly[]; +extern const char kUserAgent[]; } // namespace switches
diff --git a/ipc/ipc_message_start.h b/ipc/ipc_message_start.h index 9edcfa5e..8acdd7c1 100644 --- a/ipc/ipc_message_start.h +++ b/ipc/ipc_message_start.h
@@ -129,6 +129,8 @@ PageLoadMetricsMsgStart, MemoryMsgStart, IPCTestMsgStart, + ArcInstanceMsgStart, + ArcInstanceHostMsgStart, LastIPCMsgStart // Must come last. };
diff --git a/mandoline/ui/common/BUILD.gn b/mandoline/ui/common/BUILD.gn deleted file mode 100644 index a695e43..0000000 --- a/mandoline/ui/common/BUILD.gn +++ /dev/null
@@ -1,17 +0,0 @@ -# Copyright 2014 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -source_set("common") { - sources = [ - "util.cc", - "util.h", - ] - - deps = [ - "//components/mus/public/cpp", - "//mojo/converters/geometry", - "//ui/gfx", - "//ui/gfx/geometry", - ] -}
diff --git a/mandoline/ui/desktop_ui/BUILD.gn b/mandoline/ui/desktop_ui/BUILD.gn index 916683a..255419a 100644 --- a/mandoline/ui/desktop_ui/BUILD.gn +++ b/mandoline/ui/desktop_ui/BUILD.gn
@@ -39,7 +39,6 @@ "//base", "//components/web_view/public/cpp", "//components/web_view/public/interfaces", - "//mandoline/ui/common", "//mojo/application/public/cpp:sources", "//mojo/common:common_base", "//mojo/converters/geometry",
diff --git a/mandoline/ui/desktop_ui/browser_window.cc b/mandoline/ui/desktop_ui/browser_window.cc index 59d82ef2..4b4e698 100644 --- a/mandoline/ui/desktop_ui/browser_window.cc +++ b/mandoline/ui/desktop_ui/browser_window.cc
@@ -12,7 +12,6 @@ #include "components/mus/public/cpp/event_matcher.h" #include "components/mus/public/cpp/scoped_window_ptr.h" #include "components/mus/public/cpp/window_tree_host_factory.h" -#include "mandoline/ui/common/util.h" #include "mandoline/ui/desktop_ui/browser_commands.h" #include "mandoline/ui/desktop_ui/browser_manager.h" #include "mandoline/ui/desktop_ui/find_bar_view.h" @@ -27,6 +26,7 @@ #include "ui/views/background.h" #include "ui/views/controls/button/label_button.h" #include "ui/views/mus/aura_init.h" +#include "ui/views/mus/display_converter.h" #include "ui/views/mus/native_widget_view_manager.h" #include "ui/views/widget/widget_delegate.h" @@ -392,7 +392,7 @@ void BrowserWindow::Init(mus::Window* root) { DCHECK_GT(root->viewport_metrics().device_pixel_ratio, 0); if (!aura_init_) { - ui_init_.reset(new ui::mojo::UIInit(GetDisplaysFromWindow(root))); + ui_init_.reset(new ui::mojo::UIInit(views::GetDisplaysFromWindow(root))); aura_init_.reset(new views::AuraInit(app_, "mandoline_ui.pak")); }
diff --git a/mandoline/ui/omnibox/BUILD.gn b/mandoline/ui/omnibox/BUILD.gn index 9e95dbd..76530b9 100644 --- a/mandoline/ui/omnibox/BUILD.gn +++ b/mandoline/ui/omnibox/BUILD.gn
@@ -28,7 +28,6 @@ "//base", "//components/mus/public/cpp", "//components/url_formatter", - "//mandoline/ui/common", "//mandoline/ui/desktop_ui/public/interfaces", "//mojo/application/public/cpp:sources", "//mojo/common",
diff --git a/mandoline/ui/omnibox/omnibox_application.cc b/mandoline/ui/omnibox/omnibox_application.cc index 7dffe081..3a17170 100644 --- a/mandoline/ui/omnibox/omnibox_application.cc +++ b/mandoline/ui/omnibox/omnibox_application.cc
@@ -10,7 +10,6 @@ #include "components/mus/public/cpp/window_tree_connection.h" #include "components/mus/public/cpp/window_tree_delegate.h" #include "components/url_formatter/url_fixer.h" -#include "mandoline/ui/common/util.h" #include "mandoline/ui/desktop_ui/public/interfaces/view_embedder.mojom.h" #include "mojo/application/public/cpp/application_impl.h" #include "mojo/common/common_type_converters.h" @@ -20,6 +19,7 @@ #include "ui/views/controls/textfield/textfield_controller.h" #include "ui/views/layout/layout_manager.h" #include "ui/views/mus/aura_init.h" +#include "ui/views/mus/display_converter.h" #include "ui/views/mus/native_widget_view_manager.h" #include "ui/views/widget/widget_delegate.h" @@ -119,7 +119,7 @@ root_ = root; if (!aura_init_.get()) { - ui_init_.reset(new ui::mojo::UIInit(GetDisplaysFromWindow(root_))); + ui_init_.reset(new ui::mojo::UIInit(views::GetDisplaysFromWindow(root_))); aura_init_.reset(new views::AuraInit(app_, "mandoline_ui.pak")); edit_ = new views::Textfield; edit_->set_controller(this);
diff --git a/media/BUILD.gn b/media/BUILD.gn index f15e5903..514d40f 100644 --- a/media/BUILD.gn +++ b/media/BUILD.gn
@@ -165,6 +165,10 @@ "capture/video/win/video_capture_device_win.h", "cdm/aes_decryptor.cc", "cdm/aes_decryptor.h", + "cdm/cdm_adapter.cc", + "cdm/cdm_adapter.h", + "cdm/cdm_adapter_impl.cc", + "cdm/cdm_adapter_impl.h", "cdm/default_cdm_factory.cc", "cdm/default_cdm_factory.h", "cdm/json_web_key.cc", @@ -175,6 +179,8 @@ "cdm/player_tracker_impl.h", "cdm/proxy_decryptor.cc", "cdm/proxy_decryptor.h", + "cdm/supported_cdm_versions.cc", + "cdm/supported_cdm_versions.h", "ffmpeg/ffmpeg_deleters.h", "filters/audio_clock.cc", "filters/audio_clock.h",
diff --git a/media/cdm/cdm_adapter.cc b/media/cdm/cdm_adapter.cc new file mode 100644 index 0000000..94791cf0 --- /dev/null +++ b/media/cdm/cdm_adapter.cc
@@ -0,0 +1,93 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/cdm/cdm_adapter.h" + +#include "base/logging.h" +#include "media/cdm/cdm_adapter_impl.h" + +namespace media { + +CdmAdapter::CdmAdapter() {} + +CdmAdapter::~CdmAdapter() {} + +void CdmAdapter::Initialize( + const std::string& key_system, + const base::FilePath& cdm_path, + const CdmConfig& cdm_config, + const SessionMessageCB& session_message_cb, + const SessionClosedCB& session_closed_cb, + const LegacySessionErrorCB& legacy_session_error_cb, + const SessionKeysChangeCB& session_keys_change_cb, + const SessionExpirationUpdateCB& session_expiration_update_cb, + scoped_ptr<SimpleCdmPromise> promise) { + DCHECK(!key_system.empty()); + DCHECK(!session_message_cb.is_null()); + DCHECK(!session_closed_cb.is_null()); + DCHECK(!legacy_session_error_cb.is_null()); + DCHECK(!session_keys_change_cb.is_null()); + DCHECK(!session_expiration_update_cb.is_null()); + + scoped_refptr<CdmAdapterImpl> cdm = new CdmAdapterImpl(); + cdm->Initialize(key_system, cdm_path, cdm_config, session_message_cb, + session_closed_cb, legacy_session_error_cb, + session_keys_change_cb, session_expiration_update_cb, + promise.Pass()); + cdm_ = cdm.Pass(); +} + +void CdmAdapter::SetServerCertificate(const std::vector<uint8_t>& certificate, + scoped_ptr<SimpleCdmPromise> promise) { + DCHECK(cdm_); + cdm_->SetServerCertificate(certificate, promise.Pass()); +} + +void CdmAdapter::CreateSessionAndGenerateRequest( + SessionType session_type, + EmeInitDataType init_data_type, + const std::vector<uint8_t>& init_data, + scoped_ptr<NewSessionCdmPromise> promise) { + DCHECK(cdm_); + return cdm_->CreateSessionAndGenerateRequest(session_type, init_data_type, + init_data, promise.Pass()); +} + +void CdmAdapter::LoadSession(SessionType session_type, + const std::string& session_id, + scoped_ptr<NewSessionCdmPromise> promise) { + DCHECK(cdm_); + DCHECK(!session_id.empty()); + return cdm_->LoadSession(session_type, session_id, promise.Pass()); +} + +void CdmAdapter::UpdateSession(const std::string& session_id, + const std::vector<uint8_t>& response, + scoped_ptr<SimpleCdmPromise> promise) { + DCHECK(cdm_); + DCHECK(!session_id.empty()); + DCHECK(!response.empty()); + return cdm_->UpdateSession(session_id, response, promise.Pass()); +} + +void CdmAdapter::CloseSession(const std::string& session_id, + scoped_ptr<SimpleCdmPromise> promise) { + DCHECK(cdm_); + DCHECK(!session_id.empty()); + return cdm_->CloseSession(session_id, promise.Pass()); +} + +void CdmAdapter::RemoveSession(const std::string& session_id, + scoped_ptr<SimpleCdmPromise> promise) { + DCHECK(cdm_); + DCHECK(!session_id.empty()); + return cdm_->RemoveSession(session_id, promise.Pass()); +} + +CdmContext* CdmAdapter::GetCdmContext() { + DCHECK(cdm_); + return cdm_->GetCdmContext(); +} + +} // namespace media
diff --git a/media/cdm/cdm_adapter.h b/media/cdm/cdm_adapter.h new file mode 100644 index 0000000..b304fb3 --- /dev/null +++ b/media/cdm/cdm_adapter.h
@@ -0,0 +1,69 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_CDM_CDM_ADAPTER_H_ +#define MEDIA_CDM_CDM_ADAPTER_H_ + +#include <string> +#include <vector> + +#include "base/files/file_path.h" +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "media/base/cdm_config.h" +#include "media/base/media_export.h" +#include "media/base/media_keys.h" + +namespace media { + +// Due to windows warning C4275 (should not export a class that inherits from +// a non-exported class), this class exists as a wrapper for CdmAdapterImpl. +class MEDIA_EXPORT CdmAdapter : public MediaKeys { + public: + CdmAdapter(); + + // Load the CDM using |cdm_path| and initialize it using |key_system| and + // |cdm_config|. Callbacks will be used for events generated by the CDM. + // |promise| is resolved if the CDM is loaded and initialized correctly, + // otherwise it is rejected. + void Initialize(const std::string& key_system, + const base::FilePath& cdm_path, + const CdmConfig& cdm_config, + const SessionMessageCB& session_message_cb, + const SessionClosedCB& session_closed_cb, + const LegacySessionErrorCB& legacy_session_error_cb, + const SessionKeysChangeCB& session_keys_change_cb, + const SessionExpirationUpdateCB& session_expiration_update_cb, + scoped_ptr<SimpleCdmPromise> promise); + + // MediaKeys implementation. + void SetServerCertificate(const std::vector<uint8_t>& certificate, + scoped_ptr<SimpleCdmPromise> promise) override; + void CreateSessionAndGenerateRequest( + SessionType session_type, + EmeInitDataType init_data_type, + const std::vector<uint8_t>& init_data, + scoped_ptr<NewSessionCdmPromise> promise) override; + void LoadSession(SessionType session_type, + const std::string& session_id, + scoped_ptr<NewSessionCdmPromise> promise) override; + void UpdateSession(const std::string& session_id, + const std::vector<uint8_t>& response, + scoped_ptr<SimpleCdmPromise> promise) override; + void CloseSession(const std::string& session_id, + scoped_ptr<SimpleCdmPromise> promise) override; + void RemoveSession(const std::string& session_id, + scoped_ptr<SimpleCdmPromise> promise) override; + CdmContext* GetCdmContext() override; + + private: + ~CdmAdapter() final; + + scoped_refptr<MediaKeys> cdm_; + DISALLOW_COPY_AND_ASSIGN(CdmAdapter); +}; + +} // namespace media + +#endif // MEDIA_CDM_CDM_ADAPTER_H_
diff --git a/media/cdm/cdm_adapter_impl.cc b/media/cdm/cdm_adapter_impl.cc new file mode 100644 index 0000000..aabd1fa8 --- /dev/null +++ b/media/cdm/cdm_adapter_impl.cc
@@ -0,0 +1,479 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/cdm/cdm_adapter_impl.h" + +#include "base/bind.h" +#include "base/logging.h" +#include "base/message_loop/message_loop.h" +#include "base/stl_util.h" +#include "base/thread_task_runner_handle.h" +#include "base/time/time.h" +#include "media/base/cdm_context.h" +#include "media/base/cdm_key_information.h" +#include "media/base/limits.h" +#include "media/cdm/cdm_wrapper.h" + +namespace media { + +namespace { + +cdm::SessionType MediaSessionTypeToCdmSessionType( + MediaKeys::SessionType session_type) { + switch (session_type) { + case MediaKeys::TEMPORARY_SESSION: + return cdm::kTemporary; + case MediaKeys::PERSISTENT_LICENSE_SESSION: + return cdm::kPersistentLicense; + case MediaKeys::PERSISTENT_RELEASE_MESSAGE_SESSION: + return cdm::kPersistentKeyRelease; + } + + NOTREACHED(); + return cdm::kTemporary; +} + +cdm::InitDataType MediaInitDataTypeToCdmInitDataType( + EmeInitDataType init_data_type) { + switch (init_data_type) { + case EmeInitDataType::CENC: + return cdm::kCenc; + case EmeInitDataType::KEYIDS: + return cdm::kKeyIds; + case EmeInitDataType::WEBM: + return cdm::kWebM; + case EmeInitDataType::UNKNOWN: + break; + } + + NOTREACHED(); + return cdm::kKeyIds; +} + +MediaKeys::Exception CdmErrorTypeToMediaExceptionType(cdm::Error error) { + switch (error) { + case cdm::kNotSupportedError: + return MediaKeys::NOT_SUPPORTED_ERROR; + case cdm::kInvalidStateError: + return MediaKeys::INVALID_STATE_ERROR; + case cdm::kInvalidAccessError: + return MediaKeys::INVALID_ACCESS_ERROR; + case cdm::kQuotaExceededError: + return MediaKeys::QUOTA_EXCEEDED_ERROR; + case cdm::kUnknownError: + return MediaKeys::UNKNOWN_ERROR; + case cdm::kClientError: + return MediaKeys::CLIENT_ERROR; + case cdm::kOutputError: + return MediaKeys::OUTPUT_ERROR; + } + + NOTREACHED(); + return MediaKeys::UNKNOWN_ERROR; +} + +MediaKeys::MessageType CdmMessageTypeToMediaMessageType( + cdm::MessageType message_type) { + switch (message_type) { + case cdm::kLicenseRequest: + return MediaKeys::LICENSE_REQUEST; + case cdm::kLicenseRenewal: + return MediaKeys::LICENSE_RENEWAL; + case cdm::kLicenseRelease: + return MediaKeys::LICENSE_RELEASE; + } + + NOTREACHED(); + return MediaKeys::LICENSE_REQUEST; +} + +CdmKeyInformation::KeyStatus CdmKeyStatusToCdmKeyInformationKeyStatus( + cdm::KeyStatus status) { + switch (status) { + case cdm::kUsable: + return CdmKeyInformation::USABLE; + case cdm::kInternalError: + return CdmKeyInformation::INTERNAL_ERROR; + case cdm::kExpired: + return CdmKeyInformation::EXPIRED; + case cdm::kOutputRestricted: + return CdmKeyInformation::OUTPUT_RESTRICTED; + case cdm::kOutputDownscaled: + return CdmKeyInformation::OUTPUT_DOWNSCALED; + case cdm::kStatusPending: + return CdmKeyInformation::KEY_STATUS_PENDING; + case cdm::kReleased: + return CdmKeyInformation::RELEASED; + } + + NOTREACHED(); + return CdmKeyInformation::INTERNAL_ERROR; +} + +static void* GetCdmHost(int host_interface_version, void* user_data) { + if (!host_interface_version || !user_data) + return nullptr; + + static_assert( + cdm::ContentDecryptionModule::Host::kVersion == cdm::Host_8::kVersion, + "update the code below"); + + // Ensure IsSupportedCdmHostVersion matches implementation of this function. + // Always update this DCHECK when updating this function. + // If this check fails, update this function and DCHECK or update + // IsSupportedCdmHostVersion. + + DCHECK( + // Future version is not supported. + !IsSupportedCdmHostVersion(cdm::Host_8::kVersion + 1) && + // Current version is supported. + IsSupportedCdmHostVersion(cdm::Host_8::kVersion) && + // Include all previous supported versions (if any) here. + IsSupportedCdmHostVersion(cdm::Host_7::kVersion) && + // One older than the oldest supported version is not supported. + !IsSupportedCdmHostVersion(cdm::Host_7::kVersion - 1)); + DCHECK(IsSupportedCdmHostVersion(host_interface_version)); + + CdmAdapterImpl* cdm_adapter = static_cast<CdmAdapterImpl*>(user_data); + DVLOG(1) << "Create CDM Host with version " << host_interface_version; + switch (host_interface_version) { + case cdm::Host_8::kVersion: + return static_cast<cdm::Host_8*>(cdm_adapter); + case cdm::Host_7::kVersion: + return static_cast<cdm::Host_7*>(cdm_adapter); + default: + NOTREACHED(); + return nullptr; + } +} + +} // namespace + +CdmAdapterImpl::CdmAdapterImpl() + : task_runner_(base::ThreadTaskRunnerHandle::Get()), weak_factory_(this) {} + +CdmAdapterImpl::~CdmAdapterImpl() {} + +CdmWrapper* CdmAdapterImpl::CreateCdmInstance(const std::string& key_system, + const base::FilePath& cdm_path) { + DCHECK(task_runner_->BelongsToCurrentThread()); + + // TODO(jrummell): We need to call INITIALIZE_CDM_MODULE() and + // DeinitializeCdmModule(). However, that should only be done once for the + // library. + base::NativeLibraryLoadError error; + library_.Reset(base::LoadNativeLibrary(cdm_path, &error)); + if (!library_.is_valid()) { + DVLOG(1) << "CDM instance for " + key_system + " could not be created. " + << error.ToString(); + return nullptr; + } + + CreateCdmFunc create_cdm_func = reinterpret_cast<CreateCdmFunc>( + library_.GetFunctionPointer("CreateCdmInstance")); + if (!create_cdm_func) { + DVLOG(1) << "No CreateCdmInstance() in library for " + key_system; + return nullptr; + } + + CdmWrapper* cdm = CdmWrapper::Create(create_cdm_func, key_system.data(), + key_system.size(), GetCdmHost, this); + + DVLOG(1) << "CDM instance for " + key_system + (cdm ? "" : " could not be") + + " created."; + return cdm; +} + +void CdmAdapterImpl::Initialize( + const std::string& key_system, + const base::FilePath& cdm_path, + const CdmConfig& cdm_config, + const SessionMessageCB& session_message_cb, + const SessionClosedCB& session_closed_cb, + const LegacySessionErrorCB& legacy_session_error_cb, + const SessionKeysChangeCB& session_keys_change_cb, + const SessionExpirationUpdateCB& session_expiration_update_cb, + scoped_ptr<SimpleCdmPromise> promise) { + DCHECK(task_runner_->BelongsToCurrentThread()); + DCHECK(!key_system.empty()); + DCHECK(key_system_.empty()); + DCHECK(!session_message_cb.is_null()); + DCHECK(!session_closed_cb.is_null()); + DCHECK(!legacy_session_error_cb.is_null()); + DCHECK(!session_keys_change_cb.is_null()); + DCHECK(!session_expiration_update_cb.is_null()); + + session_message_cb_ = session_message_cb; + session_closed_cb_ = session_closed_cb; + legacy_session_error_cb_ = legacy_session_error_cb; + session_keys_change_cb_ = session_keys_change_cb; + session_expiration_update_cb_ = session_expiration_update_cb; + + cdm_.reset(CreateCdmInstance(key_system, cdm_path)); + if (!cdm_) { + promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, + "Unable to create CDM."); + return; + } + + key_system_ = key_system; + cdm_config_ = cdm_config; + cdm_->Initialize(cdm_config_.allow_distinctive_identifier, + cdm_config_.allow_persistent_state); + promise->resolve(); +} + +void CdmAdapterImpl::SetServerCertificate( + const std::vector<uint8_t>& certificate, + scoped_ptr<SimpleCdmPromise> promise) { + DCHECK(task_runner_->BelongsToCurrentThread()); + + if (certificate.size() < limits::kMinCertificateLength || + certificate.size() > limits::kMaxCertificateLength) { + promise->reject(MediaKeys::INVALID_ACCESS_ERROR, 0, + "Incorrect certificate."); + return; + } + + uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass()); + cdm_->SetServerCertificate(promise_id, vector_as_array(&certificate), + certificate.size()); +} + +void CdmAdapterImpl::CreateSessionAndGenerateRequest( + SessionType session_type, + EmeInitDataType init_data_type, + const std::vector<uint8_t>& init_data, + scoped_ptr<NewSessionCdmPromise> promise) { + DCHECK(task_runner_->BelongsToCurrentThread()); + + uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass()); + cdm_->CreateSessionAndGenerateRequest( + promise_id, MediaSessionTypeToCdmSessionType(session_type), + MediaInitDataTypeToCdmInitDataType(init_data_type), + vector_as_array(&init_data), init_data.size()); +} + +void CdmAdapterImpl::LoadSession(SessionType session_type, + const std::string& session_id, + scoped_ptr<NewSessionCdmPromise> promise) { + DCHECK(task_runner_->BelongsToCurrentThread()); + + uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass()); + cdm_->LoadSession(promise_id, MediaSessionTypeToCdmSessionType(session_type), + session_id.data(), session_id.size()); +} + +void CdmAdapterImpl::UpdateSession(const std::string& session_id, + const std::vector<uint8_t>& response, + scoped_ptr<SimpleCdmPromise> promise) { + DCHECK(task_runner_->BelongsToCurrentThread()); + DCHECK(!session_id.empty()); + DCHECK(!response.empty()); + + uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass()); + cdm_->UpdateSession(promise_id, session_id.data(), session_id.size(), + vector_as_array(&response), response.size()); +} + +void CdmAdapterImpl::CloseSession(const std::string& session_id, + scoped_ptr<SimpleCdmPromise> promise) { + DCHECK(task_runner_->BelongsToCurrentThread()); + DCHECK(!session_id.empty()); + + uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass()); + cdm_->CloseSession(promise_id, session_id.data(), session_id.size()); +} + +void CdmAdapterImpl::RemoveSession(const std::string& session_id, + scoped_ptr<SimpleCdmPromise> promise) { + DCHECK(task_runner_->BelongsToCurrentThread()); + DCHECK(!session_id.empty()); + + uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass()); + cdm_->RemoveSession(promise_id, session_id.data(), session_id.size()); +} + +CdmContext* CdmAdapterImpl::GetCdmContext() { + DCHECK(task_runner_->BelongsToCurrentThread()); + + // TODO(jrummell): Support the Decryptor interface. + NOTIMPLEMENTED(); + return nullptr; +} + +cdm::Buffer* CdmAdapterImpl::Allocate(uint32_t capacity) { + DCHECK(task_runner_->BelongsToCurrentThread()); + + // TODO(jrummell): Figure out how memory should be passed around when + // decrypting. + NOTIMPLEMENTED(); + return nullptr; +} + +void CdmAdapterImpl::SetTimer(int64_t delay_ms, void* context) { + DCHECK(task_runner_->BelongsToCurrentThread()); + task_runner_->PostDelayedTask(FROM_HERE, + base::Bind(&CdmAdapterImpl::TimerExpired, + weak_factory_.GetWeakPtr(), context), + base::TimeDelta::FromMilliseconds(delay_ms)); +} + +void CdmAdapterImpl::TimerExpired(void* context) { + DCHECK(task_runner_->BelongsToCurrentThread()); + cdm_->TimerExpired(context); +} + +cdm::Time CdmAdapterImpl::GetCurrentWallTime() { + DCHECK(task_runner_->BelongsToCurrentThread()); + return base::Time::Now().ToDoubleT(); +} + +void CdmAdapterImpl::OnResolvePromise(uint32_t promise_id) { + DCHECK(task_runner_->BelongsToCurrentThread()); + cdm_promise_adapter_.ResolvePromise(promise_id); +} + +void CdmAdapterImpl::OnResolveNewSessionPromise(uint32_t promise_id, + const char* session_id, + uint32_t session_id_size) { + DCHECK(task_runner_->BelongsToCurrentThread()); + cdm_promise_adapter_.ResolvePromise(promise_id, + std::string(session_id, session_id_size)); +} + +void CdmAdapterImpl::OnRejectPromise(uint32_t promise_id, + cdm::Error error, + uint32_t system_code, + const char* error_message, + uint32_t error_message_size) { + DCHECK(task_runner_->BelongsToCurrentThread()); + cdm_promise_adapter_.RejectPromise( + promise_id, CdmErrorTypeToMediaExceptionType(error), system_code, + std::string(error_message, error_message_size)); +} + +void CdmAdapterImpl::OnSessionMessage(const char* session_id, + uint32_t session_id_size, + cdm::MessageType message_type, + const char* message, + uint32_t message_size, + const char* legacy_destination_url, + uint32_t legacy_destination_url_size) { + DCHECK(task_runner_->BelongsToCurrentThread()); + DCHECK(legacy_destination_url_size == 0 || + message_type != cdm::MessageType::kLicenseRequest); + + GURL verified_gurl = + GURL(std::string(legacy_destination_url, legacy_destination_url_size)); + if (!verified_gurl.is_valid()) { + DLOG(WARNING) << "SessionMessage legacy_destination_url is invalid : " + << verified_gurl.possibly_invalid_spec(); + verified_gurl = GURL::EmptyGURL(); // Replace invalid destination_url. + } + + const uint8_t* message_ptr = reinterpret_cast<const uint8*>(message); + session_message_cb_.Run( + std::string(session_id, session_id_size), + CdmMessageTypeToMediaMessageType(message_type), + std::vector<uint8_t>(message_ptr, message_ptr + message_size), + verified_gurl); +} + +void CdmAdapterImpl::OnSessionKeysChange(const char* session_id, + uint32_t session_id_size, + bool has_additional_usable_key, + const cdm::KeyInformation* keys_info, + uint32_t keys_info_count) { + DCHECK(task_runner_->BelongsToCurrentThread()); + + CdmKeysInfo keys; + keys.reserve(keys_info_count); + for (uint32_t i = 0; i < keys_info_count; ++i) { + const auto& info = keys_info[i]; + keys.push_back(new CdmKeyInformation( + info.key_id, info.key_id_size, + CdmKeyStatusToCdmKeyInformationKeyStatus(info.status), + info.system_code)); + } + + session_keys_change_cb_.Run(std::string(session_id, session_id_size), + has_additional_usable_key, keys.Pass()); +} + +void CdmAdapterImpl::OnExpirationChange(const char* session_id, + uint32_t session_id_size, + cdm::Time new_expiry_time) { + DCHECK(task_runner_->BelongsToCurrentThread()); + + session_expiration_update_cb_.Run(std::string(session_id, session_id_size), + base::Time::FromDoubleT(new_expiry_time)); +} + +void CdmAdapterImpl::OnSessionClosed(const char* session_id, + uint32_t session_id_size) { + DCHECK(task_runner_->BelongsToCurrentThread()); + + session_closed_cb_.Run(std::string(session_id, session_id_size)); +} + +void CdmAdapterImpl::OnLegacySessionError(const char* session_id, + uint32_t session_id_size, + cdm::Error error, + uint32_t system_code, + const char* error_message, + uint32_t error_message_size) { + DCHECK(task_runner_->BelongsToCurrentThread()); + + legacy_session_error_cb_.Run(std::string(session_id, session_id_size), + CdmErrorTypeToMediaExceptionType(error), + system_code, + std::string(error_message, error_message_size)); +} + +void CdmAdapterImpl::SendPlatformChallenge(const char* service_id, + uint32_t service_id_size, + const char* challenge, + uint32_t challenge_size) { + DCHECK(task_runner_->BelongsToCurrentThread()); + + // TODO(jrummell): If platform verification is available, use it. + NOTIMPLEMENTED(); + cdm::PlatformChallengeResponse platform_challenge_response = {}; + cdm_->OnPlatformChallengeResponse(platform_challenge_response); +} + +void CdmAdapterImpl::EnableOutputProtection(uint32_t desired_protection_mask) { + DCHECK(task_runner_->BelongsToCurrentThread()); + + // TODO(jrummell): If output protection is available, use it. + NOTIMPLEMENTED(); +} + +void CdmAdapterImpl::QueryOutputProtectionStatus() { + DCHECK(task_runner_->BelongsToCurrentThread()); + + // TODO(jrummell): If output protection is available, use it. + NOTIMPLEMENTED(); + cdm_->OnQueryOutputProtectionStatus(cdm::kQueryFailed, 0, 0); +} + +void CdmAdapterImpl::OnDeferredInitializationDone(cdm::StreamType stream_type, + cdm::Status decoder_status) { + DCHECK(task_runner_->BelongsToCurrentThread()); + + // Not initializing a decoder, so this should never happen. + NOTREACHED(); +} + +// The CDM owns the returned object and must call FileIO::Close() to release it. +cdm::FileIO* CdmAdapterImpl::CreateFileIO(cdm::FileIOClient* client) { + DCHECK(task_runner_->BelongsToCurrentThread()); + + // TODO(jrummell): This should use the mojo FileIO client. + NOTIMPLEMENTED(); + return nullptr; +} + +} // namespace media
diff --git a/media/cdm/cdm_adapter_impl.h b/media/cdm/cdm_adapter_impl.h new file mode 100644 index 0000000..41b091c --- /dev/null +++ b/media/cdm/cdm_adapter_impl.h
@@ -0,0 +1,153 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_CDM_CDM_ADAPTER_IMPL_H_ +#define MEDIA_CDM_CDM_ADAPTER_IMPL_H_ + +#include <string> +#include <vector> + +#include "base/files/file_path.h" +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "base/scoped_native_library.h" +#include "base/threading/thread.h" +#include "media/base/cdm_config.h" +#include "media/base/cdm_promise_adapter.h" +#include "media/base/media_keys.h" +#include "media/cdm/api/content_decryption_module.h" + +namespace media { + +class CdmWrapper; + +class CdmAdapterImpl : public MediaKeys, + public cdm::Host_7, + public cdm::Host_8 { + public: + CdmAdapterImpl(); + + // Load the CDM using |cdm_path| and initialize it using |key_system| and + // |cdm_config|. Callbacks will be used for events generated by the CDM. + // |promise| is resolved if the CDM is loaded and initialized correctly, + // otherwise it is rejected. + void Initialize(const std::string& key_system, + const base::FilePath& cdm_path, + const CdmConfig& cdm_config, + const SessionMessageCB& session_message_cb, + const SessionClosedCB& session_closed_cb, + const LegacySessionErrorCB& legacy_session_error_cb, + const SessionKeysChangeCB& session_keys_change_cb, + const SessionExpirationUpdateCB& session_expiration_update_cb, + scoped_ptr<SimpleCdmPromise> promise); + + // MediaKeys implementation. + void SetServerCertificate(const std::vector<uint8_t>& certificate, + scoped_ptr<SimpleCdmPromise> promise) override; + void CreateSessionAndGenerateRequest( + SessionType session_type, + EmeInitDataType init_data_type, + const std::vector<uint8_t>& init_data, + scoped_ptr<NewSessionCdmPromise> promise) override; + void LoadSession(SessionType session_type, + const std::string& session_id, + scoped_ptr<NewSessionCdmPromise> promise) override; + void UpdateSession(const std::string& session_id, + const std::vector<uint8_t>& response, + scoped_ptr<SimpleCdmPromise> promise) override; + void CloseSession(const std::string& session_id, + scoped_ptr<SimpleCdmPromise> promise) override; + void RemoveSession(const std::string& session_id, + scoped_ptr<SimpleCdmPromise> promise) override; + CdmContext* GetCdmContext() override; + + // cdm::Host_7 and cdm::Host_8 implementation. + cdm::Buffer* Allocate(uint32_t capacity) override; + void SetTimer(int64_t delay_ms, void* context) override; + cdm::Time GetCurrentWallTime() override; + void OnResolveNewSessionPromise(uint32_t promise_id, + const char* session_id, + uint32_t session_id_size) override; + void OnResolvePromise(uint32_t promise_id) override; + void OnRejectPromise(uint32_t promise_id, + cdm::Error error, + uint32_t system_code, + const char* error_message, + uint32_t error_message_size) override; + void OnSessionMessage(const char* session_id, + uint32_t session_id_size, + cdm::MessageType message_type, + const char* message, + uint32_t message_size, + const char* legacy_destination_url, + uint32_t legacy_destination_url_size) override; + void OnSessionKeysChange(const char* session_id, + uint32_t session_id_size, + bool has_additional_usable_key, + const cdm::KeyInformation* keys_info, + uint32_t keys_info_count) override; + void OnExpirationChange(const char* session_id, + uint32_t session_id_size, + cdm::Time new_expiry_time) override; + void OnSessionClosed(const char* session_id, + uint32_t session_id_size) override; + void OnLegacySessionError(const char* session_id, + uint32_t session_id_size, + cdm::Error error, + uint32_t system_code, + const char* error_message, + uint32_t error_message_size) override; + void SendPlatformChallenge(const char* service_id, + uint32_t service_id_size, + const char* challenge, + uint32_t challenge_size) override; + void EnableOutputProtection(uint32_t desired_protection_mask) override; + void QueryOutputProtectionStatus() override; + void OnDeferredInitializationDone(cdm::StreamType stream_type, + cdm::Status decoder_status) override; + cdm::FileIO* CreateFileIO(cdm::FileIOClient* client) override; + + private: + ~CdmAdapterImpl() final; + + // Create an instance of the |key_system| CDM contained in |cdm_path|. + // Caller owns the returned pointer. On error (unable to load, does not + // support |key_system|, does not support an supported interface, etc.) + // NULL will be returned. + CdmWrapper* CreateCdmInstance(const std::string& key_system, + const base::FilePath& cdm_path); + + // Helper for SetTimer(). + void TimerExpired(void* context); + + // Keep a reference to the CDM. + base::ScopedNativeLibrary library_; + + // Used to keep track of promises while the CDM is processing the request. + CdmPromiseAdapter cdm_promise_adapter_; + + scoped_ptr<CdmWrapper> cdm_; + std::string key_system_; + CdmConfig cdm_config_; + + // Callbacks for firing session events. + SessionMessageCB session_message_cb_; + SessionClosedCB session_closed_cb_; + LegacySessionErrorCB legacy_session_error_cb_; + SessionKeysChangeCB session_keys_change_cb_; + SessionExpirationUpdateCB session_expiration_update_cb_; + + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + + // NOTE: Weak pointers must be invalidated before all other member variables. + base::WeakPtrFactory<CdmAdapterImpl> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(CdmAdapterImpl); +}; + +} // namespace media + +#endif // MEDIA_CDM_CDM_ADAPTER_IMPL_H_
diff --git a/media/cdm/cdm_wrapper.h b/media/cdm/cdm_wrapper.h index c8fe54d..f5aef43 100644 --- a/media/cdm/cdm_wrapper.h +++ b/media/cdm/cdm_wrapper.h
@@ -12,6 +12,7 @@ #include "media/cdm/supported_cdm_versions.h" #if defined(USE_PPAPI_CDM_ADAPTER) +// When building the ppapi adapter do not include any non-trivial base/ headers. #include "ppapi/cpp/logging.h" #define PLATFORM_DCHECK PP_DCHECK #else @@ -21,6 +22,19 @@ namespace media { +// Returns a pointer to the requested CDM upon success. +// Returns NULL if an error occurs or the requested |cdm_interface_version| or +// |key_system| is not supported or another error occurs. +// The caller should cast the returned pointer to the type matching +// |cdm_interface_version|. +// Caller retains ownership of arguments and must call Destroy() on the returned +// object. +typedef void* (*CreateCdmFunc)(int cdm_interface_version, + const char* key_system, + uint32_t key_system_size, + GetCdmHostFunc get_cdm_host_func, + void* user_data); + // CdmWrapper wraps different versions of ContentDecryptionModule interfaces and // exposes a common interface to the caller. // @@ -36,7 +50,8 @@ // (just a shim layer in most cases), everything is done in this header file. class CdmWrapper { public: - static CdmWrapper* Create(const char* key_system, + static CdmWrapper* Create(CreateCdmFunc create_cdm_func, + const char* key_system, uint32_t key_system_size, GetCdmHostFunc get_cdm_host_func, void* user_data); @@ -103,15 +118,16 @@ template <class CdmInterface> class CdmWrapperImpl : public CdmWrapper { public: - static CdmWrapper* Create(const char* key_system, + static CdmWrapper* Create(CreateCdmFunc create_cdm_func, + const char* key_system, uint32_t key_system_size, GetCdmHostFunc get_cdm_host_func, void* user_data) { void* cdm_instance = - ::CreateCdmInstance(CdmInterface::kVersion, key_system, key_system_size, - get_cdm_host_func, user_data); + create_cdm_func(CdmInterface::kVersion, key_system, key_system_size, + get_cdm_host_func, user_data); if (!cdm_instance) - return NULL; + return nullptr; return new CdmWrapperImpl<CdmInterface>( static_cast<CdmInterface*>(cdm_instance)); @@ -256,7 +272,8 @@ init_data_type_as_string.length(), init_data, init_data_size); } -CdmWrapper* CdmWrapper::Create(const char* key_system, +CdmWrapper* CdmWrapper::Create(CreateCdmFunc create_cdm_func, + const char* key_system, uint32_t key_system_size, GetCdmHostFunc get_cdm_host_func, void* user_data) { @@ -280,13 +297,15 @@ // Try to create the CDM using the latest CDM interface version. CdmWrapper* cdm_wrapper = CdmWrapperImpl<cdm::ContentDecryptionModule>::Create( - key_system, key_system_size, get_cdm_host_func, user_data); + create_cdm_func, key_system, key_system_size, get_cdm_host_func, + user_data); // If |cdm_wrapper| is NULL, try to create the CDM using older supported // versions of the CDM interface here. if (!cdm_wrapper) { cdm_wrapper = CdmWrapperImpl<cdm::ContentDecryptionModule_7>::Create( - key_system, key_system_size, get_cdm_host_func, user_data); + create_cdm_func, key_system, key_system_size, get_cdm_host_func, + user_data); } return cdm_wrapper;
diff --git a/media/cdm/ppapi/ppapi_cdm_adapter.cc b/media/cdm/ppapi/ppapi_cdm_adapter.cc index e4fa9e43..e90a2f6 100644 --- a/media/cdm/ppapi/ppapi_cdm_adapter.cc +++ b/media/cdm/ppapi/ppapi_cdm_adapter.cc
@@ -341,8 +341,10 @@ PpapiCdmAdapter::~PpapiCdmAdapter() {} CdmWrapper* PpapiCdmAdapter::CreateCdmInstance(const std::string& key_system) { - CdmWrapper* cdm = CdmWrapper::Create(key_system.data(), key_system.size(), - GetCdmHost, this); + // The Pepper plugin will be staticly linked to the CDM, so pass the plugin's + // CreateCdmInstance() to CdmWrapper. + CdmWrapper* cdm = CdmWrapper::Create(::CreateCdmInstance, key_system.data(), + key_system.size(), GetCdmHost, this); const std::string message = "CDM instance for " + key_system + (cdm ? "" : " could not be") + " created.";
diff --git a/media/cdm/ppapi/ppapi_cdm_adapter.h b/media/cdm/ppapi/ppapi_cdm_adapter.h index 7d1527dd..470bc9a5 100644 --- a/media/cdm/ppapi/ppapi_cdm_adapter.h +++ b/media/cdm/ppapi/ppapi_cdm_adapter.h
@@ -165,6 +165,9 @@ std::string legacy_destination_url; }; + // Create an instance of the |key_system| CDM. Caller owns the returned + // pointer. On error (unable to load CDM, does not support |key_system|, + // does not support an supported interface, etc.) NULL will be returned. CdmWrapper* CreateCdmInstance(const std::string& key_system); // <code>PPB_ContentDecryptor_Private</code> dispatchers. These are passed to
diff --git a/media/media.gyp b/media/media.gyp index dc23002a4..75f6e91 100644 --- a/media/media.gyp +++ b/media/media.gyp
@@ -488,6 +488,10 @@ 'capture/video/win/video_capture_device_win.h', 'cdm/aes_decryptor.cc', 'cdm/aes_decryptor.h', + 'cdm/cdm_adapter.cc', + 'cdm/cdm_adapter.h', + 'cdm/cdm_adapter_impl.cc', + 'cdm/cdm_adapter_impl.h', 'cdm/default_cdm_factory.cc', 'cdm/default_cdm_factory.h', 'cdm/json_web_key.cc',
diff --git a/media/midi/midi_manager_win.cc b/media/midi/midi_manager_win.cc index 4adedbb..efab827 100644 --- a/media/midi/midi_manager_win.cc +++ b/media/midi/midi_manager_win.cc
@@ -428,7 +428,7 @@ ~MidiServiceWinImpl() final { // Start() and Stop() of the threads, and AddDevicesChangeObserver() and // RemoveDevicesChangeObserver() should be called on the same thread. - CHECK(thread_checker_.CalledOnValidThread()); + DCHECK(thread_checker_.CalledOnValidThread()); destructor_started = true; base::SystemMonitor::Get()->RemoveDevicesChangedObserver(this); @@ -482,7 +482,7 @@ void InitializeAsync(MidiServiceWinDelegate* delegate) final { // Start() and Stop() of the threads, and AddDevicesChangeObserver() and // RemoveDevicesChangeObserver() should be called on the same thread. - CHECK(thread_checker_.CalledOnValidThread()); + DCHECK(thread_checker_.CalledOnValidThread()); delegate_ = delegate; @@ -539,7 +539,7 @@ // base::SystemMonitor::DevicesChangedObserver overrides: void OnDevicesChanged(base::SystemMonitor::DeviceType device_type) final { - CHECK(thread_checker_.CalledOnValidThread()); + DCHECK(thread_checker_.CalledOnValidThread()); if (destructor_started) return; @@ -1120,7 +1120,6 @@ } MidiManagerWin::~MidiManagerWin() { - midi_service_.reset(); } void MidiManagerWin::StartInitialization() { @@ -1129,6 +1128,10 @@ midi_service_->InitializeAsync(this); } +void MidiManagerWin::Finalize() { + midi_service_.reset(); +} + void MidiManagerWin::DispatchSendMidiData(MidiManagerClient* client, uint32 port_index, const std::vector<uint8>& data,
diff --git a/media/midi/midi_manager_win.h b/media/midi/midi_manager_win.h index dbee7e15..b54f9d18 100644 --- a/media/midi/midi_manager_win.h +++ b/media/midi/midi_manager_win.h
@@ -47,6 +47,7 @@ // MidiManager overrides: void StartInitialization() final; + void Finalize() final; void DispatchSendMidiData(MidiManagerClient* client, uint32 port_index, const std::vector<uint8>& data,
diff --git a/mojo/converters/geometry/geometry_type_converters.cc b/mojo/converters/geometry/geometry_type_converters.cc index 00f4f343..c918d01 100644 --- a/mojo/converters/geometry/geometry_type_converters.cc +++ b/mojo/converters/geometry/geometry_type_converters.cc
@@ -115,4 +115,39 @@ return gfx::Size(input.width, input.height); } +// static +Insets TypeConverter<Insets, gfx::Insets>::Convert(const gfx::Insets& input) { + Insets insets; + insets.top = input.top(); + insets.left = input.left(); + insets.bottom = input.bottom(); + insets.right = input.right(); + return insets; +} + +// static +gfx::Insets TypeConverter<gfx::Insets, Insets>::Convert(const Insets& input) { + return gfx::Insets(input.top, input.left, input.bottom, input.right); +} + +// static +InsetsPtr TypeConverter<InsetsPtr, gfx::Insets>::Convert( + const gfx::Insets& input) { + InsetsPtr insets(Insets::New()); + insets->top = input.top(); + insets->left = input.left(); + insets->bottom = input.bottom(); + insets->right = input.right(); + return insets.Pass(); +} + +// static +gfx::Insets TypeConverter<gfx::Insets, InsetsPtr>::Convert( + const InsetsPtr& input) { + if (input.is_null()) + return gfx::Insets(); + + return gfx::Insets(input->top, input->left, input->bottom, input->right); +} + } // namespace mojo
diff --git a/mojo/converters/geometry/geometry_type_converters.h b/mojo/converters/geometry/geometry_type_converters.h index d3d8fd2..f90aba7 100644 --- a/mojo/converters/geometry/geometry_type_converters.h +++ b/mojo/converters/geometry/geometry_type_converters.h
@@ -6,6 +6,7 @@ #define MOJO_CONVERTERS_GEOMETRY_GEOMETRY_TYPE_CONVERTERS_H_ #include "mojo/converters/geometry/mojo_geometry_export.h" +#include "ui/gfx/geometry/insets.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/point_f.h" #include "ui/gfx/geometry/rect.h" @@ -78,6 +79,24 @@ static gfx::Size Convert(const Size& input); }; +template <> +struct MOJO_GEOMETRY_EXPORT TypeConverter<Insets, gfx::Insets> { + static Insets Convert(const gfx::Insets& input); +}; +template <> +struct MOJO_GEOMETRY_EXPORT TypeConverter<gfx::Insets, Insets> { + static gfx::Insets Convert(const Insets& input); +}; + +template <> +struct MOJO_GEOMETRY_EXPORT TypeConverter<InsetsPtr, gfx::Insets> { + static InsetsPtr Convert(const gfx::Insets& input); +}; +template <> +struct MOJO_GEOMETRY_EXPORT TypeConverter<gfx::Insets, InsetsPtr> { + static gfx::Insets Convert(const InsetsPtr& input); +}; + } // namespace mojo #endif // MOJO_CONVERTERS_GEOMETRY_GEOMETRY_TYPE_CONVERTERS_H_
diff --git a/third_party/WebKit/LayoutTests/bluetooth/advertising-data.html b/third_party/WebKit/LayoutTests/bluetooth/advertising-data.html new file mode 100644 index 0000000..703ab815 --- /dev/null +++ b/third_party/WebKit/LayoutTests/bluetooth/advertising-data.html
@@ -0,0 +1,116 @@ +<!DOCTYPE html> +<script src="../resources/testharness.js"></script> +<script src="../resources/testharnessreport.js"></script> +<script src="resources/bluetooth-helpers.js"></script> +<script> +'use strict'; + +test(function(t) { assert_true(window.testRunner instanceof Object); t.done(); }, + 'window.testRunner is required for the following tests.'); +// Tests that we are handling values returned from the underlying platform +// correctly. Only meant to be used by chromium. +[{ + name: 'Tx Power too low must result in nulled txPower.', + tx_power: -128, + expected_tx_power: null, + rssi: 0, + expected_rssi: 0 +}, { + name: 'RSSI too low must result in nulled rssi.', + tx_power: 0, + expected_tx_power: 0, + rssi: -128, + expected_rssi: null +}, { + name: 'Low Tx Power should appear in adData.', + tx_power: -127, + expected_tx_power: -127, + rssi: 0, + expected_rssi: 0 +}, { + name: 'Low RSSI should appear in adData.', + tx_power: 0, + expected_tx_power: 0, + rssi: -127, + expected_rssi: -127 +}, { + name: 'High Tx Power should appear in adData.', + // TODO(ortuno): According to the Bluetooth Spec Supplement, 127 is the + // the hightest possible valid value for Tx Power. Change to 127 when + // fixed: http://crbug.com/551572 + tx_power: 126, + expected_tx_power: 126, + rssi: 0, + expected_rssi: 0 +}, { + name: 'High RSSI should appear in adData.', + tx_power: 0, + expected_tx_power: 0, + rssi: 126, + expected_rssi: 126 +}, { + // TODO(ortuno): Remove this test since 127 is both a valid Tx Power + // and the max value of a int8. + // http://crbug.com/551572 + name: 'Tx Power too high must result in nulled txPower.', + tx_power: 127, + expected_tx_power: null, + rssi: 0, + expected_rssi: 0 +}, { + name: 'RSSI too high must result in nulled rssi.', + tx_power: 0, + expected_tx_power: 0, + rssi: 127, + expected_rssi: null +}].forEach(power_test => { + promise_test(() => { + testRunner.setBluetoothMockDataSet('PowerValueAdapter:' + + power_test.tx_power + ':' + + power_test.rssi); + return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]}) + .then(device => { + let adv_data = device.adData; + assert_equals(adv_data.txPower, power_test.expected_tx_power); + assert_equals(adv_data.rssi, power_test.expected_rssi); + }); + }, power_test.name); +}); + +// Tests for all platforms. +[{ + name: 'TxPower not present, RSSI not present.', + tx_power_present: false, + rssi_present: false +}, { + name: 'TxPower not present, RSSI present.', + tx_power_present: false, + rssi_present: true +}, { + name: 'TxPower present, RSSI not present.', + tx_power_present: true, + rssi_present: false, +}, { + name: 'TxPower present, RSSI present.', + tx_power_present: true, + rssi_present: true +}].forEach(power_test => { + promise_test(() => { + testRunner.setBluetoothMockDataSet('PowerPresenceAdapter:' + + power_test.tx_power_present + ':' + + power_test.rssi_present); + return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]}) + .then(device => { + let adv_data = device.adData; + let expected_tx_power = power_test.tx_power_present ? + -10 /* broadcasting at 0.1mW */ + : null; + let expected_rssi = power_test.rssi_present ? + -51 /* power at 1m from device broadcasting at 0.1mW */ + : null; + assert_equals(adv_data.txPower, expected_tx_power); + assert_equals(adv_data.rssi, expected_rssi); + }); + }, power_test.name) +}); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/text/first-letter-bad-line-boxes-crash-expected.txt b/third_party/WebKit/LayoutTests/fast/text/first-letter-bad-line-boxes-crash-expected.txt index fd703d5..bbfaf90 100644 --- a/third_party/WebKit/LayoutTests/fast/text/first-letter-bad-line-boxes-crash-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/text/first-letter-bad-line-boxes-crash-expected.txt
@@ -3,6 +3,7 @@ CONSOLE WARNING: We don't execute document.execCommand() this time, because it is called recursively. \\\\\\m{VVVVVVVVVVVVVVV<};<WWWWW - \\\\\\m{VVVVVVVVVVVVVVV<};<WWWWW + Te\\\\\\m{VVVVVVVVVVVVVVV<};<WWWWW xt +
diff --git a/third_party/WebKit/LayoutTests/fast/text/insert-text-crash-expected.txt b/third_party/WebKit/LayoutTests/fast/text/insert-text-crash-expected.txt index 6902cf2..d5bb3cf6 100644 --- a/third_party/WebKit/LayoutTests/fast/text/insert-text-crash-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/text/insert-text-crash-expected.txt
@@ -1,4 +1,4 @@ CONSOLE WARNING: We don't execute document.execCommand() this time, because it is called recursively. CONSOLE WARNING: SVG's SMIL animations (<animate>, <set>, etc.) are deprecated and will be removed. Please use CSS animations or Web animations instead. -a:ca:ce#@::l@::l +a:ce#@:a:ce#@::l:l Test passes if it does not CRASH.
diff --git a/third_party/WebKit/LayoutTests/http/tests/fetch/window/pageimportancesignals-expected.txt b/third_party/WebKit/LayoutTests/http/tests/fetch/window/pageimportancesignals-expected.txt new file mode 100644 index 0000000..f062130 --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/fetch/window/pageimportancesignals-expected.txt
@@ -0,0 +1,17 @@ +CONSOLE MESSAGE: line 12: Testing script initiated GET fetch. +WebPageImportanceSignals: + hadFormInteraction: false + issuedNonGetFetchFromScript: false +CONSOLE MESSAGE: line 28: Testing script initiated POST fetch. +WebPageImportanceSignals: + hadFormInteraction: false + issuedNonGetFetchFromScript: true +PageImportanceSignals should be recorded after script initiated non-GET fetch. + +On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". + + +PASS successfullyParsed is true + +TEST COMPLETE +
diff --git a/third_party/WebKit/LayoutTests/http/tests/fetch/window/pageimportancesignals.html b/third_party/WebKit/LayoutTests/http/tests/fetch/window/pageimportancesignals.html new file mode 100644 index 0000000..fc272ad --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/fetch/window/pageimportancesignals.html
@@ -0,0 +1,44 @@ +<!DOCTYPE html> +<script src="/js-test-resources/js-test.js"></script> +<script> +description("PageImportanceSignals should be recorded after script initiated non-GET fetch."); +window.jsTestIsAsync = true; + +function parseJSON(response) { + return response.json; +} + +function test1() { + console.log("Testing script initiated GET fetch."); + window.fetch("../resources/simple.json") + .then(parseJSON) + .then(function(data) { + if (window.testRunner) + window.testRunner.dumpPageImportanceSignals(); + + test2(); + }) + .catch(function(error) { + testFailed("fetch failed: "+error); + finishJSTest(); + }); +} + +function test2() { + console.log("Testing script initiated POST fetch."); + window.fetch("../resources/simple.json", { method: "POST" }) + .then(parseJSON) + .then(function(data) { + if (window.testRunner) + window.testRunner.dumpPageImportanceSignals(); + + finishJSTest(); + }) + .catch(function() { + testFailed("fetch failed: "+error); + finishJSTest(); + }); +} + +test1(); +</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/resources/usecounter.js b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/resources/usecounter.js new file mode 100644 index 0000000..bc89a96f --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/resources/usecounter.js
@@ -0,0 +1,5 @@ +function isUseCounted(frame) { + var ServiceWorkerControlledPage = 990; // From UseCounter.h + return frame.contentWindow.internals.isUseCounted( + frame.contentDocument, ServiceWorkerControlledPage); +}
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/usecounter-on-claim.html b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/usecounter-on-claim.html new file mode 100644 index 0000000..93cba0a7 --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/usecounter-on-claim.html
@@ -0,0 +1,56 @@ +<!DOCTYPE html> +<title>Service Worker: UseCounter for page controlled-on-claim</title> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script src="../resources/test-helpers.js"></script> +<script src="resources/usecounter.js"></script> +<script> + +promise_test(function(t) { + var url = '../resources/claim-worker.js'; + var scope = '../resources/blank.html?usecounter-on-claim'; + var worker; + var frame; + + return service_worker_unregister(t, scope) + .then(function() { return with_iframe(scope); }) + .then(function(f) { + frame = f; + add_completion_callback(function() { frame.remove(); }); + var w = frame.contentWindow; + assert_equals(w.navigator.serviceWorker.controller, null); + assert_false(isUseCounted(frame), + 'should not be counted as controlled yet'); + return navigator.serviceWorker.register(url, {scope: scope}); + }) + .then(function(registration) { + add_completion_callback(function() { registration.unregister(); }); + worker = registration.installing; + return wait_for_state(t, worker, 'activated'); + }) + .then(function() { + var w = frame.contentWindow; + var saw_controllerchanged = new Promise(function(resolve) { + w.navigator.serviceWorker.oncontrollerchange = resolve; + }); + var channel = new MessageChannel(); + var saw_message = new Promise(function(resolve) { + channel.port1.onmessage = t.step_func(function(e) { + assert_equals(e.data, 'PASS', 'claim() should fulfill'); + resolve(); + }); + }); + worker.postMessage({port: channel.port2}, [channel.port2]); + return Promise.all([saw_controllerchanged, saw_message]); + }) + .then(function() { + var w = frame.contentWindow; + var controller = w.navigator.serviceWorker.controller; + assert_true(controller instanceof w.ServiceWorker); + assert_true(isUseCounted(frame), + 'should be counted as controlled after claim()'); + }); + }, 'usecounter is counted upon claim() after registration'); + +</script> +</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/usecounter-on-load.html b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/usecounter-on-load.html new file mode 100644 index 0000000..3788ac01 --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/usecounter-on-load.html
@@ -0,0 +1,29 @@ +<!DOCTYPE html> +<title>Service Worker: UseCounter for page controlled-on-load</title> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script src="../resources/test-helpers.js"></script> +<script src="resources/usecounter.js"></script> +<script> + +promise_test(function(t) { + var url = 'resources/empty-worker.js'; + var scope = 'resources/blank.html?on-load'; + + return service_worker_unregister_and_register(t, url, scope) + .then(function(registration) { + add_completion_callback(function() { registration.unregister(); }); + return wait_for_state(t, registration.installing, 'activated'); + }) + .then(function() { return with_iframe(scope) }) + .then(function(frame) { + add_completion_callback(function() { frame.remove(); }); + var w = frame.contentWindow; + var controller = w.navigator.serviceWorker.controller; + assert_true(controller instanceof w.ServiceWorker); + assert_true(isUseCounted(frame), 'should be counted as controlled'); + }); + }, 'usecounter is counted for a controlled document'); + +</script> +</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/usecounter-on-reload.html b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/usecounter-on-reload.html new file mode 100644 index 0000000..874dd46 --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/usecounter-on-reload.html
@@ -0,0 +1,47 @@ +<!DOCTYPE html> +<title>Service Worker: UseCounter for page controlled-on-reload</title> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script src="../resources/test-helpers.js"></script> +<script src="resources/usecounter.js"></script> +<script> + +promise_test(function(t) { + var url = 'resources/empty-worker.js'; + var scope = 'resources/blank.html?on-reload'; + var frame; + + return service_worker_unregister(t, scope) + .then(function() { return with_iframe(scope); }) + .then(function(f) { + frame = f; + add_completion_callback(function() { frame.remove(); }); + var w = frame.contentWindow; + assert_equals(w.navigator.serviceWorker.controller, null); + assert_false(isUseCounted(frame), + 'should not be counted as controlled yet'); + return navigator.serviceWorker.register(url, {scope: scope}); + }) + .then(function(registration) { + add_completion_callback(function() { registration.unregister(); }); + return wait_for_state(t, registration.installing, 'activated'); + }) + .then(function() { + var w = frame.contentWindow; + assert_equals(w.navigator.serviceWorker.controller, null); + return new Promise(function(resolve) { + frame.onload = function() { resolve(); } + w.location.reload(); + }); + }) + .then(function() { + var w = frame.contentWindow; + var controller = w.navigator.serviceWorker.controller; + assert_true(controller instanceof w.ServiceWorker); + assert_true(isUseCounted(frame), + 'should be counted as controlled after reload()'); + }); + }, 'usecounter is counted upon reload after registration'); + +</script> +</html>
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 70d1d6b..cc69615 100644 --- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -289,6 +289,10 @@ interface BlobEvent : Event getter data method constructor +interface BluetoothAdvertisingData + getter rssi + getter txPower + method constructor interface BluetoothCharacteristicProperties getter authenticatedSignedWrites getter broadcast @@ -301,6 +305,7 @@ getter writeWithoutResponse method constructor interface BluetoothDevice + getter adData getter deviceClass getter id getter instanceID
diff --git a/third_party/WebKit/Source/core/css/CSSSelectorList.cpp b/third_party/WebKit/Source/core/css/CSSSelectorList.cpp index ba3f0f0..ab68f70 100644 --- a/third_party/WebKit/Source/core/css/CSSSelectorList.cpp +++ b/third_party/WebKit/Source/core/css/CSSSelectorList.cpp
@@ -175,13 +175,13 @@ } }; -bool CSSSelectorList::hasShadowDistributedAt(size_t index) const +bool CSSSelectorList::selectorHasShadowDistributed(size_t index) const { SelectorHasShadowDistributed functor; return forEachTagSelector(functor, selectorAt(index)); } -class SelectorCrossesTreeScopes { +class SelectorUsesDeepCombinatorOrShadowPseudo { public: bool operator()(const CSSSelector& selector) { @@ -189,9 +189,9 @@ } }; -bool CSSSelectorList::selectorCrossesTreeScopes(size_t index) const +bool CSSSelectorList::selectorUsesDeepCombinatorOrShadowPseudo(size_t index) const { - SelectorCrossesTreeScopes functor; + SelectorUsesDeepCombinatorOrShadowPseudo functor; return forEachTagSelector(functor, selectorAt(index)); }
diff --git a/third_party/WebKit/Source/core/css/CSSSelectorList.h b/third_party/WebKit/Source/core/css/CSSSelectorList.h index 0c1ec08..d37148d 100644 --- a/third_party/WebKit/Source/core/css/CSSSelectorList.h +++ b/third_party/WebKit/Source/core/css/CSSSelectorList.h
@@ -63,9 +63,10 @@ bool selectorNeedsUpdatedDistribution(size_t index) const; - // TODO(esprehn): These methods are confusing and incorrectly named. - bool hasShadowDistributedAt(size_t index) const; - bool selectorCrossesTreeScopes(size_t index) const; + // TODO(kochi): "ShadowDistributed" means the selector has ::content pseudo element. + // Once ::slotted is introduced, come up with more readable name. + bool selectorHasShadowDistributed(size_t index) const; + bool selectorUsesDeepCombinatorOrShadowPseudo(size_t index) const; String selectorsText() const;
diff --git a/third_party/WebKit/Source/core/css/FontFace.idl b/third_party/WebKit/Source/core/css/FontFace.idl index 37e45c4..e847005 100644 --- a/third_party/WebKit/Source/core/css/FontFace.idl +++ b/third_party/WebKit/Source/core/css/FontFace.idl
@@ -43,6 +43,7 @@ // FIXME: This should be (DOMString or BinaryData), where BinaryData is typedef of (ArrayBuffer or ArrayBufferView) Constructor(DOMString family, (DOMString or ArrayBuffer or ArrayBufferView) source, optional FontFaceDescriptors descriptors), ConstructorCallWith=ExecutionContext, + MeasureAs=FontFaceConstructor, WillBeGarbageCollected, ] interface FontFace { [RaisesException=Setter, SetterCallWith=ExecutionContext] attribute DOMString family;
diff --git a/third_party/WebKit/Source/core/css/RuleSet.cpp b/third_party/WebKit/Source/core/css/RuleSet.cpp index 5bcdaf0..b37c2b0 100644 --- a/third_party/WebKit/Source/core/css/RuleSet.cpp +++ b/third_party/WebKit/Source/core/css/RuleSet.cpp
@@ -259,9 +259,9 @@ const CSSSelectorList& selectorList = styleRule->selectorList(); for (size_t selectorIndex = 0; selectorIndex != kNotFound; selectorIndex = selectorList.indexOfNextSelectorAfter(selectorIndex)) { - if (selectorList.selectorCrossesTreeScopes(selectorIndex)) { - m_treeBoundaryCrossingRules.append(MinimalRuleData(styleRule, selectorIndex, addRuleFlags)); - } else if (selectorList.hasShadowDistributedAt(selectorIndex)) { + if (selectorList.selectorUsesDeepCombinatorOrShadowPseudo(selectorIndex)) { + m_deepCombinatorOrShadowPseudoRules.append(MinimalRuleData(styleRule, selectorIndex, addRuleFlags)); + } else if (selectorList.selectorHasShadowDistributed(selectorIndex)) { m_shadowDistributedRules.append(MinimalRuleData(styleRule, selectorIndex, addRuleFlags)); } else { addRule(styleRule, selectorIndex, addRuleFlags); @@ -341,7 +341,7 @@ m_viewportRules.shrinkToFit(); m_fontFaceRules.shrinkToFit(); m_keyframesRules.shrinkToFit(); - m_treeBoundaryCrossingRules.shrinkToFit(); + m_deepCombinatorOrShadowPseudoRules.shrinkToFit(); m_shadowDistributedRules.shrinkToFit(); } @@ -382,7 +382,7 @@ visitor->trace(m_viewportRules); visitor->trace(m_fontFaceRules); visitor->trace(m_keyframesRules); - visitor->trace(m_treeBoundaryCrossingRules); + visitor->trace(m_deepCombinatorOrShadowPseudoRules); visitor->trace(m_shadowDistributedRules); visitor->trace(m_viewportDependentMediaQueryResults); visitor->trace(m_pendingRules);
diff --git a/third_party/WebKit/Source/core/css/RuleSet.h b/third_party/WebKit/Source/core/css/RuleSet.h index abf096a..203d177 100644 --- a/third_party/WebKit/Source/core/css/RuleSet.h +++ b/third_party/WebKit/Source/core/css/RuleSet.h
@@ -144,7 +144,7 @@ const WillBeHeapVector<RawPtrWillBeMember<StyleRuleViewport>>& viewportRules() const { ASSERT(!m_pendingRules); return m_viewportRules; } const WillBeHeapVector<RawPtrWillBeMember<StyleRuleFontFace>>& fontFaceRules() const { return m_fontFaceRules; } const WillBeHeapVector<RawPtrWillBeMember<StyleRuleKeyframes>>& keyframesRules() const { return m_keyframesRules; } - const WillBeHeapVector<MinimalRuleData>& treeBoundaryCrossingRules() const { return m_treeBoundaryCrossingRules; } + const WillBeHeapVector<MinimalRuleData>& deepCombinatorOrShadowPseudoRules() const { return m_deepCombinatorOrShadowPseudoRules; } const WillBeHeapVector<MinimalRuleData>& shadowDistributedRules() const { return m_shadowDistributedRules; } const MediaQueryResultList& viewportDependentMediaQueryResults() const { return m_viewportDependentMediaQueryResults; } @@ -220,7 +220,9 @@ WillBeHeapVector<RawPtrWillBeMember<StyleRuleViewport>> m_viewportRules; WillBeHeapVector<RawPtrWillBeMember<StyleRuleFontFace>> m_fontFaceRules; WillBeHeapVector<RawPtrWillBeMember<StyleRuleKeyframes>> m_keyframesRules; - WillBeHeapVector<MinimalRuleData> m_treeBoundaryCrossingRules; + WillBeHeapVector<MinimalRuleData> m_deepCombinatorOrShadowPseudoRules; + // TODO(kochi): "shadowDistributed" means the selector has ::content pseudo element. + // Once ::slotted is introduced, come up with more readable name. WillBeHeapVector<MinimalRuleData> m_shadowDistributedRules; MediaQueryResultList m_viewportDependentMediaQueryResults;
diff --git a/third_party/WebKit/Source/core/css/resolver/ScopedStyleResolver.cpp b/third_party/WebKit/Source/core/css/resolver/ScopedStyleResolver.cpp index f2bb5fe..e42cae5 100644 --- a/third_party/WebKit/Source/core/css/resolver/ScopedStyleResolver.cpp +++ b/third_party/WebKit/Source/core/css/resolver/ScopedStyleResolver.cpp
@@ -207,14 +207,14 @@ void ScopedStyleResolver::addTreeBoundaryCrossingRules(const RuleSet& authorRules, CSSStyleSheet* parentStyleSheet, unsigned sheetIndex) { bool isDocumentScope = treeScope().rootNode().isDocumentNode(); - if (authorRules.treeBoundaryCrossingRules().isEmpty() && (isDocumentScope || authorRules.shadowDistributedRules().isEmpty())) + if (authorRules.deepCombinatorOrShadowPseudoRules().isEmpty() && (isDocumentScope || authorRules.shadowDistributedRules().isEmpty())) return; - if (!authorRules.treeBoundaryCrossingRules().isEmpty()) + if (!authorRules.deepCombinatorOrShadowPseudoRules().isEmpty()) m_hasDeepOrShadowSelector = true; OwnPtrWillBeRawPtr<RuleSet> ruleSetForScope = RuleSet::create(); - addRules(ruleSetForScope.get(), authorRules.treeBoundaryCrossingRules()); + addRules(ruleSetForScope.get(), authorRules.deepCombinatorOrShadowPseudoRules()); if (!isDocumentScope) addRules(ruleSetForScope.get(), authorRules.shadowDistributedRules());
diff --git a/third_party/WebKit/Source/core/dom/Node.cpp b/third_party/WebKit/Source/core/dom/Node.cpp index 50e0821e..ce58a2e 100644 --- a/third_party/WebKit/Source/core/dom/Node.cpp +++ b/third_party/WebKit/Source/core/dom/Node.cpp
@@ -1439,8 +1439,7 @@ String Node::debugName() const { StringBuilder name; - name.append(nodeName()); - + name.append(debugNodeName()); if (isElementNode()) { const Element& thisElement = toElement(*this); if (thisElement.hasID()) { @@ -1459,10 +1458,14 @@ name.append('\''); } } - return name.toString(); } +String Node::debugNodeName() const +{ + return nodeName(); +} + #ifndef NDEBUG static void appendAttributeDesc(const Node* node, StringBuilder& stringBuilder, const QualifiedName& name, const char* attrDesc)
diff --git a/third_party/WebKit/Source/core/dom/Node.h b/third_party/WebKit/Source/core/dom/Node.h index dbc4db9..3d58ac8 100644 --- a/third_party/WebKit/Source/core/dom/Node.h +++ b/third_party/WebKit/Source/core/dom/Node.h
@@ -579,6 +579,8 @@ // virtual void removedFrom(ContainerNode* insertionPoint); + // FIXME(dominicc): This method is not debug-only--it is used by + // Tracing--rename it to something indicative. String debugName() const; #ifndef NDEBUG @@ -787,6 +789,13 @@ #endif bool hasTreeSharedParent() const { return !!parentOrShadowHostNode(); } + // Gets nodeName without caching AtomicStrings. Used by + // debugName. Compositor may call debugName from the "impl" thread + // during "commit". The main thread is stopped at that time, but + // it is not safe to cache AtomicStrings because those are + // per-thread. + virtual String debugNodeName() const; + enum EditableLevel { Editable, RichlyEditable }; bool hasEditableStyle(EditableLevel, UserSelectAllTreatment = UserSelectAllIsAlwaysNonEditable) const; bool isEditableToAccessibility(EditableLevel) const;
diff --git a/third_party/WebKit/Source/core/dom/SelectorQuery.cpp b/third_party/WebKit/Source/core/dom/SelectorQuery.cpp index 1f929dd..4b47147 100644 --- a/third_party/WebKit/Source/core/dom/SelectorQuery.cpp +++ b/third_party/WebKit/Source/core/dom/SelectorQuery.cpp
@@ -106,13 +106,13 @@ for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(*selector)) selectorCount++; - m_crossesTreeBoundary = false; + m_usesDeepCombinatorOrShadowPseudo = false; m_needsUpdatedDistribution = false; m_selectors.reserveInitialCapacity(selectorCount); unsigned index = 0; for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(*selector), ++index) { m_selectors.uncheckedAppend(selector); - m_crossesTreeBoundary |= selectorList.selectorCrossesTreeScopes(index); + m_usesDeepCombinatorOrShadowPseudo |= selectorList.selectorUsesDeepCombinatorOrShadowPseudo(index); m_needsUpdatedDistribution |= selectorList.selectorNeedsUpdatedDistribution(index); } } @@ -213,7 +213,7 @@ inline bool SelectorDataList::canUseFastQuery(const ContainerNode& rootNode) const { - if (m_crossesTreeBoundary) + if (m_usesDeepCombinatorOrShadowPseudo) return false; if (m_needsUpdatedDistribution) return false; @@ -455,7 +455,7 @@ if (!canUseFastQuery(rootNode)) { if (m_needsUpdatedDistribution) rootNode.updateDistribution(); - if (m_crossesTreeBoundary) { + if (m_usesDeepCombinatorOrShadowPseudo) { executeSlowTraversingShadowTree<SelectorQueryTrait>(rootNode, output); } else { executeSlow<SelectorQueryTrait>(rootNode, output);
diff --git a/third_party/WebKit/Source/core/dom/SelectorQuery.h b/third_party/WebKit/Source/core/dom/SelectorQuery.h index 08e8639..172fecd 100644 --- a/third_party/WebKit/Source/core/dom/SelectorQuery.h +++ b/third_party/WebKit/Source/core/dom/SelectorQuery.h
@@ -81,7 +81,7 @@ const CSSSelector* selectorForIdLookup(const CSSSelector&) const; Vector<const CSSSelector*> m_selectors; - bool m_crossesTreeBoundary : 1; + bool m_usesDeepCombinatorOrShadowPseudo : 1; bool m_needsUpdatedDistribution : 1; };
diff --git a/third_party/WebKit/Source/core/editing/VisibleUnits.cpp b/third_party/WebKit/Source/core/editing/VisibleUnits.cpp index 7328a36..a51beb24 100644 --- a/third_party/WebKit/Source/core/editing/VisibleUnits.cpp +++ b/third_party/WebKit/Source/core/editing/VisibleUnits.cpp
@@ -29,6 +29,7 @@ #include "core/HTMLNames.h" #include "core/dom/Document.h" #include "core/dom/Element.h" +#include "core/dom/FirstLetterPseudoElement.h" #include "core/dom/NodeTraversal.h" #include "core/dom/Text.h" #include "core/editing/EditingUtilities.h" @@ -51,6 +52,7 @@ #include "core/layout/LayoutBlockFlow.h" #include "core/layout/LayoutInline.h" #include "core/layout/LayoutObject.h" +#include "core/layout/LayoutTextFragment.h" #include "core/layout/LayoutView.h" #include "core/layout/line/InlineIterator.h" #include "core/layout/line/InlineTextBox.h" @@ -2149,6 +2151,32 @@ return VisiblePosition(); } +// TODO(yosin): We should use |associatedLayoutObjectOf()| in "VisibleUnits.cpp" +// where it takes |LayoutObject| from |Position|. +static LayoutObject* associatedLayoutObjectOf(const Node& node, int offsetInNode) +{ + ASSERT(offsetInNode >= 0); + LayoutObject* layoutObject = node.layoutObject(); + if (!node.isTextNode() || !layoutObject || !toLayoutText(layoutObject)->isTextFragment()) + return layoutObject; + LayoutTextFragment* layoutTextFragment = toLayoutTextFragment(layoutObject); + if (layoutTextFragment->isRemainingTextLayoutObject()) { + if (static_cast<unsigned>(offsetInNode) >= layoutTextFragment->start()) + return layoutObject; + LayoutObject* firstLetterLayoutObject = layoutTextFragment->firstLetterPseudoElement()->layoutObject(); + if (!firstLetterLayoutObject) + return nullptr; + // TODO(yosin): We're not sure when |firstLetterLayoutObject| has + // multiple child layout object. + ASSERT(firstLetterLayoutObject->slowFirstChild() == firstLetterLayoutObject->slowLastChild()); + return firstLetterLayoutObject->slowFirstChild(); + } + // TODO(yosin): We should rename |LayoutTextFramge::length()| instead of + // |end()|, once |LayoutTextFramge| has it. See http://crbug.com/545789 + ASSERT(static_cast<unsigned>(offsetInNode) <= layoutTextFragment->start() + layoutTextFragment->fragmentLength()); + return layoutTextFragment; +} + template <typename Strategy> static bool inRenderedText(const PositionTemplate<Strategy>& position) { @@ -2156,22 +2184,23 @@ if (!anchorNode || !anchorNode->isTextNode()) return false; - LayoutObject* layoutObject = anchorNode->layoutObject(); + const int offsetInNode = position.computeEditingOffset(); + LayoutObject* layoutObject = associatedLayoutObjectOf(*anchorNode, offsetInNode); if (!layoutObject) return false; - const int offsetInNode = position.computeEditingOffset(); LayoutText* textLayoutObject = toLayoutText(layoutObject); + const int textOffset = offsetInNode - textLayoutObject->textStartOffset(); for (InlineTextBox *box = textLayoutObject->firstTextBox(); box; box = box->nextTextBox()) { - if (offsetInNode < static_cast<int>(box->start()) && !textLayoutObject->containsReversedText()) { + if (textOffset < static_cast<int>(box->start()) && !textLayoutObject->containsReversedText()) { // The offset we're looking for is before this node // this means the offset must be in content that is // not laid out. Return false. return false; } - if (box->containsCaretOffset(offsetInNode)) { + if (box->containsCaretOffset(textOffset)) { // Return false for offsets inside composed characters. - return offsetInNode == 0 || offsetInNode == textLayoutObject->nextOffset(textLayoutObject->previousOffset(offsetInNode)); + return textOffset == 0 || textOffset == textLayoutObject->nextOffset(textLayoutObject->previousOffset(textOffset)); } } @@ -2406,7 +2435,7 @@ return lastVisible.deprecatedComputePosition(); // skip position in non-laid out or invisible node - LayoutObject* layoutObject = currentNode->layoutObject(); + LayoutObject* layoutObject = associatedLayoutObjectOf(*currentNode, currentPos.offsetInLeafNode()); if (!layoutObject || layoutObject->style()->visibility() != VISIBLE) continue; @@ -2433,19 +2462,33 @@ // return current position if it is in laid out text if (layoutObject->isText() && toLayoutText(layoutObject)->firstTextBox()) { + LayoutText* const textLayoutObject = toLayoutText(layoutObject); + const unsigned textStartOffset = textLayoutObject->textStartOffset(); if (currentNode != startNode) { // This assertion fires in layout tests in the case-transform.html test because // of a mix-up between offsets in the text in the DOM tree with text in the // layout tree which can have a different length due to case transformation. // Until we resolve that, disable this so we can run the layout tests! // ASSERT(currentOffset >= layoutObject->caretMaxOffset()); - return PositionTemplate<Strategy>(currentNode, layoutObject->caretMaxOffset()); + return PositionTemplate<Strategy>(currentNode, layoutObject->caretMaxOffset() + textStartOffset); } - unsigned textOffset = currentPos.offsetInLeafNode(); - LayoutText* textLayoutObject = toLayoutText(layoutObject); + // Map offset in DOM node to offset in InlineBox. + ASSERT(currentPos.offsetInLeafNode() >= static_cast<int>(textStartOffset)); + const unsigned textOffset = currentPos.offsetInLeafNode() - textStartOffset; InlineTextBox* lastTextBox = textLayoutObject->lastTextBox(); for (InlineTextBox* box = textLayoutObject->firstTextBox(); box; box = box->nextTextBox()) { + if (textOffset == box->start()) { + if (textLayoutObject->isTextFragment() && toLayoutTextFragment(layoutObject)->isRemainingTextLayoutObject()) { + // |currentPos| is at start of remaining text of + // |Text| node with :first-letter. + ASSERT(currentPos.offsetInLeafNode() >= 1); + LayoutObject* firstLetterLayoutObject = toLayoutTextFragment(layoutObject)->firstLetterPseudoElement()->layoutObject(); + if (firstLetterLayoutObject && firstLetterLayoutObject->style()->visibility() == VISIBLE) + return currentPos.computePosition(); + } + continue; + } if (textOffset <= box->start() + box->len()) { if (textOffset > box->start()) return currentPos.computePosition(); @@ -2543,7 +2586,7 @@ return lastVisible.deprecatedComputePosition(); // skip position in non-laid out or invisible node - LayoutObject* layoutObject = currentNode->layoutObject(); + LayoutObject* layoutObject = associatedLayoutObjectOf(*currentNode, currentPos.offsetInLeafNode()); if (!layoutObject || layoutObject->style()->visibility() != VISIBLE) continue; @@ -2565,13 +2608,16 @@ // return current position if it is in laid out text if (layoutObject->isText() && toLayoutText(layoutObject)->firstTextBox()) { + LayoutText* const textLayoutObject = toLayoutText(layoutObject); + const unsigned textStartOffset = textLayoutObject->textStartOffset(); if (currentNode != startNode) { ASSERT(currentPos.atStartOfNode()); - return PositionTemplate<Strategy>(currentNode, layoutObject->caretMinOffset()); + return PositionTemplate<Strategy>(currentNode, layoutObject->caretMinOffset() + textStartOffset); } - unsigned textOffset = currentPos.offsetInLeafNode(); - LayoutText* textLayoutObject = toLayoutText(layoutObject); + // Map offset in DOM node to offset in InlineBox. + ASSERT(currentPos.offsetInLeafNode() >= static_cast<int>(textStartOffset)); + const unsigned textOffset = currentPos.offsetInLeafNode() - textStartOffset; InlineTextBox* lastTextBox = textLayoutObject->lastTextBox(); for (InlineTextBox* box = textLayoutObject->firstTextBox(); box; box = box->nextTextBox()) { if (textOffset <= box->end()) {
diff --git a/third_party/WebKit/Source/core/editing/VisibleUnitsTest.cpp b/third_party/WebKit/Source/core/editing/VisibleUnitsTest.cpp index 3079616..75a7a8d 100644 --- a/third_party/WebKit/Source/core/editing/VisibleUnitsTest.cpp +++ b/third_party/WebKit/Source/core/editing/VisibleUnitsTest.cpp
@@ -762,6 +762,28 @@ EXPECT_EQ(PositionInComposedTree::lastPositionInNode(host.get()), mostForwardCaretPosition(PositionInComposedTree::afterNode(host.get()))); } +TEST_F(VisibleUnitsTest, mostBackwardCaretPositionFirstLetter) +{ + // Note: first-letter pseudo element contains letter and punctuations. + const char* bodyContent = "<style>p:first-letter {color:red;}</style><p id=sample> (2)45 </p>"; + setBodyContent(bodyContent); + updateLayoutAndStyleForPainting(); + + Node* sample = document().getElementById("sample")->firstChild(); + + EXPECT_EQ(Position(sample->parentNode(), 0), mostBackwardCaretPosition(Position(sample, 0))); + EXPECT_EQ(Position(sample->parentNode(), 0), mostBackwardCaretPosition(Position(sample, 1))); + EXPECT_EQ(Position(sample, 2), mostBackwardCaretPosition(Position(sample, 2))); + EXPECT_EQ(Position(sample, 3), mostBackwardCaretPosition(Position(sample, 3))); + EXPECT_EQ(Position(sample, 4), mostBackwardCaretPosition(Position(sample, 4))); + EXPECT_EQ(Position(sample, 5), mostBackwardCaretPosition(Position(sample, 5))); + EXPECT_EQ(Position(sample, 6), mostBackwardCaretPosition(Position(sample, 6))); + EXPECT_EQ(Position(sample, 6), mostBackwardCaretPosition(Position(sample, 7))); + EXPECT_EQ(Position(sample, 6), mostBackwardCaretPosition(Position::lastPositionInNode(sample->parentNode()))); + EXPECT_EQ(Position(sample, 6), mostBackwardCaretPosition(Position::afterNode(sample->parentNode()))); + EXPECT_EQ(Position::lastPositionInNode(document().body()), mostBackwardCaretPosition(Position::lastPositionInNode(document().body()))); +} + TEST_F(VisibleUnitsTest, mostForwardCaretPositionAfterAnchor) { const char* bodyContent = "<p id='host'><b id='one'>1</b></p>"; @@ -778,6 +800,28 @@ EXPECT_EQ(PositionInComposedTree(three->firstChild(), 3), mostBackwardCaretPosition(PositionInComposedTree::afterNode(host.get()))); } +TEST_F(VisibleUnitsTest, mostForwardCaretPositionFirstLetter) +{ + // Note: first-letter pseudo element contains letter and punctuations. + const char* bodyContent = "<style>p:first-letter {color:red;}</style><p id=sample> (2)45 </p>"; + setBodyContent(bodyContent); + updateLayoutAndStyleForPainting(); + + Node* sample = document().getElementById("sample")->firstChild(); + + EXPECT_EQ(Position(document().body(), 0), mostForwardCaretPosition(Position::firstPositionInNode(document().body()))); + EXPECT_EQ(Position(sample, 1), mostForwardCaretPosition(Position::beforeNode(sample->parentNode()))); + EXPECT_EQ(Position(sample, 1), mostForwardCaretPosition(Position::firstPositionInNode(sample->parentNode()))); + EXPECT_EQ(Position(sample, 1), mostForwardCaretPosition(Position(sample, 0))); + EXPECT_EQ(Position(sample, 1), mostForwardCaretPosition(Position(sample, 1))); + EXPECT_EQ(Position(sample, 2), mostForwardCaretPosition(Position(sample, 2))); + EXPECT_EQ(Position(sample, 3), mostForwardCaretPosition(Position(sample, 3))); + EXPECT_EQ(Position(sample, 4), mostForwardCaretPosition(Position(sample, 4))); + EXPECT_EQ(Position(sample, 5), mostForwardCaretPosition(Position(sample, 5))); + EXPECT_EQ(Position(sample, 7), mostForwardCaretPosition(Position(sample, 6))); + EXPECT_EQ(Position(sample, 7), mostForwardCaretPosition(Position(sample, 7))); +} + TEST_F(VisibleUnitsTest, nextPositionOf) { const char* bodyContent = "<b id=zero>0</b><p id=host><b id=one>1</b><b id=two>22</b></p><b id=three>333</b>";
diff --git a/third_party/WebKit/Source/core/frame/UseCounter.h b/third_party/WebKit/Source/core/frame/UseCounter.h index b7de419d..f600654 100644 --- a/third_party/WebKit/Source/core/frame/UseCounter.h +++ b/third_party/WebKit/Source/core/frame/UseCounter.h
@@ -861,6 +861,8 @@ HTMLLabelElementFormContentAttribute = 986, DeviceOrientationAbsoluteInsecureOrigin = 987, DeviceOrientationAbsoluteSecureOrigin = 988, + FontFaceConstructor = 989, + ServiceWorkerControlledPage = 990, // Add new features immediately above this line. Don't change assigned // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/WebKit/Source/core/html/HTMLElement.cpp b/third_party/WebKit/Source/core/html/HTMLElement.cpp index fb1a964..c85256a 100644 --- a/third_party/WebKit/Source/core/html/HTMLElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLElement.cpp
@@ -72,8 +72,21 @@ DEFINE_ELEMENT_FACTORY_WITH_TAGNAME(HTMLElement); +String HTMLElement::debugNodeName() const +{ + if (document().isHTMLDocument()) { + return tagQName().hasPrefix() + ? Element::nodeName().upper() + : tagQName().localName().upper(); + } + return Element::nodeName(); +} + String HTMLElement::nodeName() const { + // localNameUpper may intern and cache an AtomicString. + RELEASE_ASSERT(isMainThread()); + // FIXME: Would be nice to have an atomicstring lookup based off uppercase // chars that does not have to copy the string on a hit in the hash. // FIXME: We should have a way to detect XHTML elements and replace the hasPrefix() check with it.
diff --git a/third_party/WebKit/Source/core/html/HTMLElement.h b/third_party/WebKit/Source/core/html/HTMLElement.h index 333cd66b..eeb2c34 100644 --- a/third_party/WebKit/Source/core/html/HTMLElement.h +++ b/third_party/WebKit/Source/core/html/HTMLElement.h
@@ -121,6 +121,7 @@ void calculateAndAdjustDirectionality(); private: + String debugNodeName() const final; String nodeName() const final; bool isHTMLElement() const = delete; // This will catch anyone doing an unnecessary check.
diff --git a/third_party/WebKit/Source/core/layout/LayoutTextFragment.h b/third_party/WebKit/Source/core/layout/LayoutTextFragment.h index d5e0368..d4c6198 100644 --- a/third_party/WebKit/Source/core/layout/LayoutTextFragment.h +++ b/third_party/WebKit/Source/core/layout/LayoutTextFragment.h
@@ -44,6 +44,7 @@ bool canBeSelectionLeaf() const override { return node() && node()->hasEditableStyle(); } unsigned start() const { return m_start; } + unsigned fragmentLength() const { return m_fragmentLength; } unsigned textStartOffset() const override { return start(); } @@ -80,7 +81,6 @@ Text* associatedTextNode() const; void updateHitTestResult(HitTestResult&, const LayoutPoint&) override; - unsigned fragmentLength() const { return m_fragmentLength; } unsigned m_start; unsigned m_fragmentLength;
diff --git a/third_party/WebKit/Source/devtools/devtools.gypi b/third_party/WebKit/Source/devtools/devtools.gypi index 3a4f6dd..82c2807 100644 --- a/third_party/WebKit/Source/devtools/devtools.gypi +++ b/third_party/WebKit/Source/devtools/devtools.gypi
@@ -192,7 +192,6 @@ 'front_end/bindings/SASSSourceMapping.js', 'front_end/bindings/StylesSourceMapping.js', 'front_end/bindings/TempFile.js', - 'front_end/bindings/WorkspaceController.js', ], 'devtools_platform_js_files': [ 'front_end/platform/DOMExtension.js',
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/FileSystemWorkspaceBinding.js b/third_party/WebKit/Source/devtools/front_end/bindings/FileSystemWorkspaceBinding.js index d4e51a1..d8e69f0e 100644 --- a/third_party/WebKit/Source/devtools/front_end/bindings/FileSystemWorkspaceBinding.js +++ b/third_party/WebKit/Source/devtools/front_end/bindings/FileSystemWorkspaceBinding.js
@@ -39,6 +39,7 @@ this._workspace = workspace; this._isolatedFileSystemManager.addEventListener(WebInspector.IsolatedFileSystemManager.Events.FileSystemAdded, this._fileSystemAdded, this); this._isolatedFileSystemManager.addEventListener(WebInspector.IsolatedFileSystemManager.Events.FileSystemRemoved, this._fileSystemRemoved, this); + this._isolatedFileSystemManager.addEventListener(WebInspector.IsolatedFileSystemManager.Events.FileSystemFilesChanged, this._fileSystemFilesChanged, this); /** @type {!Map.<string, !WebInspector.FileSystemWorkspaceBinding.FileSystem>} */ this._boundFileSystems = new Map(); @@ -98,6 +99,22 @@ }, /** + * @param {!WebInspector.Event} event + */ + _fileSystemFilesChanged: function(event) + { + var paths = /** @type {!Array<string>} */ (event.data); + for (var path of paths) { + var normalizedPath = WebInspector.IsolatedFileSystem.normalizePath(path); + for (var key of this._boundFileSystems.keys()) { + if (!normalizedPath.startsWith(key)) + continue; + this._boundFileSystems.get(key)._fileChanged(normalizedPath.substr(key.length + 1)); + } + } + }, + + /** * @param {string} projectId * @return {string} */ @@ -233,7 +250,7 @@ this._projectId = WebInspector.FileSystemWorkspaceBinding.projectId(this._fileSystem.path()); console.assert(!this._workspace.project(this._projectId)); - this._workspace.addProject(this._projectId, this); + this._project = this._workspace.addProject(this._projectId, this); this.populate(); } @@ -617,6 +634,19 @@ this.dispatchEventToListeners(WebInspector.ProjectDelegate.Events.FileRemoved, path); }, + /** + * @param {string} path + */ + _fileChanged: function(path) + { + var uiSourceCode = this._project.uiSourceCode(path); + if (!uiSourceCode) { + this._addFile(path); + return; + } + this.dispatchEventToListeners(WebInspector.ProjectDelegate.Events.FileChanged, path); + }, + dispose: function() { this._workspace.removeProject(this._projectId);
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/WorkspaceController.js b/third_party/WebKit/Source/devtools/front_end/bindings/WorkspaceController.js deleted file mode 100644 index 495aee6..0000000 --- a/third_party/WebKit/Source/devtools/front_end/bindings/WorkspaceController.js +++ /dev/null
@@ -1,63 +0,0 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @constructor - * @suppressGlobalPropertiesCheck - */ -WebInspector.WorkspaceController = function(workspace) -{ - this._workspace = workspace; - // Only for main window. - window.addEventListener("focus", this._windowFocused.bind(this), false); - this._fileSystemRefreshThrottler = new WebInspector.Throttler(1000); -} - -WebInspector.WorkspaceController.prototype = { - /** - * @param {!Event} event - */ - _windowFocused: function(event) - { - this._fileSystemRefreshThrottler.schedule(refreshFileSystems.bind(this)); - - /** - * @this {WebInspector.WorkspaceController} - */ - function refreshFileSystems() - { - var barrier = new CallbackBarrier(); - var projects = this._workspace.projects(); - for (var i = 0; i < projects.length; ++i) - projects[i].refresh("/", barrier.createCallback()); - return barrier.donePromise(); - } - } -}
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/module.json b/third_party/WebKit/Source/devtools/front_end/bindings/module.json index a7da14c..4f2b5be 100644 --- a/third_party/WebKit/Source/devtools/front_end/bindings/module.json +++ b/third_party/WebKit/Source/devtools/front_end/bindings/module.json
@@ -19,7 +19,6 @@ "PresentationConsoleMessageHelper.js", "ResourceUtils.js", "TempFile.js", - "WorkspaceController.js", "ContentScriptProjectDecorator.js" ] }
diff --git a/third_party/WebKit/Source/devtools/front_end/console/ConsoleViewMessage.js b/third_party/WebKit/Source/devtools/front_end/console/ConsoleViewMessage.js index 8c28906..df94691 100644 --- a/third_party/WebKit/Source/devtools/front_end/console/ConsoleViewMessage.js +++ b/third_party/WebKit/Source/devtools/front_end/console/ConsoleViewMessage.js
@@ -45,8 +45,6 @@ /** @type {!Array.<!WebInspector.DataGrid>} */ this._dataGrids = []; - /** @type {!Map.<!WebInspector.DataGrid, ?Element>} */ - this._dataGridParents = new Map(); /** @type {!Object.<string, function(!WebInspector.RemoteObject, !Element, boolean=)>} */ this._customFormatters = { @@ -88,12 +86,8 @@ */ wasShown: function() { - for (var i = 0; this._dataGrids && i < this._dataGrids.length; ++i) { - var dataGrid = this._dataGrids[i]; - var parentElement = this._dataGridParents.get(dataGrid) || null; - parentElement.appendChild(dataGrid.element); - dataGrid.updateWidths(); - } + for (var i = 0; this._dataGrids && i < this._dataGrids.length; ++i) + this._dataGrids[i].updateWidths(); this._isVisible = true; }, @@ -108,22 +102,10 @@ /** * @override */ - cacheFastHeight: function() - { - this._cachedHeight = this.contentElement().offsetHeight; - }, - - /** - * @override - */ willHide: function() { this._isVisible = false; - for (var i = 0; this._dataGrids && i < this._dataGrids.length; ++i) { - var dataGrid = this._dataGrids[i]; - this._dataGridParents.set(dataGrid, dataGrid.element.parentElement); - dataGrid.element.remove(); - } + this._cachedHeight = this.contentElement().offsetHeight; }, /** @@ -607,8 +589,8 @@ columnNames.unshift(WebInspector.UIString("(index)")); var dataGrid = WebInspector.SortableDataGrid.create(columnNames, flatValues); dataGrid.renderInline(); + dataGridContainer.appendChild(dataGrid.element); this._dataGrids.push(dataGrid); - this._dataGridParents.set(dataGrid, dataGridContainer); return element; },
diff --git a/third_party/WebKit/Source/devtools/front_end/devtools.js b/third_party/WebKit/Source/devtools/front_end/devtools.js index 671aac0f..000b533fa 100644 --- a/third_party/WebKit/Source/devtools/front_end/devtools.js +++ b/third_party/WebKit/Source/devtools/front_end/devtools.js
@@ -176,6 +176,11 @@ this._dispatchOnInspectorFrontendAPI("fileSystemAdded", ["", fileSystem]); }, + fileSystemFilesChanged: function(path) + { + this._dispatchOnInspectorFrontendAPI("fileSystemFilesChanged", [path]); + }, + /** * @param {number} requestId * @param {string} fileSystemPath
diff --git a/third_party/WebKit/Source/devtools/front_end/host/InspectorFrontendHostAPI.js b/third_party/WebKit/Source/devtools/front_end/host/InspectorFrontendHostAPI.js index 34f2075..4b38146 100644 --- a/third_party/WebKit/Source/devtools/front_end/host/InspectorFrontendHostAPI.js +++ b/third_party/WebKit/Source/devtools/front_end/host/InspectorFrontendHostAPI.js
@@ -42,6 +42,7 @@ FileSystemsLoaded: "fileSystemsLoaded", FileSystemRemoved: "fileSystemRemoved", FileSystemAdded: "fileSystemAdded", + FileSystemFilesChanged: "fileSystemFilesChanged", FrontendAPIAttached: "frontendAPIAttached", FrontendAPIDetached: "frontendAPIDetached", IndexingTotalWorkCalculated: "indexingTotalWorkCalculated", @@ -73,6 +74,7 @@ [InspectorFrontendHostAPI.Events.FileSystemsLoaded, ["fileSystems"]], [InspectorFrontendHostAPI.Events.FileSystemRemoved, ["fileSystemPath"]], [InspectorFrontendHostAPI.Events.FileSystemAdded, ["errorMessage", "fileSystem"]], + [InspectorFrontendHostAPI.Events.FileSystemFilesChanged, ["paths"]], [InspectorFrontendHostAPI.Events.FrontendAPIAttached, ["frontendAPIAttached"]], [InspectorFrontendHostAPI.Events.FrontendAPIDetached, ["frontendAPIDetached"]], [InspectorFrontendHostAPI.Events.IndexingTotalWorkCalculated, ["requestId", "fileSystemPath", "totalWork"]],
diff --git a/third_party/WebKit/Source/devtools/front_end/main/Main.js b/third_party/WebKit/Source/devtools/front_end/main/Main.js index 41ea1365..2c7918e 100644 --- a/third_party/WebKit/Source/devtools/front_end/main/Main.js +++ b/third_party/WebKit/Source/devtools/front_end/main/Main.js
@@ -230,7 +230,6 @@ WebInspector.openAnchorLocationRegistry.registerHandler(autoselectPanel, function() { return false; }); WebInspector.Linkifier.setLinkHandler(new WebInspector.HandlerRegistry.LinkHandler()); - new WebInspector.WorkspaceController(WebInspector.workspace); new WebInspector.Main.PauseListener(); new WebInspector.Main.InspectedNodeRevealer(); new WebInspector.NetworkPanelIndicator();
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/timelineStatusDialog.css b/third_party/WebKit/Source/devtools/front_end/timeline/timelineStatusDialog.css index e5ffd8b..83a6023 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/timelineStatusDialog.css +++ b/third_party/WebKit/Source/devtools/front_end/timeline/timelineStatusDialog.css
@@ -15,9 +15,11 @@ margin-top: -1px; } -.timeline-status-dialog div { +.timeline-status-dialog > div { margin: 2px; height: 14px; + display: flex; + align-items: baseline; } .timeline-status-dialog ::before { @@ -57,7 +59,7 @@ } .timeline-status-dialog .stop-button { - text-align: center; margin-top: 8px; height: 100%; + align-self: center; }
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/ViewportControl.js b/third_party/WebKit/Source/devtools/front_end/ui/ViewportControl.js index 943aba3f..b9de04d 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/ViewportControl.js +++ b/third_party/WebKit/Source/devtools/front_end/ui/ViewportControl.js
@@ -94,8 +94,6 @@ */ WebInspector.ViewportElement = function() { } WebInspector.ViewportElement.prototype = { - cacheFastHeight: function() { }, - willHide: function() { }, wasShown: function() { }, @@ -120,11 +118,6 @@ /** * @override */ - cacheFastHeight: function() { }, - - /** - * @override - */ willHide: function() { }, /** @@ -223,10 +216,17 @@ var itemCount = this._provider.itemCount(); if (!itemCount) return; + var firstVisibleIndex = this._firstVisibleIndex; + var lastVisibleIndex = this._lastVisibleIndex; + var height = 0; this._cumulativeHeights = new Int32Array(itemCount); - this._cumulativeHeights[0] = this._provider.fastHeight(0); - for (var i = 1; i < itemCount; ++i) - this._cumulativeHeights[i] = this._cumulativeHeights[i - 1] + this._provider.fastHeight(i); + for (var i = 0; i < itemCount; ++i) { + if (firstVisibleIndex <= i && i <= lastVisibleIndex) + height += this._renderedItems[i - firstVisibleIndex].element().offsetHeight; + else + height += this._provider.fastHeight(i); + this._cumulativeHeights[i] = height; + } }, /** @@ -376,8 +376,6 @@ var itemCount = this._provider.itemCount(); if (!itemCount) { for (var i = 0; i < this._renderedItems.length; ++i) - this._renderedItems[i].cacheFastHeight(); - for (var i = 0; i < this._renderedItems.length; ++i) this._renderedItems[i].willHide(); this._renderedItems = []; this._contentElement.removeChildren(); @@ -399,9 +397,8 @@ if (this._cumulativeHeights && itemCount !== this._cumulativeHeights.length) delete this._cumulativeHeights; for (var i = 0; i < this._renderedItems.length; ++i) { - this._renderedItems[i].cacheFastHeight(); // Tolerate 1-pixel error due to double-to-integer rounding errors. - if (this._cumulativeHeights && Math.abs(this._cachedItemHeight(this._firstVisibleIndex + i) - this._provider.fastHeight(i + this._firstVisibleIndex)) > 1) + if (this._cumulativeHeights && Math.abs(this._cachedItemHeight(this._firstVisibleIndex + i) - this._renderedItems[i].element().offsetHeight) > 1) delete this._cumulativeHeights; } this._rebuildCumulativeHeightsIfNeeded(); @@ -421,16 +418,22 @@ var topGapHeight = this._cumulativeHeights[this._firstVisibleIndex - 1] || 0; var bottomGapHeight = this._cumulativeHeights[this._cumulativeHeights.length - 1] - this._cumulativeHeights[this._lastVisibleIndex]; - this._topGapElement.style.height = topGapHeight + "px"; - this._bottomGapElement.style.height = bottomGapHeight + "px"; - this._topGapElement._active = !!topGapHeight; - this._bottomGapElement._active = !!bottomGapHeight; + /** + * @this {WebInspector.ViewportControl} + */ + function prepare() + { + this._topGapElement.style.height = topGapHeight + "px"; + this._bottomGapElement.style.height = bottomGapHeight + "px"; + this._topGapElement._active = !!topGapHeight; + this._bottomGapElement._active = !!bottomGapHeight; + this._contentElement.style.setProperty("height", "10000000px"); + } - this._contentElement.style.setProperty("height", "10000000px"); if (isInvalidating) - this._fullViewportUpdate(); + this._fullViewportUpdate(prepare.bind(this)); else - this._partialViewportUpdate(oldFirstVisibleIndex, oldLastVisibleIndex); + this._partialViewportUpdate(oldFirstVisibleIndex, oldLastVisibleIndex, prepare.bind(this)); this._contentElement.style.removeProperty("height"); // Should be the last call in the method as it might force layout. if (shouldRestoreSelection) @@ -439,25 +442,31 @@ this.element.scrollTop = this.element.scrollHeight; }, - _fullViewportUpdate: function() + /** + * @param {function()} prepare + */ + _fullViewportUpdate: function(prepare) { for (var i = 0; i < this._renderedItems.length; ++i) this._renderedItems[i].willHide(); + prepare(); this._renderedItems = []; this._contentElement.removeChildren(); for (var i = this._firstVisibleIndex; i <= this._lastVisibleIndex; ++i) { var viewportElement = this._providerElement(i); this._contentElement.appendChild(viewportElement.element()); this._renderedItems.push(viewportElement); - viewportElement.wasShown(); } + for (var i = 0; i < this._renderedItems.length; ++i) + this._renderedItems[i].wasShown(); }, /** * @param {number} oldFirstVisibleIndex * @param {number} oldLastVisibleIndex + * @param {function()} prepare */ - _partialViewportUpdate: function(oldFirstVisibleIndex, oldLastVisibleIndex) + _partialViewportUpdate: function(oldFirstVisibleIndex, oldLastVisibleIndex, prepare) { var willBeHidden = []; for (var i = 0; i < this._renderedItems.length; ++i) { @@ -467,22 +476,26 @@ } for (var i = 0; i < willBeHidden.length; ++i) willBeHidden[i].willHide(); + prepare(); for (var i = 0; i < willBeHidden.length; ++i) willBeHidden[i].element().remove(); this._renderedItems = []; var anchor = this._contentElement.firstChild; + var wasShown = []; for (var i = this._firstVisibleIndex; i <= this._lastVisibleIndex; ++i) { var viewportElement = this._providerElement(i); var element = viewportElement.element(); if (element !== anchor) { this._contentElement.insertBefore(element, anchor); - viewportElement.wasShown(); + wasShown.push(viewportElement); } else { anchor = anchor.nextSibling; } this._renderedItems.push(viewportElement); } + for (var i = 0; i < wasShown.length; ++i) + wasShown[i].wasShown(); }, /**
diff --git a/third_party/WebKit/Source/devtools/front_end/workspace/IsolatedFileSystemManager.js b/third_party/WebKit/Source/devtools/front_end/workspace/IsolatedFileSystemManager.js index f26ac30..5869e611 100644 --- a/third_party/WebKit/Source/devtools/front_end/workspace/IsolatedFileSystemManager.js +++ b/third_party/WebKit/Source/devtools/front_end/workspace/IsolatedFileSystemManager.js
@@ -40,6 +40,7 @@ InspectorFrontendHost.events.addEventListener(InspectorFrontendHostAPI.Events.FileSystemsLoaded, this._onFileSystemsLoaded, this); InspectorFrontendHost.events.addEventListener(InspectorFrontendHostAPI.Events.FileSystemRemoved, this._onFileSystemRemoved, this); InspectorFrontendHost.events.addEventListener(InspectorFrontendHostAPI.Events.FileSystemAdded, this._onFileSystemAdded, this); + InspectorFrontendHost.events.addEventListener(InspectorFrontendHostAPI.Events.FileSystemFilesChanged, this._onFileSystemFilesChanged, this); this._initExcludePatterSetting(); } @@ -51,6 +52,7 @@ FileSystemAdded: "FileSystemAdded", FileSystemRemoved: "FileSystemRemoved", FileSystemsLoaded: "FileSystemsLoaded", + FileSystemFilesChanged: "FileSystemFilesChanged", ExcludedFolderAdded: "ExcludedFolderAdded", ExcludedFolderRemoved: "ExcludedFolderRemoved" } @@ -156,6 +158,14 @@ }, /** + * @param {!WebInspector.Event} event + */ + _onFileSystemFilesChanged: function(event) + { + this.dispatchEventToListeners(WebInspector.IsolatedFileSystemManager.Events.FileSystemFilesChanged, event.data); + }, + + /** * @param {string} fileSystemPath */ _fileSystemRemoved: function(fileSystemPath)
diff --git a/third_party/WebKit/Source/devtools/front_end/workspace/Workspace.js b/third_party/WebKit/Source/devtools/front_end/workspace/Workspace.js index 9f0b8a9..10de8f5 100644 --- a/third_party/WebKit/Source/devtools/front_end/workspace/Workspace.js +++ b/third_party/WebKit/Source/devtools/front_end/workspace/Workspace.js
@@ -85,6 +85,7 @@ WebInspector.ProjectDelegate.Events = { FileAdded: "FileAdded", FileRemoved: "FileRemoved", + FileChanged: "FileChanged" } WebInspector.ProjectDelegate.prototype = { @@ -208,6 +209,7 @@ this._displayName = this._projectDelegate.displayName(); projectDelegate.addEventListener(WebInspector.ProjectDelegate.Events.FileAdded, this._fileAdded, this); projectDelegate.addEventListener(WebInspector.ProjectDelegate.Events.FileRemoved, this._fileRemoved, this); + projectDelegate.addEventListener(WebInspector.ProjectDelegate.Events.FileChanged, this._fileChanged, this); } /** @@ -298,6 +300,17 @@ }, /** + * @param {!WebInspector.Event} event + */ + _fileChanged: function(event) + { + var path = /** @type {string} */ (event.data); + var uiSourceCode = this.uiSourceCode(path); + if (uiSourceCode && uiSourceCode.contentLoaded()) + uiSourceCode.checkContentUpdated(); + }, + + /** * @param {string} path */ _removeFile: function(path)
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothAdvertisingData.cpp b/third_party/WebKit/Source/modules/bluetooth/BluetoothAdvertisingData.cpp new file mode 100644 index 0000000..89d94fd --- /dev/null +++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothAdvertisingData.cpp
@@ -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. + +#include "config.h" +#include "modules/bluetooth/BluetoothAdvertisingData.h" + +namespace blink { + +namespace { +// TODO(ortuno): RSSI Unknown and Tx Power Unknown should have different +// values. Add kUnknownTxPower when implemented: http://crbug.com/551572 +const int kUnknownPower = 127; +} // namespace + +BluetoothAdvertisingData* BluetoothAdvertisingData::create(int8_t txPower, int8_t rssi) +{ + return new BluetoothAdvertisingData(txPower, rssi); +} + +int8_t BluetoothAdvertisingData::txPower(bool& isNull) +{ + if (m_txPower == kUnknownPower) { + isNull = true; + } + return m_txPower; +} + +int8_t BluetoothAdvertisingData::rssi(bool& isNull) +{ + if (m_rssi == kUnknownPower) { + isNull = true; + } + return m_rssi; +} + +BluetoothAdvertisingData::BluetoothAdvertisingData(int8_t txPower, int8_t rssi) + : m_txPower(txPower) + , m_rssi(rssi) +{ +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothAdvertisingData.h b/third_party/WebKit/Source/modules/bluetooth/BluetoothAdvertisingData.h new file mode 100644 index 0000000..4aef9b8 --- /dev/null +++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothAdvertisingData.h
@@ -0,0 +1,37 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BluetoothAdvertisingData_h +#define BluetoothAdvertisingData_h + +#include "bindings/core/v8/ScriptWrappable.h" +#include "platform/heap/Handle.h" + +namespace blink { + +// Represents the data a BLE device is advertising. +class BluetoothAdvertisingData final + : public GarbageCollected<BluetoothAdvertisingData> + , public ScriptWrappable { + DEFINE_WRAPPERTYPEINFO(); +public: + static BluetoothAdvertisingData* create(int8_t txPower, int8_t rssi); + + // IDL exposed interface: + int8_t txPower(bool& isNull); + int8_t rssi(bool& isNull); + + // Interface required by garbage collection. + DEFINE_INLINE_TRACE() { } + +private: + explicit BluetoothAdvertisingData(int8_t txPower, int8_t rssi); + + int8_t m_txPower; + int8_t m_rssi; +}; + +} // namespace blink + +#endif // BluetoothAdvertisingData_h
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothAdvertisingData.idl b/third_party/WebKit/Source/modules/bluetooth/BluetoothAdvertisingData.idl new file mode 100644 index 0000000..6e0454d0 --- /dev/null +++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothAdvertisingData.idl
@@ -0,0 +1,18 @@ +// 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. + +// https://webbluetoothcg.github.io/web-bluetooth/#bluetoothadvertisingdata + +// Implement BluetoothAdvertisingData interface: http://crbug.com/542756 + +[ + GarbageCollected, + RuntimeEnabled=WebBluetooth, +] interface BluetoothAdvertisingData { + // readonly attribute unsigned short? appearance; + readonly attribute byte? txPower; + readonly attribute byte? rssi; + // readonly attribute ManufacturerDataMap manufacturerData; + // readonly attribute ServiceDataMap serviceData; +};
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothDevice.cpp b/third_party/WebKit/Source/modules/bluetooth/BluetoothDevice.cpp index da50dfd4..2129c98 100644 --- a/third_party/WebKit/Source/modules/bluetooth/BluetoothDevice.cpp +++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothDevice.cpp
@@ -19,6 +19,8 @@ BluetoothDevice::BluetoothDevice(PassOwnPtr<WebBluetoothDevice> webDevice) : m_webDevice(webDevice) + , m_adData(BluetoothAdvertisingData::create(m_webDevice->txPower, + m_webDevice->rssi)) { } @@ -28,6 +30,11 @@ return new BluetoothDevice(webDevice); } +DEFINE_TRACE(BluetoothDevice) +{ + visitor->trace(m_adData); +} + unsigned BluetoothDevice::deviceClass(bool& isNull) { isNull = false;
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothDevice.h b/third_party/WebKit/Source/modules/bluetooth/BluetoothDevice.h index 096cda7..a0ec5db 100644 --- a/third_party/WebKit/Source/modules/bluetooth/BluetoothDevice.h +++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothDevice.h
@@ -6,6 +6,7 @@ #define BluetoothDevice_h #include "bindings/core/v8/ScriptWrappable.h" +#include "modules/bluetooth/BluetoothAdvertisingData.h" #include "platform/heap/Heap.h" #include "public/platform/modules/bluetooth/WebBluetoothDevice.h" #include "wtf/OwnPtr.h" @@ -38,11 +39,12 @@ static BluetoothDevice* take(ScriptPromiseResolver*, PassOwnPtr<WebBluetoothDevice>); // Interface required by Garbage Collection: - DEFINE_INLINE_TRACE() { } + DECLARE_VIRTUAL_TRACE(); // IDL exposed interface: String id() { return m_webDevice->id; } String name() { return m_webDevice->name; } + BluetoothAdvertisingData* adData() { return m_adData; } unsigned deviceClass(bool& isNull); String vendorIDSource(); unsigned vendorID(bool& isNull); @@ -53,6 +55,7 @@ private: OwnPtr<WebBluetoothDevice> m_webDevice; + Member<BluetoothAdvertisingData> m_adData; }; } // namespace blink
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothDevice.idl b/third_party/WebKit/Source/modules/bluetooth/BluetoothDevice.idl index 03c25e06..86ad3a9 100644 --- a/third_party/WebKit/Source/modules/bluetooth/BluetoothDevice.idl +++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothDevice.idl
@@ -22,7 +22,7 @@ [DeprecateAs=BluetoothDeviceInstanceId, ImplementedAs=id] readonly attribute DOMString instanceID; readonly attribute DOMString id; readonly attribute DOMString? name; -// readonly attribute BluetoothAdvertisingData adData; + readonly attribute BluetoothAdvertisingData adData; readonly attribute unsigned long? deviceClass; readonly attribute VendorIDSource? vendorIDSource; readonly attribute unsigned long? vendorID;
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.idl b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.idl index b830fb9..e385a17 100644 --- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.idl +++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.idl
@@ -58,7 +58,7 @@ // compositing attribute unrestricted float globalAlpha; // (default 1.0) - [TreatNullAs=NullString] attribute DOMString globalCompositeOperation; // (default source-over) + attribute DOMString globalCompositeOperation; // (default source-over) [RuntimeEnabled=ExperimentalCanvasFeatures] attribute DOMString filter; // (default 'none') // image smoothing @@ -77,7 +77,7 @@ attribute unrestricted float shadowOffsetX; attribute unrestricted float shadowOffsetY; attribute unrestricted float shadowBlur; - [TreatNullAs=NullString] attribute DOMString shadowColor; + attribute DOMString shadowColor; // rects void clearRect(unrestricted float x, unrestricted float y, unrestricted float width, unrestricted float height); @@ -133,8 +133,8 @@ // FIXME: factor out to CanvasDrawingStyles // line caps/joins attribute unrestricted float lineWidth; // (default 1) - [TreatNullAs=NullString] attribute DOMString lineCap; // "butt", "round", "square" (default "butt") - [TreatNullAs=NullString] attribute DOMString lineJoin; // "round", "bevel", "miter" (default "miter") + attribute DOMString lineCap; // "butt", "round", "square" (default "butt") + attribute DOMString lineJoin; // "round", "bevel", "miter" (default "miter") attribute unrestricted float miterLimit; // (default 10) // dashed lines
diff --git a/third_party/WebKit/Source/modules/modules.gypi b/third_party/WebKit/Source/modules/modules.gypi index 0c4d52c5..09e47ff09 100644 --- a/third_party/WebKit/Source/modules/modules.gypi +++ b/third_party/WebKit/Source/modules/modules.gypi
@@ -24,6 +24,7 @@ 'background_sync/SyncRegistration.idl', 'battery/BatteryManager.idl', 'bluetooth/Bluetooth.idl', + 'bluetooth/BluetoothAdvertisingData.idl', 'bluetooth/BluetoothDevice.idl', 'bluetooth/BluetoothCharacteristicProperties.idl', 'bluetooth/BluetoothGATTCharacteristic.idl', @@ -792,6 +793,8 @@ 'bluetooth/ConvertWebVectorToArrayBuffer.cpp', 'bluetooth/ConvertWebVectorToArrayBuffer.h', 'bluetooth/Bluetooth.cpp', + 'bluetooth/BluetoothAdvertisingData.cpp', + 'bluetooth/BluetoothAdvertisingData.h', 'bluetooth/BluetoothCharacteristicProperties.cpp', 'bluetooth/BluetoothCharacteristicProperties.h', 'bluetooth/BluetoothDevice.cpp',
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainer.cpp b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainer.cpp index 09518f7..136a0850 100644 --- a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainer.cpp +++ b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainer.cpp
@@ -42,6 +42,7 @@ #include "core/dom/ExecutionContext.h" #include "core/dom/MessagePort.h" #include "core/frame/LocalDOMWindow.h" +#include "core/frame/UseCounter.h" #include "modules/EventTargetModules.h" #include "modules/serviceworkers/ServiceWorker.h" #include "modules/serviceworkers/ServiceWorkerContainerClient.h" @@ -358,6 +359,8 @@ if (!executionContext()) return; m_controller = ServiceWorker::from(executionContext(), handle.release()); + if (m_controller) + UseCounter::count(executionContext(), UseCounter::ServiceWorkerControlledPage); if (shouldNotifyControllerChange) dispatchEvent(Event::create(EventTypeNames::controllerchange)); }
diff --git a/third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothDevice.h b/third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothDevice.h index 76534e5..e2d97b5 100644 --- a/third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothDevice.h +++ b/third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothDevice.h
@@ -20,6 +20,8 @@ WebBluetoothDevice(const WebString& id, const WebString& name, + int8_t txPower, + int8_t rssi, int32_t deviceClass, VendorIDSource vendorIDSource, uint16_t vendorID, @@ -29,6 +31,8 @@ const WebVector<WebString>& uuids) : id(id) , name(name) + , txPower(txPower) + , rssi(rssi) , deviceClass(deviceClass) , vendorIDSource(vendorIDSource) , vendorID(vendorID) @@ -42,6 +46,10 @@ // Members corresponding to BluetoothDevice attributes as specified in IDL. const WebString id; const WebString name; + // Powers: + // A value of 127 denotes an invalid power. + const int8_t txPower; + const int8_t rssi; const int32_t deviceClass; const VendorIDSource vendorIDSource; const uint16_t vendorID;
diff --git a/third_party/errorprone/BUILD.gn b/third_party/errorprone/BUILD.gn index 8274bfb..6795c5a 100644 --- a/third_party/errorprone/BUILD.gn +++ b/third_party/errorprone/BUILD.gn
@@ -37,5 +37,5 @@ main_class = "com.google.errorprone.ErrorProneCompiler" # TODO(mikecase): Remove this extra arg when the bots are on jdk8 or higher. - extra_java_args = "-Xbootclasspath/p:$target_gen_dir/javac_java.jar" + bootclasspath = "$target_gen_dir/javac_java.jar" }
diff --git a/third_party/errorprone/errorprone.gyp b/third_party/errorprone/errorprone.gyp index 4a1f6a1..67de7684 100644 --- a/third_party/errorprone/errorprone.gyp +++ b/third_party/errorprone/errorprone.gyp
@@ -84,7 +84,7 @@ 'python', '<(DEPTH)/build/android/gyp/create_java_binary_script.py', '--output', '<(PRODUCT_DIR)/bin.java/chromium_errorprone', # TODO(mikecase): Remove this extra arg when the bots are on jdk8 or higher. - '--extra-java-args', '-Xbootclasspath/p:<(PRODUCT_DIR)/lib.java/javac_jar.jar', + '--bootclasspath', '<(PRODUCT_DIR)/lib.java/javac_jar.jar', '--jar-path=<(jar_path)', '--classpath=>@(input_jars_paths)', '--main-class=com.google.errorprone.ErrorProneCompiler',
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index dd13c31..c06c07b 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -61313,6 +61313,7 @@ <int value="986" label="HTMLLabelElementFormContentAttribute"/> <int value="987" label="DeviceOrientationAbsoluteInsecureOrigin"/> <int value="988" label="DeviceOrientationAbsoluteSecureOrigin"/> + <int value="989" label="FontFaceConstructor"/> </enum> <enum name="FetchRequestMode" type="int">
diff --git a/tools/telemetry/telemetry/util/statistics.py b/tools/telemetry/telemetry/util/statistics.py index 9867f45..381c6b4 100644 --- a/tools/telemetry/telemetry/util/statistics.py +++ b/tools/telemetry/telemetry/util/statistics.py
@@ -87,26 +87,41 @@ count_less.append(len(samples)) count_less_equal.append(len(samples)) - # Iterate over the intervals defined by any pair of locations. - for i in xrange(0, len(locations)): - for j in xrange(i+1, len(locations)): - # Length of interval - length = locations[j] - locations[i] + # Compute discrepancy as max(overshoot, -undershoot), where + # overshoot = max(count_closed(i, j)/N - length(i, j)) for all i < j, + # undershoot = min(count_open(i, j)/N - length(i, j)) for all i < j, + # N = len(samples), + # count_closed(i, j) is the number of points between i and j including ends, + # count_open(i, j) is the number of points between i and j excluding ends, + # length(i, j) is locations[i] - locations[j]. - # Local discrepancy for closed interval - count_closed = count_less_equal[j] - count_less[i] - local_discrepancy_closed = abs(float(count_closed) * - inv_sample_count - length) - max_local_discrepancy = max(local_discrepancy_closed, - max_local_discrepancy) + # The following algorithm is modification of Kadane's algorithm, + # see https://en.wikipedia.org/wiki/Maximum_subarray_problem. - # Local discrepancy for open interval - count_open = count_less[j] - count_less_equal[i] - local_discrepancy_open = abs(float(count_open) * - inv_sample_count - length) - max_local_discrepancy = max(local_discrepancy_open, - max_local_discrepancy) + # The maximum of (count_closed(k, i-1)/N - length(k, i-1)) for any k < i-1. + max_diff = 0 + # The minimum of (count_open(k, i-1)/N - length(k, i-1)) for any k < i-1. + min_diff = 0 + for i in xrange(1, len(locations)): + length = locations[i] - locations[i - 1] + count_closed = count_less_equal[i] - count_less[i - 1] + count_open = count_less[i] - count_less_equal[i - 1] + # Number of points that are added if we extend a closed range that + # ends at location (i-1). + count_closed_increment = count_less_equal[i] - count_less_equal[i - 1] + # Number of points that are added if we extend an open range that + # ends at location (i-1). + count_open_increment = count_less[i] - count_less[i - 1] + # Either extend the previous optimal range or start a new one. + max_diff = max( + float(count_closed_increment) * inv_sample_count - length + max_diff, + float(count_closed) * inv_sample_count - length) + min_diff = min( + float(count_open_increment) * inv_sample_count - length + min_diff, + float(count_open) * inv_sample_count - length) + + max_local_discrepancy = max(max_diff, -min_diff, max_local_discrepancy) return max_local_discrepancy
diff --git a/ui/file_manager/audio_player/css/audio_player.css b/ui/file_manager/audio_player/css/audio_player.css index 56accad..06c01630 100644 --- a/ui/file_manager/audio_player/css/audio_player.css +++ b/ui/file_manager/audio_player/css/audio_player.css
@@ -23,6 +23,7 @@ } div.audio-player { + border-top: 4px solid white; color: #3d3d3d; cursor: default; flex: 1 1 auto;
diff --git a/ui/file_manager/audio_player/js/audio_player.js b/ui/file_manager/audio_player/js/audio_player.js index fea6cd4..ea5fd26 100644 --- a/ui/file_manager/audio_player/js/audio_player.js +++ b/ui/file_manager/audio_player/js/audio_player.js
@@ -329,7 +329,7 @@ * @type {number} * @const */ -AudioPlayer.HEADER_HEIGHT = 33; // 32px + border 1px +AudioPlayer.HEADER_HEIGHT = 36; // 32px + border 4px /** * Track height in pixels.
diff --git a/ui/file_manager/audio_player/js/background.js b/ui/file_manager/audio_player/js/background.js index 6177c7a..587c0816 100644 --- a/ui/file_manager/audio_player/js/background.js +++ b/ui/file_manager/audio_player/js/background.js
@@ -21,10 +21,13 @@ var audioPlayerCreateOptions = { id: 'audio-player', type: 'panel', - minHeight: 48 + 96, // 48px: track, 96px: controller + minHeight: 4 + 48 + 96, // 4px: border-top, 48px: track, 96px: controller minWidth: 280, - height: 48 + 96, // collapsed - width: 280 + height: 4 + 48 + 96, // collapsed + width: 280, + frame: { + color: '#fafafa' + } }; /**
diff --git a/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader.js b/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader.js index c82d88c..38a38415 100644 --- a/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader.js +++ b/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader.js
@@ -287,9 +287,6 @@ this.cache_.put(url, thumbnail); this.dispatchThumbnailLoaded_(index, thumbnail); this.continue_(); - }.bind(this), function() { - delete this.active_[url]; - this.continue_(); }.bind(this)); }; @@ -337,13 +334,13 @@ /** @type {string}*/ event.fileUrl = thumbnail.fileUrl; - /** @type {string} */ + /** @type {?string} */ event.dataUrl = thumbnail.dataUrl; - /** @type {number} */ + /** @type {?number} */ event.width = thumbnail.width; - /** @type {number}*/ + /** @type {?number}*/ event.height = thumbnail.height; return event; @@ -352,9 +349,9 @@ /** * A class to represent thumbnail data. * @param {string} fileUrl File url of an original image. - * @param {string} dataUrl Data url of thumbnail. - * @param {number} width Width of thumbnail. - * @param {number} height Height of thumbnail. + * @param {?string} dataUrl Data url of thumbnail. + * @param {?number} width Width of thumbnail. + * @param {?number} height Height of thumbnail. * @constructor * @struct */ @@ -365,17 +362,17 @@ this.fileUrl = fileUrl; /** - * @const {string} + * @const {?string} */ this.dataUrl = dataUrl; /** - * @const {number} + * @const {?number} */ this.width = width; /** - * @const {number} + * @const {?number} */ this.height = height; @@ -405,21 +402,34 @@ }; /** + * Minimum delay of milliseconds before another retry for fetching a thumbnmail + * from EXIF after failing with an IO error. In milliseconds. + * + * @type {number} + */ +ListThumbnailLoader.Task.EXIF_IO_ERROR_DELAY = 3000; + +/** * Fetches thumbnail. * * @return {!Promise<!ListThumbnailLoader.ThumbnailData>} A promise which is - * resolved when thumbnail is fetched. + * resolved when thumbnail data is fetched with either a success or an + * error. */ ListThumbnailLoader.Task.prototype.fetch = function() { + var ioError = false; return this.thumbnailModel_.get([this.entry_]).then(function(metadatas) { // When it failed to read exif header with an IO error, do not generate // thumbnail at this time since it may success in the second try. If it // failed to read at 0 byte, it would be an IO error. if (metadatas[0].thumbnail.urlError && metadatas[0].thumbnail.urlError.errorDescription === - 'Error: Unexpected EOF @0') - throw metadatas[0].thumbnail.urlError; - + 'Error: Unexpected EOF @0') { + ioError = true; + return Promise.reject(); + } + return metadatas[0]; + }.bind(this)).then(function(metadata) { var loadTargets = [ ThumbnailLoader.LoadTarget.CONTENT_METADATA, ThumbnailLoader.LoadTarget.EXTERNAL_METADATA @@ -436,11 +446,25 @@ } return new this.thumbnailLoaderConstructor_( - this.entry_, ThumbnailLoader.LoaderType.IMAGE, metadatas[0], + this.entry_, ThumbnailLoader.LoaderType.IMAGE, metadata, undefined /* opt_mediaType */, loadTargets) .loadAsDataUrl(ThumbnailLoader.FillMode.OVER_FILL); }.bind(this)).then(function(result) { return new ListThumbnailLoader.ThumbnailData( this.entry_.toURL(), result.data, result.width, result.height); + }.bind(this)).catch(function() { + // If an error happens during generating of a thumbnail, then return + // an empty object, so we don't retry the thumbnail over and over + // again. + var thumbnailData = new ListThumbnailLoader.ThumbnailData( + this.entry_.toURL(), null, null, null); + if (ioError) { + // If fetching a thumbnail from EXIF fails due to an IO error, then try to + // refetch it in the future, but not earlier than in 3 second. + setTimeout(function() { + thumbnailData.outdated = true; + }, ListThumbnailLoader.Task.EXIF_IO_ERROR_DELAY); + } + return thumbnailData; }.bind(this)); };
diff --git a/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader_unittest.js b/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader_unittest.js index b5ee6f45..bb35917 100644 --- a/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader_unittest.js +++ b/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader_unittest.js
@@ -44,6 +44,8 @@ var listThumbnailLoader; var getCallbacks; var thumbnailLoadedEvents; +var thumbnailModel; +var metadataModel; var fileListModel; var directoryModel; var currentVolumeType; @@ -67,7 +69,7 @@ MockThumbnailLoader.testImageHeight = 160; getCallbacks = {}; - var thumbnailModel = { + thumbnailModel = { get: function(entries) { return new Promise(function(fulfill) { getCallbacks[getKeyOfGetCallback_(entries)] = fulfill; @@ -75,7 +77,7 @@ } }; - var metadataModel = { + metadataModel = { get: function() {}, getCache: function(entries, names) { return [{}]; @@ -375,3 +377,41 @@ assertEquals(2, Object.keys(getCallbacks).length); } + +/** + * Test case for EXIF IO error and retrying logic. + */ +function testExifIOError(callback) { + var task = new ListThumbnailLoader.Task( + entry1, + // Mocking volume manager. + { + getVolumeInfo: function(entry) { + return { volumeType: currentVolumeType }; + } + }, + // Mocking thumbnail model. + { + get: function(entries) { + return Promise.resolve([{ + thumbnail: { + urlError: { + errorDescription: 'Error: Unexpected EOF @0' + } + } + }]); + } + }, + function() { + // Thumbnails should be fetched only from EXIF on IO error. + assertTrue(false); + }); + + return reportPromise(task.fetch().then(function(thumbnailData) { + assertEquals(null, thumbnailData.dataUrl); + assertFalse(thumbnailData.outdated); + return waitUntil(function() { + return thumbnailData.outdated; + }); + }), callback); +}
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_grid.js b/ui/file_manager/file_manager/foreground/js/ui/file_grid.js index 135af6f..8eff43d 100644 --- a/ui/file_manager/file_manager/foreground/js/ui/file_grid.js +++ b/ui/file_manager/file_manager/foreground/js/ui/file_grid.js
@@ -151,16 +151,23 @@ if (box) { var mimeType = this.metadataModel_.getCache( [entry], ['contentMimeType'])[0].contentMimeType; - FileGrid.setThumbnailImage_( - assertInstanceof(box, HTMLDivElement), - entry, - event.dataUrl, - event.width, - event.height, - /* should animate */ true, - mimeType); + if (!event.dataUrl) { + FileGrid.clearThumbnailImage_( + assertInstanceof(box, HTMLDivElement)); + FileGrid.setGenericThumbnail_( + assertInstanceof(box, HTMLDivElement), entry); + } else { + FileGrid.setThumbnailImage_( + assertInstanceof(box, HTMLDivElement), + entry, + assert(event.dataUrl), + assert(event.width), + assert(event.height), + /* should animate */ true, + mimeType); + } } - listItem.classList.toggle('thumbnail-loaded', true); + listItem.classList.toggle('thumbnail-loaded', !!event.dataUrl); } }; @@ -582,14 +589,15 @@ } if (entry.isDirectory) { - box.setAttribute('generic-thumbnail', 'folder'); + FileGrid.setGenericThumbnail_(box, entry); return; } - // Set thumbnail if it's already in cache. - if (this.listThumbnailLoader_ && - this.listThumbnailLoader_.getThumbnailFromCache(entry)) { - var thumbnailData = this.listThumbnailLoader_.getThumbnailFromCache(entry); + // Set thumbnail if it's already in cache, and the thumbnail data is not + // empty. + var thumbnailData = this.listThumbnailLoader_ ? + this.listThumbnailLoader_.getThumbnailFromCache(entry) : null; + if (thumbnailData && thumbnailData.dataUrl) { var mimeType = this.metadataModel_.getCache( [entry], ['contentMimeType'])[0].contentMimeType; FileGrid.setThumbnailImage_( @@ -602,8 +610,7 @@ mimeType); li.classList.toggle('thumbnail-loaded', true); } else { - var mediaType = FileType.getMediaType(entry); - box.setAttribute('generic-thumbnail', mediaType); + FileGrid.setGenericThumbnail_(box, entry); li.classList.toggle('thumbnail-loaded', false); } var mimeType = this.metadataModel_.getCache( @@ -652,11 +659,11 @@ /** * Sets thumbnail image to the box. * @param {!HTMLDivElement} box A div element to hold thumbnails. - * @param {Entry!} entry An entry of the thumbnail. + * @param {!Entry} entry An entry of the thumbnail. * @param {string} dataUrl Data url of thumbnail. * @param {number} width Width of thumbnail. * @param {number} height Height of thumbnail. - * @param {boolean} shouldAnimate Whether the thumbanil is shown with animation + * @param {boolean} shouldAnimate Whether the thumbnail is shown with animation * or not. * @param {string=} opt_mimeType Optional mime type for the image. * @private @@ -692,6 +699,34 @@ }; /** + * Clears thumbnail image from the box. + * @param {!HTMLDivElement} box A div element to hold thumbnails. + * @private + */ +FileGrid.clearThumbnailImage_ = function(box) { + var oldThumbnails = box.querySelectorAll('.thumbnail'); + for (var i = 0; i < oldThumbnails.length; i++) { + box.removeChild(oldThumbnails[i]); + } + return; +}; + +/** + * Sets a generic thumbnail on the box. + * @param {!HTMLDivElement} box A div element to hold thumbnails. + * @param {!Entry} entry An entry of the thumbnail. + * @private + */ +FileGrid.setGenericThumbnail_ = function(box, entry) { + if (entry.isDirectory) { + box.setAttribute('generic-thumbnail', 'folder'); + } else { + var mediaType = FileType.getMediaType(entry); + box.setAttribute('generic-thumbnail', mediaType); + } +}; + +/** * Applies cloud import history badges as appropriate for the Entry. * * @param {!FileEntry} entry
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_table.js b/ui/file_manager/file_manager/foreground/js/ui/file_table.js index 0545025..1764273 100644 --- a/ui/file_manager/file_manager/foreground/js/ui/file_table.js +++ b/ui/file_manager/file_manager/foreground/js/ui/file_table.js
@@ -526,9 +526,14 @@ if (listItem) { var box = listItem.querySelector('.detail-thumbnail'); if (box) { - this.setThumbnailImage_( - assertInstanceof(box, HTMLDivElement), event.dataUrl, - true /* with animation */); + if (event.dataUrl) { + this.setThumbnailImage_( + assertInstanceof(box, HTMLDivElement), event.dataUrl, + true /* with animation */); + } else { + this.clearThumbnailImage_( + assertInstanceof(box, HTMLDivElement)); + } } } }; @@ -965,8 +970,9 @@ box.className = 'detail-thumbnail'; // Set thumbnail if it's already in cache. - if (this.listThumbnailLoader_ && - this.listThumbnailLoader_.getThumbnailFromCache(entry)) { + var thumbnailData = this.listThumbnailLoader_ ? + this.listThumbnailLoader_.getThumbnailFromCache(entry) : null; + if (thumbnailData && thumbnailData.dataUrl) { this.setThumbnailImage_( box, this.listThumbnailLoader_.getThumbnailFromCache(entry).dataUrl, false /* without animation */); @@ -1007,6 +1013,19 @@ }; /** + * Clears thumbnail image from the box. + * @param {!HTMLDivElement} box Detail thumbnail div element. + * @private + */ +FileTable.prototype.clearThumbnailImage_ = function(box) { + var oldThumbnails = box.querySelectorAll('.thumbnail'); + + for (var i = 0; i < oldThumbnails.length; i++) { + box.removeChild(oldThumbnails[i]); + } +}; + +/** * Renders the selection checkmark in the detail table. * @return {!HTMLDivElement} Created element. * @private
diff --git a/ui/gl/angle_platform_impl.cc b/ui/gl/angle_platform_impl.cc index 1f1085b5..4f979ca 100644 --- a/ui/gl/angle_platform_impl.cc +++ b/ui/gl/angle_platform_impl.cc
@@ -37,10 +37,6 @@ LOG(WARNING) << warningMessage; } -void ANGLEPlatformImpl::logInfo(const char* infoMessage) { - LOG(INFO) << infoMessage; -} - angle::Platform::TraceEventHandle ANGLEPlatformImpl::addTraceEvent( char phase, const unsigned char* category_group_enabled,
diff --git a/ui/gl/angle_platform_impl.h b/ui/gl/angle_platform_impl.h index 61dd0fb..0783f2cb 100644 --- a/ui/gl/angle_platform_impl.h +++ b/ui/gl/angle_platform_impl.h
@@ -24,7 +24,6 @@ double monotonicallyIncreasingTime() override; void logError(const char* errorMessage) override; void logWarning(const char* warningMessage) override; - void logInfo(const char* infoMessage) override; const unsigned char* getTraceCategoryEnabledFlag( const char* category_group) override; TraceEventHandle addTraceEvent(char phase,
diff --git a/ui/mojo/geometry/geometry.mojom b/ui/mojo/geometry/geometry.mojom index 62bc6c8e..95a4336 100644 --- a/ui/mojo/geometry/geometry.mojom +++ b/ui/mojo/geometry/geometry.mojom
@@ -37,3 +37,10 @@ // Row major order. array<float, 16> matrix; }; + +struct Insets { + int32 top; + int32 left; + int32 bottom; + int32 right; +};
diff --git a/ui/views/controls/glow_hover_controller.cc b/ui/views/controls/glow_hover_controller.cc index 5ce23fa..d621cea9 100644 --- a/ui/views/controls/glow_hover_controller.cc +++ b/ui/views/controls/glow_hover_controller.cc
@@ -4,10 +4,6 @@ #include "ui/views/controls/glow_hover_controller.h" -#include "third_party/skia/include/effects/SkGradientShader.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/image/image_skia.h" -#include "ui/gfx/image/image_skia_operations.h" #include "ui/views/view.h" namespace views { @@ -72,49 +68,13 @@ return animation_.GetCurrentValue(); } -bool GlowHoverController::ShouldDraw() const { - return animation_.IsShowing() || animation_.is_animating(); +SkAlpha GlowHoverController::GetAlpha() const { + return static_cast<SkAlpha>(gfx::ToFlooredInt( + 0.5 + animation_.CurrentValueBetween(0., 255 * opacity_scale_))); } -void GlowHoverController::Draw(gfx::Canvas* canvas, - const gfx::ImageSkia& mask_image) const { - if (!ShouldDraw()) - return; - - // Draw a radial gradient to hover_canvas. - gfx::Canvas hover_canvas(gfx::Size(mask_image.width(), mask_image.height()), - canvas->image_scale(), - false); - - // Draw a radial gradient to hover_canvas. - int radius = view_->width() / 3; - - SkPoint center_point; - center_point.iset(location_.x(), location_.y()); - SkColor colors[2]; - int hover_alpha = - static_cast<int>(255 * opacity_scale_ * animation_.GetCurrentValue()); - colors[0] = SkColorSetARGB(hover_alpha, 255, 255, 255); - colors[1] = SkColorSetARGB(0, 255, 255, 255); - skia::RefPtr<SkShader> shader = skia::AdoptRef( - SkGradientShader::CreateRadial( - center_point, SkIntToScalar(radius), colors, NULL, 2, - SkShader::kClamp_TileMode)); - // Shader can end up null when radius = 0. - // If so, this results in default full tab glow behavior. - if (shader) { - SkPaint paint; - paint.setStyle(SkPaint::kFill_Style); - paint.setAntiAlias(true); - paint.setShader(shader.get()); - hover_canvas.DrawRect(gfx::Rect(location_.x() - radius, - location_.y() - radius, - radius * 2, radius * 2), paint); - } - gfx::ImageSkia result = gfx::ImageSkiaOperations::CreateMaskedImage( - gfx::ImageSkia(hover_canvas.ExtractImageRep()), mask_image); - canvas->DrawImageInt(result, (view_->width() - mask_image.width()) / 2, - (view_->height() - mask_image.height()) / 2); +bool GlowHoverController::ShouldDraw() const { + return animation_.IsShowing() || animation_.is_animating(); } void GlowHoverController::AnimationEnded(const gfx::Animation* animation) {
diff --git a/ui/views/controls/glow_hover_controller.h b/ui/views/controls/glow_hover_controller.h index 6be5ae7..00bf528 100644 --- a/ui/views/controls/glow_hover_controller.h +++ b/ui/views/controls/glow_hover_controller.h
@@ -44,6 +44,8 @@ // constructor. void SetLocation(const gfx::Point& location); + const gfx::Point& location() const { return location_; } + // Initiates showing the hover. void Show(Style style); @@ -56,14 +58,12 @@ // Returns the value of the animation. double GetAnimationValue() const; + SkAlpha GetAlpha() const; + // Returns true if there is something to be drawn. Use this instead of // invoking Draw() if creating |mask_image| is expensive. bool ShouldDraw() const; - // If the hover is currently visible it is drawn to the supplied canvas. - // |mask_image| is used to determine what parts of the canvas to draw on. - void Draw(gfx::Canvas* canvas, const gfx::ImageSkia& mask_image) const; - // gfx::AnimationDelegate overrides: void AnimationEnded(const gfx::Animation* animation) override; void AnimationProgressed(const gfx::Animation* animation) override;
diff --git a/ui/views/mus/BUILD.gn b/ui/views/mus/BUILD.gn index fa6741f..1384128 100644 --- a/ui/views/mus/BUILD.gn +++ b/ui/views/mus/BUILD.gn
@@ -8,6 +8,8 @@ sources = [ "aura_init.cc", "aura_init.h", + "display_converter.cc", + "display_converter.h", "input_method_mus.cc", "input_method_mus.h", "native_widget_mus.cc", @@ -18,6 +20,7 @@ "surface_binding.h", "surface_context_factory.cc", "surface_context_factory.h", + "window_manager_client_area_insets.h", "window_manager_connection.cc", "window_manager_connection.h", "window_tree_host_mus.cc", @@ -53,6 +56,8 @@ "//ui/compositor", "//ui/events", "//ui/events:events_base", + "//ui/gfx", + "//ui/gfx/geometry", "//ui/gl", "//ui/mojo/ime:interfaces_cpp_sources", "//ui/mojo/init",
diff --git a/mandoline/ui/common/util.cc b/ui/views/mus/display_converter.cc similarity index 88% rename from mandoline/ui/common/util.cc rename to ui/views/mus/display_converter.cc index 2ef16046..954aad7 100644 --- a/mandoline/ui/common/util.cc +++ b/ui/views/mus/display_converter.cc
@@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "mandoline/ui/common/util.h" +#include "ui/views/mus/display_converter.h" #include "components/mus/public/cpp/window.h" #include "mojo/converters/geometry/geometry_type_converters.h" -namespace mandoline { +namespace views { std::vector<gfx::Display> GetDisplaysFromWindow(mus::Window* window) { static int64 synthesized_display_id = 2000; @@ -21,4 +21,4 @@ return displays; } -} // namespace mandoline +} // namespace views
diff --git a/mandoline/ui/common/util.h b/ui/views/mus/display_converter.h similarity index 64% rename from mandoline/ui/common/util.h rename to ui/views/mus/display_converter.h index 63e88b5..a747455 100644 --- a/mandoline/ui/common/util.h +++ b/ui/views/mus/display_converter.h
@@ -2,20 +2,21 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef MANDOLINE_UI_COMMON_UTIL_H_ -#define MANDOLINE_UI_COMMON_UTIL_H_ +#ifndef UI_VIEWS_MUS_DISPLAY_CONVERTER_H_ +#define UI_VIEWS_MUS_DISPLAY_CONVERTER_H_ #include <vector> + #include "ui/gfx/display.h" namespace mus { class Window; } -namespace mandoline { +namespace views { std::vector<gfx::Display> GetDisplaysFromWindow(mus::Window* window); -} // namespace mandoline +} // namespace views -#endif // MANDOLINE_UI_COMMON_UTIL_H_ \ No newline at end of file +#endif // UI_VIEWS_MUS_DISPLAY_CONVERTER_H_
diff --git a/ui/views/mus/native_widget_mus.cc b/ui/views/mus/native_widget_mus.cc index f9b43d3..507e83f 100644 --- a/ui/views/mus/native_widget_mus.cc +++ b/ui/views/mus/native_widget_mus.cc
@@ -10,9 +10,15 @@ #include "ui/aura/client/default_capture_client.h" #include "ui/aura/layout_manager.h" #include "ui/aura/window.h" +#include "ui/base/hit_test.h" +#include "ui/compositor/clip_transform_recorder.h" +#include "ui/compositor/paint_recorder.h" +#include "ui/gfx/canvas.h" #include "ui/native_theme/native_theme_aura.h" +#include "ui/views/mus/window_manager_client_area_insets.h" #include "ui/views/mus/window_tree_host_mus.h" #include "ui/views/widget/widget_delegate.h" +#include "ui/views/window/custom_frame_view.h" #include "ui/wm/core/base_focus_rules.h" #include "ui/wm/core/capture_controller.h" #include "ui/wm/core/focus_controller.h" @@ -20,6 +26,8 @@ namespace views { namespace { +WindowManagerClientAreaInsets* window_manager_client_area_insets = nullptr; + // TODO: figure out what this should be. class FocusRulesImpl : public wm::BaseFocusRules { public: @@ -61,6 +69,60 @@ DISALLOW_COPY_AND_ASSIGN(ContentWindowLayoutManager); }; +// As the window manager renderers the non-client decorations this class does +// very little but honor the client area insets from the window manager. +class ClientSideNonClientFrameView : public NonClientFrameView { + public: + explicit ClientSideNonClientFrameView(views::Widget* widget) + : widget_(widget) {} + ~ClientSideNonClientFrameView() override {} + + private: + // Returns the default values of client area insets from the window manager. + static gfx::Insets GetDefaultWindowManagerInsets(bool is_maximized) { + if (!window_manager_client_area_insets) + return gfx::Insets(); + return is_maximized ? window_manager_client_area_insets->maximized_insets + : window_manager_client_area_insets->normal_insets; + } + + // NonClientFrameView: + gfx::Rect GetBoundsForClientView() const override { + gfx::Rect result(GetLocalBounds()); + result.Inset(GetDefaultWindowManagerInsets(widget_->IsMaximized())); + return result; + } + gfx::Rect GetWindowBoundsForClientBounds( + const gfx::Rect& client_bounds) const override { + const gfx::Insets insets( + GetDefaultWindowManagerInsets(widget_->IsMaximized())); + return gfx::Rect(client_bounds.x() - insets.left(), + client_bounds.y() - insets.top(), + client_bounds.width() + insets.width(), + client_bounds.height() + insets.height()); + } + int NonClientHitTest(const gfx::Point& point) override { return HTNOWHERE; } + void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask) override { + // The window manager provides the shape; do nothing. + } + void ResetWindowControls() override { + // TODO(sky): push to wm? + } + void UpdateWindowIcon() override { + // NOTIMPLEMENTED(); + } + void UpdateWindowTitle() override { + // NOTIMPLEMENTED(); + } + void SizeConstraintsChanged() override { + // NOTIMPLEMENTED(); + } + + views::Widget* widget_; + + DISALLOW_COPY_AND_ASSIGN(ClientSideNonClientFrameView); +}; + } // namespace //////////////////////////////////////////////////////////////////////////////// @@ -78,6 +140,15 @@ content_(new aura::Window(this)) {} NativeWidgetMus::~NativeWidgetMus() {} +// static +void NativeWidgetMus::SetWindowManagerClientAreaInsets( + const WindowManagerClientAreaInsets& insets) { + delete window_manager_client_area_insets; + // This is called early on, so we don't bother trying to relayout existing + // NativeWidgetMus. When we support restarting the WM we'll need to do that. + window_manager_client_area_insets = new WindowManagerClientAreaInsets(insets); +} + //////////////////////////////////////////////////////////////////////////////// // NativeWidgetMus, private: @@ -87,12 +158,20 @@ if (!non_client_view || !non_client_view->client_view()) return; - window_->SetClientArea(non_client_view->client_view()->bounds()); + const gfx::Rect client_area_rect(non_client_view->client_view()->bounds()); + window_->SetClientArea(gfx::Insets( + client_area_rect.y(), client_area_rect.x(), + non_client_view->bounds().height() - client_area_rect.bottom(), + non_client_view->bounds().width() - client_area_rect.right())); } //////////////////////////////////////////////////////////////////////////////// // NativeWidgetMus, internal::NativeWidgetPrivate implementation: +NonClientFrameView* NativeWidgetMus::CreateNonClientFrameView() { + return new ClientSideNonClientFrameView(GetWidget()); +} + void NativeWidgetMus::InitNativeWidget(const Widget::InitParams& params) { window_tree_host_.reset( new WindowTreeHostMus(shell_, window_, surface_type_)); @@ -119,11 +198,6 @@ // TODO(beng): much else, see [Desktop]NativeWidgetAura. } -NonClientFrameView* NativeWidgetMus::CreateNonClientFrameView() { - // NOTIMPLEMENTED(); - return nullptr; -} - bool NativeWidgetMus::ShouldUseNativeFrame() const { // NOTIMPLEMENTED(); return false; @@ -386,7 +460,7 @@ } void NativeWidgetMus::SchedulePaintInRect(const gfx::Rect& rect) { - // NOTIMPLEMENTED(); + content_->SchedulePaintInRect(rect); } void NativeWidgetMus::SetCursor(gfx::NativeCursor cursor) {
diff --git a/ui/views/mus/native_widget_mus.h b/ui/views/mus/native_widget_mus.h index 61df1cc..dbfbba0 100644 --- a/ui/views/mus/native_widget_mus.h +++ b/ui/views/mus/native_widget_mus.h
@@ -23,6 +23,10 @@ namespace mus { class Window; + +namespace mojom { +class WindowManager; +} } namespace wm { @@ -30,6 +34,7 @@ } namespace views { +struct WindowManagerClientAreaInsets; class WindowTreeHostMus; // An implementation of NativeWidget that binds to a mus::Window. Because Aura @@ -47,12 +52,22 @@ mus::mojom::SurfaceType surface_type); ~NativeWidgetMus() override; + // Sets the insets for the client area. These values come from the window + // manager. + static void SetWindowManagerClientAreaInsets( + const WindowManagerClientAreaInsets& insets); + + mus::Window* window() { return window_; } + + protected: + // internal::NativeWidgetPrivate: + NonClientFrameView* CreateNonClientFrameView() override; + private: void UpdateClientAreaInWindowManager(); // internal::NativeWidgetPrivate: void InitNativeWidget(const Widget::InitParams& params) override; - NonClientFrameView* CreateNonClientFrameView() override; bool ShouldUseNativeFrame() const override; bool ShouldWindowContentsBeTransparent() const override; void FrameTypeChanged() override;
diff --git a/ui/views/mus/window_manager_client_area_insets.h b/ui/views/mus/window_manager_client_area_insets.h new file mode 100644 index 0000000..20a27f6 --- /dev/null +++ b/ui/views/mus/window_manager_client_area_insets.h
@@ -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. + +#ifndef UI_VIEWS_MUS_WINDOW_MANAGER_CLIENT_AREA_INSETS_H_ +#define UI_VIEWS_MUS_WINDOW_MANAGER_CLIENT_AREA_INSETS_H_ + +#include "ui/gfx/geometry/insets.h" + +namespace views { + +struct WindowManagerClientAreaInsets { + gfx::Insets normal_insets; + gfx::Insets maximized_insets; +}; + +} // namespace views + +#endif // UI_VIEWS_MUS_WINDOW_MANAGER_CLIENT_AREA_INSETS_H_
diff --git a/ui/views/mus/window_manager_connection.cc b/ui/views/mus/window_manager_connection.cc index b46ac10..006a8b3 100644 --- a/ui/views/mus/window_manager_connection.cc +++ b/ui/views/mus/window_manager_connection.cc
@@ -17,6 +17,7 @@ #include "ui/gfx/geometry/rect.h" #include "ui/mojo/init/ui_init.h" #include "ui/views/mus/native_widget_mus.h" +#include "ui/views/mus/window_manager_client_area_insets.h" #include "ui/views/views_delegate.h" namespace mojo { @@ -58,6 +59,8 @@ } // namespace mojo +namespace views { + namespace { using WindowManagerConnectionPtr = @@ -69,18 +72,23 @@ std::vector<gfx::Display> GetDisplaysFromWindowManager( mus::mojom::WindowManagerPtr* window_manager) { + WindowManagerClientAreaInsets client_insets; std::vector<gfx::Display> displays; - (*window_manager)->GetDisplays( - [&displays](mojo::Array<mus::mojom::DisplayPtr> mojom_displays) { - displays = mojom_displays.To<std::vector<gfx::Display>>(); + (*window_manager) + ->GetConfig([&displays, + &client_insets](mus::mojom::WindowManagerConfigPtr results) { + displays = results->displays.To<std::vector<gfx::Display>>(); + client_insets.normal_insets = + results->normal_client_area_insets.To<gfx::Insets>(); + client_insets.maximized_insets = + results->maximized_client_area_insets.To<gfx::Insets>(); }); CHECK(window_manager->WaitForIncomingResponse()); + NativeWidgetMus::SetWindowManagerClientAreaInsets(client_insets); return displays; } -} - -namespace views { +} // namespace // static void WindowManagerConnection::Create(
diff --git a/ui/views/window/non_client_view.h b/ui/views/window/non_client_view.h index 762ccf1..4efde57b 100644 --- a/ui/views/window/non_client_view.h +++ b/ui/views/window/non_client_view.h
@@ -73,12 +73,19 @@ // the parent NonClientView because that makes it more difficult to calculate // hittests for regions that are partially obscured by the ClientView, e.g. // HTSYSMENU. + // Return value is one of the windows HT constants (see ui/base/hit_test.h). virtual int NonClientHitTest(const gfx::Point& point) = 0; + + // Used to make the hosting widget shaped (non-rectangular). For a + // rectangular window do nothing. For a shaped window update |window_mask| + // accordingly. |size| is the size of the widget. virtual void GetWindowMask(const gfx::Size& size, gfx::Path* window_mask) = 0; virtual void ResetWindowControls() = 0; virtual void UpdateWindowIcon() = 0; virtual void UpdateWindowTitle() = 0; + + // Whether the widget can be resized or maximized has changed. virtual void SizeConstraintsChanged() = 0; // View: