diff --git a/AUTHORS b/AUTHORS index 233d94eb..450bf6b 100644 --- a/AUTHORS +++ b/AUTHORS
@@ -367,6 +367,7 @@ Jungkee Song <jungkee.song@samsung.com> Junmin Zhu <junmin.zhu@intel.com> Kai Jiang <jiangkai@gmail.com> +Kai Köhne <kai.koehne@qt.io> Kal Conley <kcconley@gmail.com> Kalyan Kondapally <kalyan.kondapally@intel.com> Kamil Jiwa <kamil.jiwa@gmail.com>
diff --git a/DEPS b/DEPS index 30c001f..7dbbd90 100644 --- a/DEPS +++ b/DEPS
@@ -40,11 +40,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': '2103cf0ff09763aeaa35508734f765aec9b75665', + 'skia_revision': '6d4d6cce5e6e73d14c5d39c20321b189d737dfd5', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': '4b8a39354acd5949f3a389581fe6bda679a4e6d2', + 'v8_revision': 'd6a08d86c04b5b652533978ef6b257de09d0599e', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling swarming_client # and whatever else without interference from each other. @@ -228,7 +228,7 @@ Var('chromium_git') + '/native_client/src/third_party/scons-2.0.1.git' + '@' + '1c1550e17fc26355d08627fbdec13d8291227067', 'src/third_party/webrtc': - Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '3e52797e71d77b2d61bb31bf035314c030d0cfcc', # commit position 16104 + Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '7367842b0870f9b03b9559c584899d4bf0ad93ec', # commit position 16120 'src/third_party/openmax_dl': Var('chromium_git') + '/external/webrtc/deps/third_party/openmax.git' + '@' + Var('openmax_dl_revision'),
diff --git a/base/mac/sdk_forward_declarations.h b/base/mac/sdk_forward_declarations.h index dce61ad..9f60262c 100644 --- a/base/mac/sdk_forward_declarations.h +++ b/base/mac/sdk_forward_declarations.h
@@ -76,6 +76,8 @@ #if !defined(MAC_OS_X_VERSION_10_10) || \ MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10 BASE_EXPORT extern NSString* const NSUserActivityTypeBrowsingWeb; +BASE_EXPORT extern NSString* const NSAppearanceNameVibrantDark; +BASE_EXPORT extern NSString* const NSAppearanceNameVibrantLight; #endif // MAC_OS_X_VERSION_10_10 } // extern "C" @@ -108,6 +110,10 @@ - (void)viewDidLoad; @end +@interface NSWindow (YosemiteSDK) +- (void)setTitlebarAppearsTransparent:(BOOL)flag; +@end + @interface NSProcessInfo (YosemiteSDK) @property(readonly) NSOperatingSystemVersion operatingSystemVersion; @end @@ -116,6 +122,12 @@ @property(getter=isActive) BOOL active; @end +@interface NSVisualEffectView (YosemiteSDK) +- (void)setState:(NSVisualEffectState)state; +@end + +@class NSVisualEffectView; + #endif // MAC_OS_X_VERSION_10_10 // Once Chrome no longer supports OSX 10.10.2, everything within this
diff --git a/build/android/gyp/write_build_config.py b/build/android/gyp/write_build_config.py index 3a529af..98d1d7d 100755 --- a/build/android/gyp/write_build_config.py +++ b/build/android/gyp/write_build_config.py
@@ -342,6 +342,7 @@ 'android_resources': ['build_config', 'resources_zip'], 'android_apk': ['build_config', 'jar_path', 'dex_path', 'resources_zip'], 'deps_dex': ['build_config', 'dex_path'], + 'dist_jar': ['build_config'], 'resource_rewriter': ['build_config'], 'group': ['build_config'], } @@ -456,10 +457,10 @@ deps_info['incremental_install_script_path'] = ( options.incremental_install_script_path) + if options.type in ('java_binary', 'java_library', 'android_apk', 'dist_jar'): # Classpath values filled in below (after applying tested_apk_config). config['javac'] = {} - if options.type in ('java_binary', 'java_library'): # Only resources might have srcjars (normal srcjar targets are listed in # srcjar_deps). A resource's srcjar contains the R.java file for those @@ -548,7 +549,7 @@ if options.type in ['android_apk', 'deps_dex']: deps_dex_files = [c['dex_path'] for c in all_library_deps] - if options.type in ('java_binary', 'java_library', 'android_apk'): + if options.type in ('java_binary', 'java_library', 'android_apk', 'dist_jar'): javac_classpath = [c['jar_path'] for c in direct_library_deps] java_full_classpath = [c['jar_path'] for c in all_library_deps] @@ -627,7 +628,7 @@ dex_config = config['final_dex'] dex_config['dependency_dex_files'] = deps_dex_files - if options.type in ('java_binary', 'java_library', 'android_apk'): + if options.type in ('java_binary', 'java_library', 'android_apk', 'dist_jar'): config['javac']['classpath'] = javac_classpath config['javac']['interface_classpath'] = [ _AsInterfaceJar(p) for p in javac_classpath] @@ -635,14 +636,19 @@ 'full_classpath': java_full_classpath } - if options.type == 'android_apk': + if options.type in ('android_apk', 'dist_jar'): dependency_jars = [c['jar_path'] for c in all_library_deps] - all_interface_jars = [ - _AsInterfaceJar(p) for p in dependency_jars + [options.jar_path]] + all_interface_jars = [_AsInterfaceJar(p) for p in dependency_jars] + if options.type == 'android_apk': + all_interface_jars.append(_AsInterfaceJar(options.jar_path)) + config['dist_jar'] = { 'dependency_jars': dependency_jars, 'all_interface_jars': all_interface_jars, } + + if options.type == 'android_apk': + dependency_jars = [c['jar_path'] for c in all_library_deps] manifest = AndroidManifest(options.android_manifest) deps_info['package_name'] = manifest.GetPackageName() if not options.tested_apk_config and manifest.GetInstrumentation():
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni index 102e98c..32a00a1 100644 --- a/build/config/android/internal_rules.gni +++ b/build/config/android/internal_rules.gni
@@ -59,7 +59,7 @@ # Don't need to enforce naming scheme for these targets since we never # consider them in dependency chains. if (!_is_prebuilt_binary && type != "android_apk" && type != "java_binary" && - type != "resource_rewriter") { + type != "resource_rewriter" && type != "dist_jar") { set_sources_assignment_filter(_java_target_whitelist) _parent_invoker = invoker.invoker _target_label = @@ -86,8 +86,9 @@ assert(type == "android_apk" || type == "java_library" || type == "android_resources" || type == "deps_dex" || - type == "android_assets" || type == "resource_rewriter" || - type == "java_binary" || type == "group" || type == "java_prebuilt") + type == "dist_jar" || type == "android_assets" || + type == "resource_rewriter" || type == "java_binary" || + type == "group" || type == "java_prebuilt") forward_variables_from(invoker, [
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni index 1db01006..7abf41c 100644 --- a/build/config/android/rules.gni +++ b/build/config/android/rules.gni
@@ -1195,6 +1195,86 @@ } } + # Combines all dependent .jar files into a single .jar file. + # + # Variables: + # output: Path to the output jar. + # override_build_config: Use a pre-existing .build_config. Must be of type + # "apk". + # use_interface_jars: Use all dependent interface .jars rather than + # implementation .jars. + # direct_deps_only: Do not recurse on deps. + # data, deps, testonly, visibility: Usual meaning. + # + # Example + # dist_jar("lib_fatjar") { + # deps = [ ":my_java_lib" ] + # } + template("dist_jar") { + if (defined(invoker.override_build_config)) { + _build_config = invoker.override_build_config + } else { + _build_config = "$target_gen_dir/$target_name.build_config" + _build_config_target_name = "${target_name}__build_config" + + write_build_config(_build_config_target_name) { + forward_variables_from(invoker, [ "testonly" ]) + type = "dist_jar" + if (defined(invoker.deps)) { + possible_config_deps = invoker.deps + } + build_config = _build_config + } + } + + action(target_name) { + forward_variables_from(invoker, + [ + "data", + "deps", + "testonly", + "visibility", + ]) + script = "//build/android/gyp/create_dist_jar.py" + depfile = "$target_gen_dir/$target_name.d" + + inputs = [ + _build_config, + ] + + outputs = [ + invoker.output, + ] + + if (defined(_build_config_target_name)) { + deps += [ ":$_build_config_target_name" ] + } + + args = [ + "--depfile", + rebase_path(depfile, root_build_dir), + "--output", + rebase_path(invoker.output, root_build_dir), + ] + + _rebased_build_config = rebase_path(_build_config, root_build_dir) + if (defined(invoker.direct_deps_only) && invoker.direct_deps_only) { + if (defined(invoker.use_interface_jars) && invoker.use_interface_jars) { + args += [ "--inputs=@FileArg($_rebased_build_config:javac:interface_classpath)" ] + } else { + args += + [ "--inputs=@FileArg($_rebased_build_config:javac:classpath)" ] + } + } else { + if (defined(invoker.use_interface_jars) && invoker.use_interface_jars) { + args += [ "--inputs=@FileArg($_rebased_build_config:dist_jar:all_interface_jars)" ] + } else { + args += [ "--inputs=@FileArg($_rebased_build_config:dist_jar:dependency_jars)" ] + } + } + } + } + # Declare an Android library target # # This target creates an Android library containing java code and Android @@ -1832,28 +1912,16 @@ # able to just do that calculation at build time instead. if (defined(invoker.dist_ijar_path)) { _dist_ijar_path = invoker.dist_ijar_path - action("${_template_name}_dist_ijar") { - script = "//build/android/gyp/create_dist_jar.py" - depfile = "$target_gen_dir/$target_name.d" - inputs = [ - _build_config, - ] - outputs = [ - "${_dist_ijar_path}", - ] + dist_jar("${_template_name}_dist_ijar") { + override_build_config = _build_config + output = _dist_ijar_path data = [ _dist_ijar_path, ] - args = [ - "--depfile", - rebase_path(depfile, root_build_dir), - "--output", - rebase_path("${_dist_ijar_path}", root_build_dir), - "--inputs=@FileArg($_rebased_build_config:dist_jar:all_interface_jars)", - ] + use_interface_jars = true deps = [ - ":$build_config_target", # Generates the build config file. - ":$java_target", # Generates the jar file. + ":$build_config_target", + ":$java_target", ] } }
diff --git a/cc/layers/render_surface_impl.cc b/cc/layers/render_surface_impl.cc index 8605c86..cc1f28e 100644 --- a/cc/layers/render_surface_impl.cc +++ b/cc/layers/render_surface_impl.cc
@@ -152,7 +152,7 @@ } int RenderSurfaceImpl::TransformTreeIndex() const { - return owning_layer_->transform_tree_index(); + return OwningEffectNode()->transform_id; } int RenderSurfaceImpl::ClipTreeIndex() const {
diff --git a/cc/playback/raster_source.cc b/cc/playback/raster_source.cc index 6f9365f..031cd30 100644 --- a/cc/playback/raster_source.cc +++ b/cc/playback/raster_source.cc
@@ -108,13 +108,27 @@ } } +namespace { + +bool CanvasIsUnclipped(const SkCanvas* canvas) { + if (!canvas->isClipRect()) + return false; + + SkIRect bounds; + if (!canvas->getClipDeviceBounds(&bounds)) + return false; + + SkISize size = canvas->getBaseLayerSize(); + return bounds.contains(0, 0, size.width(), size.height()); +} + +} // namespace + void RasterSource::PrepareForPlaybackToCanvas(SkCanvas* canvas) const { // TODO(hendrikw): See if we can split this up into separate functions. - if (canvas->getClipStack()->quickContains( - SkRect::MakeFromIRect(canvas->imageInfo().bounds()))) { + if (CanvasIsUnclipped(canvas)) canvas->discard(); - } // If this raster source has opaque contents, it is guaranteeing that it will // draw an opaque rect the size of the layer. If it is not, then we must
diff --git a/cc/trees/draw_property_utils.cc b/cc/trees/draw_property_utils.cc index 9251bef..4bcac305 100644 --- a/cc/trees/draw_property_utils.cc +++ b/cc/trees/draw_property_utils.cc
@@ -1278,7 +1278,7 @@ const EffectNode* effect_node = effect_tree.Node(render_surface->EffectTreeIndex()); // The draw transform of root render surface is identity tranform. - if (transform_node->id == 1) { + if (transform_node->id == TransformTree::kRootNodeId) { render_surface->SetDrawTransform(gfx::Transform()); return; }
diff --git a/cc/trees/property_tree.cc b/cc/trees/property_tree.cc index 1bef82ef..2e9ed3e 100644 --- a/cc/trees/property_tree.cc +++ b/cc/trees/property_tree.cc
@@ -49,6 +49,7 @@ device_scale_factor_(1.f), device_transform_scale_factor_(1.f) { cached_data_.push_back(TransformCachedNodeData()); + cached_data_[kRootNodeId].target_id = kRootNodeId; } TransformTree::~TransformTree() = default; @@ -117,6 +118,7 @@ nodes_affected_by_outer_viewport_bounds_delta_.clear(); cached_data_.clear(); cached_data_.push_back(TransformCachedNodeData()); + cached_data_[kRootNodeId].target_id = kRootNodeId; sticky_position_data_.clear(); #if DCHECK_IS_ON() @@ -2067,8 +2069,7 @@ gfx::Transform PropertyTrees::ToScreenSpaceTransformWithoutSurfaceContentsScale( int transform_id, int effect_id) const { - DCHECK_GT(transform_id, 0); - if (transform_id == 1) { + if (transform_id == TransformTree::kRootNodeId) { return gfx::Transform(); } gfx::Transform screen_space_transform = transform_tree.ToScreen(transform_id);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java index 1d5a8082..b683aa3 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
@@ -368,9 +368,15 @@ } } + public void trackSnippetOpened( + int windowOpenDisposition, SnippetArticle article, int categoryIndex) { + mSnippetsBridge.onSuggestionOpened(article, categoryIndex, windowOpenDisposition); + } + @Override - public void openSnippet(int windowOpenDisposition, SnippetArticle article) { - mSnippetsBridge.onSuggestionOpened(article, windowOpenDisposition); + public void openSnippet( + int windowOpenDisposition, SnippetArticle article, int categoryIndex) { + trackSnippetOpened(windowOpenDisposition, article, categoryIndex); NewTabPageUma.recordAction(NewTabPageUma.ACTION_OPENED_SNIPPET); if (article.mIsAssetDownload) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java index 78ff652..1915b3c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
@@ -200,8 +200,9 @@ * Opens a content suggestion and records related metrics. * @param windowOpenDisposition How to open (current tab, new tab, new window etc). * @param article The content suggestion to open. + * @param categoryIndex The index of the category |article| belongs to. */ - void openSnippet(int windowOpenDisposition, SnippetArticle article); + void openSnippet(int windowOpenDisposition, SnippetArticle article, int categoryIndex); /** * Animates the search box up into the omnibox and bring up the keyboard.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SectionList.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SectionList.java index c4ecfd88..f75a9f3f8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SectionList.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SectionList.java
@@ -51,7 +51,7 @@ SuggestionsSource suggestionsSource = mNewTabPageManager.getSuggestionsSource(); int[] categories = suggestionsSource.getCategories(); int[] suggestionsPerCategory = new int[categories.length]; - int i = 0; + int categoryIndex = 0; for (int category : categories) { int categoryStatus = suggestionsSource.getCategoryStatus(category); if (categoryStatus == CategoryStatus.LOADING_ERROR @@ -59,8 +59,11 @@ || categoryStatus == CategoryStatus.CATEGORY_EXPLICITLY_DISABLED) continue; - suggestionsPerCategory[i++] = + suggestionsPerCategory[categoryIndex] = resetSection(category, categoryStatus, alwaysAllowEmptySections); + SuggestionsSection section = mSections.get(category); + if (section != null) section.setCategoryIndex(categoryIndex); + ++categoryIndex; } mNewTabPageManager.trackSnippetsPageImpression(categories, suggestionsPerCategory);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java index 088ee0ac..acb529e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java
@@ -80,6 +80,7 @@ private final List<SnippetArticle> mSuggestions = new ArrayList<>(); private final NewTabPageManager mNewTabPageManager; private final SuggestionsCategoryInfo mCategoryInfo; + private int mCategoryIndex; public SuggestionsList(NewTabPageManager newTabPageManager, SuggestionsCategoryInfo categoryInfo) { @@ -87,6 +88,14 @@ mCategoryInfo = categoryInfo; } + public void setCategoryIndex(int categoryIndex) { + mCategoryIndex = categoryIndex; + } + + public int getCategoryIndex() { + return mCategoryIndex; + } + @Override public int getItemCount() { return mSuggestions.size(); @@ -105,7 +114,8 @@ checkIndex(position); assert holder instanceof SnippetArticleViewHolder; ((SnippetArticleViewHolder) holder) - .onBindViewHolder(getSuggestionAt(position), mCategoryInfo, payloads); + .onBindViewHolder( + getSuggestionAt(position), mCategoryInfo, payloads, mCategoryIndex); } @Override @@ -426,6 +436,14 @@ return mCategoryInfo; } + public int getCategoryIndex() { + return mSuggestionsList.getCategoryIndex(); + } + + public void setCategoryIndex(int categoryIndex) { + mSuggestionsList.setCategoryIndex(categoryIndex); + } + public String getHeaderText() { return mHeader.getHeaderText(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticleViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticleViewHolder.java index 913e9c2..7bb3616 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticleViewHolder.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticleViewHolder.java
@@ -70,6 +70,7 @@ private FetchImageCallback mImageCallback; private SnippetArticle mArticle; private SuggestionsCategoryInfo mCategoryInfo; + private int mCategoryIndex; private int mPublisherFaviconSizePx; private final boolean mUseFaviconService; @@ -117,12 +118,12 @@ @Override public void onCardTapped() { - mNewTabPageManager.openSnippet(WindowOpenDisposition.CURRENT_TAB, mArticle); + mNewTabPageManager.openSnippet(WindowOpenDisposition.CURRENT_TAB, mArticle, mCategoryIndex); } @Override public void openItem(int windowDisposition) { - mNewTabPageManager.openSnippet(windowDisposition, mArticle); + mNewTabPageManager.openSnippet(windowDisposition, mArticle, mCategoryIndex); } @Override @@ -223,8 +224,8 @@ BidiFormatter.getInstance().unicodeWrap(article.mPublisher), relativeTimeSpan); } - public void onBindViewHolder( - SnippetArticle article, SuggestionsCategoryInfo categoryInfo, List<Object> payloads) { + public void onBindViewHolder(SnippetArticle article, SuggestionsCategoryInfo categoryInfo, + List<Object> payloads, int categoryIndex) { if (!payloads.isEmpty() && article.equals(mArticle)) { performPartialBind(payloads); return; @@ -234,6 +235,7 @@ mArticle = article; mCategoryInfo = categoryInfo; + mCategoryIndex = categoryIndex; updateLayout(); mHeadlineTextView.setText(mArticle.mTitle);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java index 4525f1f..a9928ce1 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java
@@ -147,10 +147,11 @@ suggestion.mPublishTimestampMilliseconds, suggestion.mScore); } - public void onSuggestionOpened(SnippetArticle suggestion, int windowOpenDisposition) { + public void onSuggestionOpened( + SnippetArticle suggestion, int categoryIndex, int windowOpenDisposition) { assert mNativeSnippetsBridge != 0; nativeOnSuggestionOpened(mNativeSnippetsBridge, suggestion.mGlobalPosition, - suggestion.mCategory, suggestion.mPosition, + suggestion.mCategory, categoryIndex, suggestion.mPosition, suggestion.mPublishTimestampMilliseconds, suggestion.mScore, windowOpenDisposition); } @@ -313,8 +314,8 @@ private native void nativeOnSuggestionShown(long nativeNTPSnippetsBridge, int globalPosition, int category, int categoryPosition, long publishTimestampMs, float score); private native void nativeOnSuggestionOpened(long nativeNTPSnippetsBridge, int globalPosition, - int category, int categoryPosition, long publishTimestampMs, float score, - int windowOpenDisposition); + int category, int categoryIndex, int categoryPosition, long publishTimestampMs, + float score, int windowOpenDisposition); private native void nativeOnSuggestionMenuOpened(long nativeNTPSnippetsBridge, int globalPosition, int category, int categoryPosition, long publishTimestampMs, float score);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/ContentSuggestionsActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/ContentSuggestionsActivity.java index 3f356975..8ca0ed4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/ContentSuggestionsActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/ContentSuggestionsActivity.java
@@ -109,7 +109,8 @@ public void trackSnippetCategoryActionClick(int category, int position) {} @Override - public void openSnippet(int windowOpenDisposition, SnippetArticle article) {} + public void openSnippet( + int windowOpenDisposition, SnippetArticle article, int categoryIndex) {} @Override public void focusSearchBox(boolean beginVoiceSearch, String pastedText) {}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java index 4c37b57..ab722ec 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java
@@ -280,7 +280,8 @@ public void trackSnippetCategoryActionClick(int category, int position) {} @Override - public void openSnippet(int windowOpenDisposition, SnippetArticle article) { + public void openSnippet( + int windowOpenDisposition, SnippetArticle article, int categoryIndex) { throw new UnsupportedOperationException(); }
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp index 5bc655f5..7496996f 100644 --- a/chrome/app/chromeos_strings.grdp +++ b/chrome/app/chromeos_strings.grdp
@@ -6248,6 +6248,24 @@ <message name="IDS_AD_LOGIN_PASSWORD" desc="Label for Password input field on both AD domain join and AD Authorization user screens.."> Password </message> + <message name="IDS_AD_PASSWORD_CHANGE_OLD_PASSWORD" desc="Old password field hint on the Active Directory password change dialog."> + Enter old password + </message> + <message name="IDS_AD_PASSWORD_CHANGE_NEW_PASSWORD" desc="New password field hint on the Active Directory password change dialog."> + Enter new password + </message> + <message name="IDS_AD_PASSWORD_CHANGE_REPEAT_NEW_PASSWORD" desc="Repeat of the new password field hint on the Active Directory password change dialog."> + Confirm new password + </message> + <message name="IDS_AD_PASSWORD_CHANGE_MESSAGE" desc="Message to the user that the Active Directory administrator requires the user to change his/her password."> + <ph name="USER_NAME">$1</ph>, your administrator requires you to change your password. + </message> + <message name="IDS_AD_PASSWORD_CHANGE_INVALID_PASSWORD" desc="Error message for the old password field on the Active Directory password change dialog."> + The password you entered is incorrect. + </message> + <message name="IDS_AD_PASSWORD_CHANGE_PASSWORDS_MISMATCH" desc="Error message in case new password fields does not match on the Active Directory password change dialog."> + Passwords do not match. + </message> <message name="IDS_ENTERPRISE_ENROLLMENT_ATTRIBUTE_EXPLANATION" desc="Device attribute message to be shown on attribute update prompt screen."> Optional — enter new or update existing information to be associated with this device. </message>
diff --git a/chrome/browser/android/ntp/ntp_snippets_bridge.cc b/chrome/browser/android/ntp/ntp_snippets_bridge.cc index 97be3815..d920bfd 100644 --- a/chrome/browser/android/ntp/ntp_snippets_bridge.cc +++ b/chrome/browser/android/ntp/ntp_snippets_bridge.cc
@@ -347,6 +347,7 @@ const JavaParamRef<jobject>& obj, jint global_position, jint j_category_id, + jint category_index, jint category_position, jlong publish_timestamp_ms, jfloat score,
diff --git a/chrome/browser/android/ntp/ntp_snippets_bridge.h b/chrome/browser/android/ntp/ntp_snippets_bridge.h index 24856e8..2e3f051 100644 --- a/chrome/browser/android/ntp/ntp_snippets_bridge.h +++ b/chrome/browser/android/ntp/ntp_snippets_bridge.h
@@ -105,6 +105,7 @@ const base::android::JavaParamRef<jobject>& obj, jint global_position, jint j_category_id, + jint category_index, jint category_position, jlong publish_timestamp_ms, jfloat score,
diff --git a/chrome/browser/browsing_data/browsing_data_remover.h b/chrome/browser/browsing_data/browsing_data_remover.h index 79d79a2..36c2c56 100644 --- a/chrome/browser/browsing_data/browsing_data_remover.h +++ b/chrome/browser/browsing_data/browsing_data_remover.h
@@ -43,6 +43,9 @@ // } // //////////////////////////////////////////////////////////////////////////////// +// +// TODO(crbug.com/668114): BrowsingDataRemover does not currently support plugin +// data deletion. Use PluginDataRemover instead. class BrowsingDataRemover { public: // Mask used for Remove.
diff --git a/chrome/browser/browsing_data/browsing_data_remover_impl.cc b/chrome/browser/browsing_data/browsing_data_remover_impl.cc index 58c7550..710a072 100644 --- a/chrome/browser/browsing_data/browsing_data_remover_impl.cc +++ b/chrome/browser/browsing_data/browsing_data_remover_impl.cc
@@ -29,7 +29,6 @@ #include "content/public/browser/content_browser_client.h" #include "content/public/browser/download_manager.h" #include "content/public/browser/notification_service.h" -#include "content/public/browser/plugin_data_remover.h" #include "content/public/browser/storage_partition.h" #include "content/public/browser/user_metrics.h" #include "net/base/net_errors.h" @@ -45,10 +44,6 @@ #include "storage/browser/quota/special_storage_policy.h" #include "url/origin.h" -#if BUILDFLAG(ENABLE_PLUGINS) -#include "chrome/browser/browsing_data/browsing_data_flash_lso_helper.h" -#endif - using base::UserMetricsAction; using content::BrowserContext; using content::BrowserThread; @@ -160,9 +155,6 @@ remove_mask_(-1), origin_type_mask_(-1), is_removing_(false), -#if BUILDFLAG(ENABLE_PLUGINS) - flash_lso_helper_(BrowsingDataFlashLSOHelper::Create(browser_context_)), -#endif sub_task_forward_callback_( base::Bind(&BrowsingDataRemoverImpl::NotifyIfDone, base::Unretained(this))), @@ -501,38 +493,6 @@ } ////////////////////////////////////////////////////////////////////////////// - // REMOVE_PLUGINS -#if BUILDFLAG(ENABLE_PLUGINS) - // Plugin is data not separated for protected and unprotected web origins. We - // check the origin_type_mask_ to prevent unintended deletion. - if (remove_mask & REMOVE_PLUGIN_DATA && - origin_type_mask_ & BrowsingDataHelper::UNPROTECTED_WEB) { - content::RecordAction(UserMetricsAction("ClearBrowsingData_LSOData")); - clear_plugin_data_count_ = 1; - - if (filter_builder.IsEmptyBlacklist()) { - DCHECK(!plugin_data_remover_); - plugin_data_remover_.reset( - content::PluginDataRemover::Create(browser_context_)); - base::WaitableEvent* event = - plugin_data_remover_->StartRemoving(delete_begin_); - - base::WaitableEventWatcher::EventCallback watcher_callback = - base::Bind(&BrowsingDataRemoverImpl::OnWaitableEventSignaled, - weak_ptr_factory_.GetWeakPtr()); - watcher_.StartWatching(event, watcher_callback); - } else { - // TODO(msramek): Store filters from the currently executed task on the - // object to avoid having to copy them to callback methods. - flash_lso_helper_->StartFetching(base::Bind( - &BrowsingDataRemoverImpl::OnSitesWithFlashDataFetched, - weak_ptr_factory_.GetWeakPtr(), - filter_builder.BuildPluginFilter())); - } - } -#endif - - ////////////////////////////////////////////////////////////////////////////// // CACHE if (remove_mask & REMOVE_CACHE) { // Tell the renderers to clear their cache. @@ -605,13 +565,6 @@ storage_partition_for_testing_ = storage_partition; } -#if BUILDFLAG(ENABLE_PLUGINS) -void BrowsingDataRemoverImpl::OverrideFlashLSOHelperForTesting( - scoped_refptr<BrowsingDataFlashLSOHelper> flash_lso_helper) { - flash_lso_helper_ = flash_lso_helper; -} -#endif - const base::Time& BrowsingDataRemoverImpl::GetLastUsedBeginTime() { return delete_begin_; } @@ -650,8 +603,7 @@ !clear_cache_.is_pending() && !clear_channel_ids_.is_pending() && !clear_http_auth_cache_.is_pending() && - !clear_storage_partition_data_.is_pending() && - !clear_plugin_data_count_; + !clear_storage_partition_data_.is_pending(); } void BrowsingDataRemoverImpl::Notify() { @@ -708,46 +660,3 @@ Notify(); } - -#if BUILDFLAG(ENABLE_PLUGINS) -void BrowsingDataRemoverImpl::OnWaitableEventSignaled( - base::WaitableEvent* waitable_event) { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - - DCHECK_EQ(1, clear_plugin_data_count_); - clear_plugin_data_count_ = 0; - - plugin_data_remover_.reset(); - watcher_.StopWatching(); - NotifyIfDone(); -} - -void BrowsingDataRemoverImpl::OnSitesWithFlashDataFetched( - base::Callback<bool(const std::string&)> plugin_filter, - const std::vector<std::string>& sites) { - DCHECK_EQ(1, clear_plugin_data_count_); - clear_plugin_data_count_ = 0; - - std::vector<std::string> sites_to_delete; - for (const std::string& site : sites) { - if (plugin_filter.Run(site)) - sites_to_delete.push_back(site); - } - - clear_plugin_data_count_ = sites_to_delete.size(); - - for (const std::string& site : sites_to_delete) { - flash_lso_helper_->DeleteFlashLSOsForSite( - site, - base::Bind(&BrowsingDataRemoverImpl::OnFlashDataDeleted, - weak_ptr_factory_.GetWeakPtr())); - } - - NotifyIfDone(); -} - -void BrowsingDataRemoverImpl::OnFlashDataDeleted() { - clear_plugin_data_count_--; - NotifyIfDone(); -} -#endif
diff --git a/chrome/browser/browsing_data/browsing_data_remover_impl.h b/chrome/browser/browsing_data/browsing_data_remover_impl.h index 36204eb..1e57134 100644 --- a/chrome/browser/browsing_data/browsing_data_remover_impl.h +++ b/chrome/browser/browsing_data/browsing_data_remover_impl.h
@@ -25,12 +25,10 @@ #include "url/gurl.h" class BrowsingDataFilterBuilder; -class BrowsingDataFlashLSOHelper; class BrowsingDataRemoverFactory; namespace content { class BrowserContext; -class PluginDataRemover; class StoragePartition; } @@ -132,11 +130,6 @@ void OverrideStoragePartitionForTesting( content::StoragePartition* storage_partition); -#if BUILDFLAG(ENABLE_PLUGINS) - void OverrideFlashLSOHelperForTesting( - scoped_refptr<BrowsingDataFlashLSOHelper> flash_lso_helper); -#endif - protected: // Use BrowsingDataRemoverFactory::GetForBrowserContext to get an instance of // this class. The constructor is protected so that the class is mockable. @@ -191,19 +184,6 @@ // not already removing, and vice-versa. void SetRemoving(bool is_removing); -#if BUILDFLAG(ENABLE_PLUGINS) - // Called when plugin data has been cleared. Invokes NotifyIfDone. - void OnWaitableEventSignaled(base::WaitableEvent* waitable_event); - - // Called when the list of |sites| storing Flash LSO cookies is fetched. - void OnSitesWithFlashDataFetched( - base::Callback<bool(const std::string&)> plugin_filter, - const std::vector<std::string>& sites); - - // Indicates that LSO cookies for one website have been deleted. - void OnFlashDataDeleted(); -#endif - // Executes the next removal task. Called after the previous task was finished // or directly from Remove() if the task queue was empty. void RunNextTask(); @@ -260,15 +240,6 @@ // to artificially delay completion. Used for testing. static CompletionInhibitor* completion_inhibitor_; -#if BUILDFLAG(ENABLE_PLUGINS) - // Used to delete plugin data. - std::unique_ptr<content::PluginDataRemover> plugin_data_remover_; - base::WaitableEventWatcher watcher_; - - // Used for per-site plugin data deletion. - scoped_refptr<BrowsingDataFlashLSOHelper> flash_lso_helper_; -#endif - // A callback to NotifyIfDone() used by SubTasks instances. const base::Closure sub_task_forward_callback_; @@ -280,9 +251,6 @@ SubTask clear_channel_ids_; SubTask clear_http_auth_cache_; SubTask clear_storage_partition_data_; - // Counts the number of plugin data tasks. Should be the number of LSO cookies - // to be deleted, or 1 while we're fetching LSO cookies or deleting in bulk. - int clear_plugin_data_count_ = 0; // Observers of the global state and individual tasks. base::ObserverList<Observer, true> observer_list_;
diff --git a/chrome/browser/browsing_data/browsing_data_remover_unittest.cc b/chrome/browser/browsing_data/browsing_data_remover_unittest.cc index 69d02d2..446d9b8d 100644 --- a/chrome/browser/browsing_data/browsing_data_remover_unittest.cc +++ b/chrome/browser/browsing_data/browsing_data_remover_unittest.cc
@@ -1111,9 +1111,9 @@ public: explicit RemovePluginDataTester(TestingProfile* profile) : helper_(new TestBrowsingDataFlashLSOHelper(profile)) { - static_cast<BrowsingDataRemoverImpl*>( - BrowsingDataRemoverFactory::GetForBrowserContext(profile)) - ->OverrideFlashLSOHelperForTesting(helper_); + static_cast<ChromeBrowsingDataRemoverDelegate*>( + BrowsingDataRemoverFactory::GetForBrowserContext(profile) + ->GetEmbedderDelegate())->OverrideFlashLSOHelperForTesting(helper_); } void AddDomain(const std::string& domain) {
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc index ac5a6495..c2e79d0 100644 --- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc +++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
@@ -64,6 +64,7 @@ #include "components/previews/core/previews_ui_service.h" #include "components/search_engines/template_url_service.h" #include "components/sessions/core/tab_restore_service.h" +#include "content/public/browser/plugin_data_remover.h" #include "content/public/browser/ssl_host_state_delegate.h" #include "content/public/browser/storage_partition.h" #include "content/public/browser/user_metrics.h" @@ -105,6 +106,10 @@ #include "chrome/browser/media/webrtc/webrtc_log_util.h" #endif +#if BUILDFLAG(ENABLE_PLUGINS) +#include "chrome/browser/browsing_data/browsing_data_flash_lso_helper.h" +#endif + using base::UserMetricsAction; using content::BrowserContext; using content::BrowserThread; @@ -287,6 +292,9 @@ clear_webrtc_logs_(sub_task_forward_callback_), #endif clear_auto_sign_in_(sub_task_forward_callback_), +#if BUILDFLAG(ENABLE_PLUGINS) + flash_lso_helper_(BrowsingDataFlashLSOHelper::Create(browser_context)), +#endif #if defined(OS_ANDROID) webapp_registry_(new WebappRegistry()), #endif @@ -791,6 +799,46 @@ } ////////////////////////////////////////////////////////////////////////////// + // REMOVE_PLUGINS + // Plugins are known to //content and their bulk deletion is implemented in + // PluginDataRemover. However, the filtered deletion uses + // BrowsingDataFlashLSOHelper which (currently) has strong dependencies + // on //chrome. + // TODO(msramek): Investigate these dependencies and move the plugin deletion + // to BrowsingDataRemoverImpl in //content. Note that code in //content + // can simply take advantage of PluginDataRemover directly to delete plugin + // data in bulk. +#if BUILDFLAG(ENABLE_PLUGINS) + // Plugin is data not separated for protected and unprotected web origins. We + // check the origin_type_mask_ to prevent unintended deletion. + if (remove_mask & BrowsingDataRemover::REMOVE_PLUGIN_DATA && + origin_type_mask & BrowsingDataHelper::UNPROTECTED_WEB) { + content::RecordAction(UserMetricsAction("ClearBrowsingData_LSOData")); + clear_plugin_data_count_ = 1; + + if (filter_builder.IsEmptyBlacklist()) { + DCHECK(!plugin_data_remover_); + plugin_data_remover_.reset( + content::PluginDataRemover::Create(profile_)); + base::WaitableEvent* event = + plugin_data_remover_->StartRemoving(delete_begin_); + + base::WaitableEventWatcher::EventCallback watcher_callback = base::Bind( + &ChromeBrowsingDataRemoverDelegate::OnWaitableEventSignaled, + weak_ptr_factory_.GetWeakPtr()); + watcher_.StartWatching(event, watcher_callback); + } else { + // TODO(msramek): Store filters from the currently executed task on the + // object to avoid having to copy them to callback methods. + flash_lso_helper_->StartFetching(base::Bind( + &ChromeBrowsingDataRemoverDelegate::OnSitesWithFlashDataFetched, + weak_ptr_factory_.GetWeakPtr(), + filter_builder.BuildPluginFilter())); + } + } +#endif + + ////////////////////////////////////////////////////////////////////////////// // REMOVE_MEDIA_LICENSES if (remove_mask & BrowsingDataRemover::REMOVE_MEDIA_LICENSES) { // TODO(jrummell): This UMA should be renamed to indicate it is for Media @@ -903,7 +951,8 @@ #if BUILDFLAG(ENABLE_WEBRTC) !clear_webrtc_logs_.is_pending() && #endif - !clear_auto_sign_in_.is_pending(); + !clear_auto_sign_in_.is_pending() && + !clear_plugin_data_count_; } #if defined(OS_ANDROID) @@ -913,6 +962,13 @@ } #endif +#if BUILDFLAG(ENABLE_PLUGINS) +void ChromeBrowsingDataRemoverDelegate::OverrideFlashLSOHelperForTesting( + scoped_refptr<BrowsingDataFlashLSOHelper> flash_lso_helper) { + flash_lso_helper_ = flash_lso_helper; +} +#endif + void ChromeBrowsingDataRemoverDelegate::OnKeywordsLoaded( base::Callback<bool(const GURL&)> url_filter) { // Deletes the entries from the model. @@ -932,16 +988,6 @@ NotifyIfDone(); } -#if BUILDFLAG(ENABLE_PLUGINS) -void ChromeBrowsingDataRemoverDelegate:: -OnDeauthorizeFlashContentLicensesCompleted( - uint32_t request_id, - bool /* success */) { - DCHECK_EQ(request_id, deauthorize_flash_content_licenses_request_id_); - clear_flash_content_licenses_.GetCompletionCallback().Run(); -} -#endif - #if defined(OS_CHROMEOS) void ChromeBrowsingDataRemoverDelegate::OnClearPlatformKeys( chromeos::DBusMethodCallStatus call_status, @@ -951,3 +997,54 @@ clear_platform_keys_.GetCompletionCallback().Run(); } #endif + +#if BUILDFLAG(ENABLE_PLUGINS) +void ChromeBrowsingDataRemoverDelegate::OnWaitableEventSignaled( + base::WaitableEvent* waitable_event) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + DCHECK_EQ(1, clear_plugin_data_count_); + clear_plugin_data_count_ = 0; + + plugin_data_remover_.reset(); + watcher_.StopWatching(); + NotifyIfDone(); +} + +void ChromeBrowsingDataRemoverDelegate::OnSitesWithFlashDataFetched( + base::Callback<bool(const std::string&)> plugin_filter, + const std::vector<std::string>& sites) { + DCHECK_EQ(1, clear_plugin_data_count_); + clear_plugin_data_count_ = 0; + + std::vector<std::string> sites_to_delete; + for (const std::string& site : sites) { + if (plugin_filter.Run(site)) + sites_to_delete.push_back(site); + } + + clear_plugin_data_count_ = sites_to_delete.size(); + + for (const std::string& site : sites_to_delete) { + flash_lso_helper_->DeleteFlashLSOsForSite( + site, + base::Bind(&ChromeBrowsingDataRemoverDelegate::OnFlashDataDeleted, + weak_ptr_factory_.GetWeakPtr())); + } + + NotifyIfDone(); +} + +void ChromeBrowsingDataRemoverDelegate::OnFlashDataDeleted() { + clear_plugin_data_count_--; + NotifyIfDone(); +} + +void ChromeBrowsingDataRemoverDelegate:: +OnDeauthorizeFlashContentLicensesCompleted( + uint32_t request_id, + bool /* success */) { + DCHECK_EQ(request_id, deauthorize_flash_content_licenses_request_id_); + clear_flash_content_licenses_.GetCompletionCallback().Run(); +} +#endif
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h index 3814224..ac542631 100644 --- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h +++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h
@@ -29,11 +29,13 @@ #include "chromeos/dbus/dbus_method_call_status.h" #endif +class BrowsingDataFlashLSOHelper; class Profile; class WebappRegistry; namespace content { class BrowserContext; +class PluginDataRemover; } // A delegate used by BrowsingDataRemover to delete data specific to Chrome @@ -87,6 +89,12 @@ std::unique_ptr<WebappRegistry> webapp_registry); #endif +#if BUILDFLAG(ENABLE_PLUGINS) + // Used for testing. + void OverrideFlashLSOHelperForTesting( + scoped_refptr<BrowsingDataFlashLSOHelper> flash_lso_helper); +#endif + private: // If AllDone(), calls the callback provided in RemoveEmbedderData(). void NotifyIfDone(); @@ -107,6 +115,17 @@ void OnClearedCookies(); #if BUILDFLAG(ENABLE_PLUGINS) + // Called when plugin data has been cleared. Invokes NotifyIfDone. + void OnWaitableEventSignaled(base::WaitableEvent* waitable_event); + + // Called when the list of |sites| storing Flash LSO cookies is fetched. + void OnSitesWithFlashDataFetched( + base::Callback<bool(const std::string&)> plugin_filter, + const std::vector<std::string>& sites); + + // Indicates that LSO cookies for one website have been deleted. + void OnFlashDataDeleted(); + // PepperFlashSettingsManager::Client implementation. void OnDeauthorizeFlashContentLicensesCompleted(uint32_t request_id, bool success) override; @@ -152,13 +171,22 @@ SubTask clear_precache_history_; SubTask clear_offline_page_data_; #endif - #if BUILDFLAG(ENABLE_WEBRTC) SubTask clear_webrtc_logs_; #endif SubTask clear_auto_sign_in_; + // Counts the number of plugin data tasks. Should be the number of LSO cookies + // to be deleted, or 1 while we're fetching LSO cookies or deleting in bulk. + int clear_plugin_data_count_ = 0; #if BUILDFLAG(ENABLE_PLUGINS) + // Used to delete plugin data. + std::unique_ptr<content::PluginDataRemover> plugin_data_remover_; + base::WaitableEventWatcher watcher_; + + // Used for per-site plugin data deletion. + scoped_refptr<BrowsingDataFlashLSOHelper> flash_lso_helper_; + uint32_t deauthorize_flash_content_licenses_request_id_ = 0; // Used to deauthorize content licenses for Pepper Flash.
diff --git a/chrome/browser/chromeos/login/oobe_screen.cc b/chrome/browser/chromeos/login/oobe_screen.cc index 0f0cdf8..92678791 100644 --- a/chrome/browser/chromeos/login/oobe_screen.cc +++ b/chrome/browser/chromeos/login/oobe_screen.cc
@@ -41,6 +41,8 @@ "device-disabled", // SCREEN_DEVICE_DISABLED "unrecoverable-cryptohome-error", // SCREEN_UNRECOVERABLE_CRYPTOHOME_ERROR "userBoard", // SCREEN_USER_SELECTION + // SCREEN_ACTIVE_DIRECTORY_PASSWORD_CHANGE + "ad-password-change", "login", // SCREEN_SPECIAL_LOGIN "oobe", // SCREEN_SPECIAL_OOBE "test:nowindow", // SCREEN_TEST_NO_WINDOW
diff --git a/chrome/browser/chromeos/login/oobe_screen.h b/chrome/browser/chromeos/login/oobe_screen.h index 1e31069a..7f2a334 100644 --- a/chrome/browser/chromeos/login/oobe_screen.h +++ b/chrome/browser/chromeos/login/oobe_screen.h
@@ -43,6 +43,7 @@ SCREEN_DEVICE_DISABLED, SCREEN_UNRECOVERABLE_CRYPTOHOME_ERROR, SCREEN_USER_SELECTION, + SCREEN_ACTIVE_DIRECTORY_PASSWORD_CHANGE, // Special "first screen" that initiates login flow. SCREEN_SPECIAL_LOGIN,
diff --git a/chrome/browser/chromeos/login/screens/core_oobe_actor.h b/chrome/browser/chromeos/login/screens/core_oobe_actor.h index 92f5a0f..1200caa 100644 --- a/chrome/browser/chromeos/login/screens/core_oobe_actor.h +++ b/chrome/browser/chromeos/login/screens/core_oobe_actor.h
@@ -43,6 +43,8 @@ virtual void InitDemoModeDetection() = 0; virtual void StopDemoModeDetection() = 0; virtual void UpdateKeyboardState() = 0; + virtual void ShowActiveDirectoryPasswordChangeScreen( + const std::string& username) = 0; }; } // namespace chromeos
diff --git a/chrome/browser/resources/chromeos/login/active_directory_password_change.html b/chrome/browser/resources/chromeos/login/active_directory_password_change.html new file mode 100644 index 0000000..3f21f19 --- /dev/null +++ b/chrome/browser/resources/chromeos/login/active_directory_password_change.html
@@ -0,0 +1,67 @@ +<!-- Copyright 2016 The Chromium Authors. All rights reserved. + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. --> + +<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/classes/iron-flex-layout.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/animations/fade-in-animation.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/animations/fade-out-animation.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animatable.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animated-pages.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html"> + +<!-- + Offline UI for the Active Directory password change. + + Attributes: + 'username' - User principal name. + Methods: + 'reset' - resets to the initial state. + Events: + 'authCompleted' - Fired when user enters old password and confirms new one. + Fires with an argument which contains: + { 'username': <username>, + 'oldPassword': <typed old password>, + 'newPassword': <typed new password>, + } +--> +<dom-module id="active-directory-password-change"> + <link rel="stylesheet" href="gaia_password_changed.css"> + <template> + <neon-animated-pages id="animatedPages" class="fit" + entry-animation="fade-in-animation" exit-animation="fade-out-animation" + selected="0"> + <neon-animatable class="fit"> + <gaia-card id="gaiaCard" class="fit"> + <div class="header flex vertical layout end-justified start"> + <h1 id="welcomeMessage" class="welcome-message"> + [[computeWelcomeMessage_(username)]] + </h1> + </div> + <div class="footer flex vertical layout justified"> + <gaia-input-form on-submit="onSubmit_" + i18n-values="button-text:offlineLoginNextBtn"> + <gaia-input id="oldPassword" type="password" required + i18n-values="error:adOldPasswordError; + label:adEnterOldPasswordHint"> + </gaia-input> + <gaia-input id="newPassword1" type="password" required + i18n-values="label:adEnterNewPasswordHint"> + </gaia-input> + <gaia-input id="newPassword2" type="password" required + i18n-values="error:adNewPasswordError; + label:adRepeatNewPasswordHint"> + </gaia-input> + </gaia-input-form> + </div> + </gaia-card> + </neon-animatable> + <neon-animatable class="fit"> + <throbber-notice class="fit" i18n-values="text:gaiaLoading"> + </throbber-notice> + </neon-animatable> + </neon-animated-pages> + <navigation-bar id="navigation" close-visible on-close="onClose_"> + </navigation-bar> + </template> +</dom-module>
diff --git a/chrome/browser/resources/chromeos/login/active_directory_password_change.js b/chrome/browser/resources/chromeos/login/active_directory_password_change.js new file mode 100644 index 0000000..2ba38f7e --- /dev/null +++ b/chrome/browser/resources/chromeos/login/active_directory_password_change.js
@@ -0,0 +1,66 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview Polymer element for Active Directory password change screen. + */ +Polymer({ + is: 'active-directory-password-change', + + properties: { + /** + * The user principal name. + */ + username: String, + }, + + /** @public */ + reset: function() { + this.$.animatedPages.selected = 0; + this.$.oldPassword.value = ''; + this.$.newPassword1.value = ''; + this.$.newPassword2.value = ''; + this.updateNavigation_(); + }, + + /** @private */ + computeWelcomeMessage_: function(username) { + return loadTimeData.getStringF('adPasswordChangeMessage', username); + }, + + /** @private */ + onSubmit_: function() { + if (!this.$.oldPassword.checkValidity() || + !this.$.newPassword1.checkValidity()) { + return; + } + if (this.$.newPassword1.value != this.$.newPassword2.value) { + this.$.newPassword2.isInvalid = true; + return; + } + this.$.animatedPages.selected++; + this.updateNavigation_(); + var msg = { + 'username': this.username, + 'oldPassword': this.$.oldPassword.value, + 'newPassword': this.$.newPassword1.value, + }; + this.$.oldPassword.value = ''; + this.$.newPassword1.value = ''; + this.$.newPassword2.value = ''; + this.fire('authCompleted', msg); + }, + + /** @private */ + onClose_: function() { + if (!this.$.navigation.closeVisible) + return; + this.fire('cancel'); + }, + + /** @private */ + updateNavigation_: function() { + this.$.navigation.closeVisible = (this.$.animatedPages.selected == 0); + }, +});
diff --git a/chrome/browser/resources/chromeos/login/custom_elements_login.html b/chrome/browser/resources/chromeos/login/custom_elements_login.html index 02c4cb76..a4551a9 100644 --- a/chrome/browser/resources/chromeos/login/custom_elements_login.html +++ b/chrome/browser/resources/chromeos/login/custom_elements_login.html
@@ -12,5 +12,6 @@ <include src="navigation_bar.html"> <include src="unrecoverable_cryptohome_error_card.html"> <include src="offline_ad_login.html"> +<include src="active_directory_password_change.html"> <script src="chrome://oobe/custom_elements.js"></script>
diff --git a/chrome/browser/resources/chromeos/login/custom_elements_login.js b/chrome/browser/resources/chromeos/login/custom_elements_login.js index 691b243f..3b04fc93 100644 --- a/chrome/browser/resources/chromeos/login/custom_elements_login.js +++ b/chrome/browser/resources/chromeos/login/custom_elements_login.js
@@ -16,3 +16,4 @@ // <include src="navigation_bar.js"> // <include src="unrecoverable_cryptohome_error_card.js"> // <include src="offline_ad_login.js"> +// <include src="active_directory_password_change.js">
diff --git a/chrome/browser/resources/chromeos/login/custom_elements_oobe.html b/chrome/browser/resources/chromeos/login/custom_elements_oobe.html index 05f00cf..112bb89 100644 --- a/chrome/browser/resources/chromeos/login/custom_elements_oobe.html +++ b/chrome/browser/resources/chromeos/login/custom_elements_oobe.html
@@ -24,5 +24,6 @@ <include src="oobe_welcome_dialog.html"> <include src="oobe_welcome.html"> <include src="offline_ad_login.html"> +<include src="active_directory_password_change.html"> <script src="chrome://oobe/custom_elements.js"></script>
diff --git a/chrome/browser/resources/chromeos/login/custom_elements_oobe.js b/chrome/browser/resources/chromeos/login/custom_elements_oobe.js index 663e622..ab6875f 100644 --- a/chrome/browser/resources/chromeos/login/custom_elements_oobe.js +++ b/chrome/browser/resources/chromeos/login/custom_elements_oobe.js
@@ -34,3 +34,4 @@ // <include src="oobe_welcome_dialog.js"> // <include src="oobe_welcome.js"> // <include src="offline_ad_login.js"> +// <include src="active_directory_password_change.js">
diff --git a/chrome/browser/resources/chromeos/login/login.js b/chrome/browser/resources/chromeos/login/login.js index 002345b..8580484 100644 --- a/chrome/browser/resources/chromeos/login/login.js +++ b/chrome/browser/resources/chromeos/login/login.js
@@ -36,6 +36,7 @@ login.FatalErrorScreen.register(); login.DeviceDisabledScreen.register(); login.UnrecoverableCryptohomeErrorScreen.register(); + login.ActiveDirectoryPasswordChangeScreen.register(/* lazyInit= */ true); cr.ui.Bubble.decorate($('bubble')); login.HeaderBar.decorate($('login-header-bar'));
diff --git a/chrome/browser/resources/chromeos/login/login_non_lock_shared.html b/chrome/browser/resources/chromeos/login/login_non_lock_shared.html index 4154892..4d477db 100644 --- a/chrome/browser/resources/chromeos/login/login_non_lock_shared.html +++ b/chrome/browser/resources/chromeos/login/login_non_lock_shared.html
@@ -32,6 +32,7 @@ <link rel="stylesheet" href="screen_fatal_error.css"> <link rel="stylesheet" href="screen_device_disabled.css"> <link rel="stylesheet" href="screen_unrecoverable_cryptohome_error.css"> +<link rel="stylesheet" href="screen_active_directory_password_change.css"> <link rel="stylesheet" href="../../options/chromeos/bluetooth.css">
diff --git a/chrome/browser/resources/chromeos/login/login_non_lock_shared.js b/chrome/browser/resources/chromeos/login/login_non_lock_shared.js index a0d72e1..0153ca3 100644 --- a/chrome/browser/resources/chromeos/login/login_non_lock_shared.js +++ b/chrome/browser/resources/chromeos/login/login_non_lock_shared.js
@@ -29,6 +29,7 @@ // <include src="screen_fatal_error.js"> // <include src="screen_device_disabled.js"> // <include src="screen_unrecoverable_cryptohome_error.js"> +// <include src="screen_active_directory_password_change.js"> // <include src="../../gaia_auth_host/authenticator.js">
diff --git a/chrome/browser/resources/chromeos/login/login_screens.html b/chrome/browser/resources/chromeos/login/login_screens.html index 8b928823..765877c 100644 --- a/chrome/browser/resources/chromeos/login/login_screens.html +++ b/chrome/browser/resources/chromeos/login/login_screens.html
@@ -16,3 +16,4 @@ <include src="screen_fatal_error.html"> <include src="screen_device_disabled.html"> <include src="screen_unrecoverable_cryptohome_error.html"> +<include src="screen_active_directory_password_change.html">
diff --git a/chrome/browser/resources/chromeos/login/login_shared.js b/chrome/browser/resources/chromeos/login/login_shared.js index ff3b386..160da795 100644 --- a/chrome/browser/resources/chromeos/login/login_shared.js +++ b/chrome/browser/resources/chromeos/login/login_shared.js
@@ -187,6 +187,14 @@ }; /** + * Shows Active Directory password change screen. + * @param {string} username Name of the user that should change the password. + */ + Oobe.showActiveDirectoryPasswordChangeScreen = function(username) { + DisplayManager.showActiveDirectoryPasswordChangeScreen(username); + }; + + /** * Show user-pods. */ Oobe.showUserPods = function() {
diff --git a/chrome/browser/resources/chromeos/login/oobe.js b/chrome/browser/resources/chromeos/login/oobe.js index 1659cdc2..6386ed6 100644 --- a/chrome/browser/resources/chromeos/login/oobe.js +++ b/chrome/browser/resources/chromeos/login/oobe.js
@@ -117,6 +117,7 @@ login.ControllerPairingScreen.register(); login.HostPairingScreen.register(); login.DeviceDisabledScreen.register(); + login.ActiveDirectoryPasswordChangeScreen.register(/* lazyInit= */ true); cr.ui.Bubble.decorate($('bubble')); login.HeaderBar.decorate($('login-header-bar'));
diff --git a/chrome/browser/resources/chromeos/login/oobe_screens.html b/chrome/browser/resources/chromeos/login/oobe_screens.html index fc8a619f..ad896b41 100644 --- a/chrome/browser/resources/chromeos/login/oobe_screens.html +++ b/chrome/browser/resources/chromeos/login/oobe_screens.html
@@ -23,3 +23,4 @@ <include src="screen_confirm_password.html"> <include src="screen_fatal_error.html"> <include src="screen_device_disabled.html"> +<include src="screen_active_directory_password_change.html">
diff --git a/chrome/browser/resources/chromeos/login/screen_active_directory_password_change.css b/chrome/browser/resources/chromeos/login/screen_active_directory_password_change.css new file mode 100644 index 0000000..81a55ef --- /dev/null +++ b/chrome/browser/resources/chromeos/login/screen_active_directory_password_change.css
@@ -0,0 +1,14 @@ +/* Copyright 2016 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#ad-password-change { + bottom: 0; + display: block; + height: 528px; /* Should be the same as #gaia-signin. */ + left: 0; + position: absolute; + right: 0; + top: 0; + width: 448px; /* Should be the same as #gaia-signin. */ +}
diff --git a/chrome/browser/resources/chromeos/login/screen_active_directory_password_change.html b/chrome/browser/resources/chromeos/login/screen_active_directory_password_change.html new file mode 100644 index 0000000..8dc8f72 --- /dev/null +++ b/chrome/browser/resources/chromeos/login/screen_active_directory_password_change.html
@@ -0,0 +1,8 @@ +<link rel="import" href="chrome://oobe/custom_elements.html"> + +<div id="ad-password-change" class="step faded hidden migrate no-logo" + hidden> + <active-directory-password-change id="active-directory-password-change" + class="fit"> + </active-directory-password-change> +</div>
diff --git a/chrome/browser/resources/chromeos/login/screen_active_directory_password_change.js b/chrome/browser/resources/chromeos/login/screen_active_directory_password_change.js new file mode 100644 index 0000000..ec04944 --- /dev/null +++ b/chrome/browser/resources/chromeos/login/screen_active_directory_password_change.js
@@ -0,0 +1,52 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview Active Directory password change screen implementation. + */ +login.createScreen('ActiveDirectoryPasswordChangeScreen', 'ad-password-change', + function() { + return { + EXTERNAL_API: [ + 'show' + ], + + adPasswordChanged_: null, + + /** @override */ + decorate: function() { + this.adPasswordChanged_ = $('active-directory-password-change'); + this.adPasswordChanged_.addEventListener('cancel', + this.cancel.bind(this)); + + this.adPasswordChanged_.addEventListener('authCompleted', + function(e) { + chrome.send('completeAdPasswordChange', + [e.detail.username, + e.detail.oldPassword, + e.detail.newPassword]); + }); + }, + + /** + * Cancels password changing and drops the user back to the login screen. + */ + cancel: function() { + Oobe.showUserPods(); + }, + + /** + * Shows password changed screen. + * @param {string} username Name of user that should change the password. + */ + show: function(username) { + // We'll get here after the successful Active Directory authentication. + // It assumes session is about to start so hides login screen controls. + Oobe.getInstance().headerHidden = true; + Oobe.showScreen({id: SCREEN_ACTIVE_DIRECTORY_PASSWORD_CHANGE}); + this.adPasswordChanged_.reset(); + this.adPasswordChanged_.username = username; + } + }; +});
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_private.mm b/chrome/browser/ui/cocoa/browser_window_controller_private.mm index fb9e2108..ab3fa19d 100644 --- a/chrome/browser/ui/cocoa/browser_window_controller_private.mm +++ b/chrome/browser/ui/cocoa/browser_window_controller_private.mm
@@ -612,6 +612,8 @@ } - (void)windowDidEnterFullScreen:(NSNotification*)notification { + [tabStripController_ setVisualEffectsDisabledForFullscreen:YES]; + // In Yosemite, some combination of the titlebar and toolbar always show in // full-screen mode. We do not want either to show. Search for the window that // contains the views, and hide it. There is no need to ever unhide the view. @@ -678,6 +680,8 @@ } - (void)windowWillExitFullScreen:(NSNotification*)notification { + [tabStripController_ setVisualEffectsDisabledForFullscreen:NO]; + if (fullscreenLowPowerCoordinator_) fullscreenLowPowerCoordinator_->SetInFullscreenTransition(true);
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm b/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm index a28a7fb..a22fc45 100644 --- a/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm +++ b/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm
@@ -700,6 +700,25 @@ EXPECT_TRUE([[contentView hitTest:point] isDescendantOf:bookmarkView]); } +// Check that when the window becomes/resigns main, the tab strip's background +// view is redrawn. +TEST_F(BrowserWindowControllerTest, TabStripBackgroundViewRedrawTest) { + NSView* view = controller_.tabStripBackgroundView; + id partial_mock = [OCMockObject partialMockForObject:view]; + + [[partial_mock expect] setNeedsDisplay:YES]; + [[NSNotificationCenter defaultCenter] + postNotificationName:NSWindowDidBecomeMainNotification + object:controller_.window]; + [partial_mock verify]; + + [[partial_mock expect] setNeedsDisplay:YES]; + [[NSNotificationCenter defaultCenter] + postNotificationName:NSWindowDidResignMainNotification + object:controller_.window]; + [partial_mock verify]; +} + @interface BrowserWindowControllerFakeFullscreen : BrowserWindowController { @private // We release the window ourselves, so we don't have to rely on the unittest
diff --git a/chrome/browser/ui/cocoa/browser_window_fullscreen_transition.mm b/chrome/browser/ui/cocoa/browser_window_fullscreen_transition.mm index 43d28e1..2855e87 100644 --- a/chrome/browser/ui/cocoa/browser_window_fullscreen_transition.mm +++ b/chrome/browser/ui/cocoa/browser_window_fullscreen_transition.mm
@@ -54,6 +54,40 @@ } // namespace +// This view draws a dummy toolbar over the resized content view during +// the exit fullscreen animation. It is removed at the end of the animation. +@interface FullscreenTabStripBackgroundView : NSView { + base::scoped_nsobject<NSColor> windowBackgroundColor_; +} + +- (instancetype)initWithFrame:(NSRect)frame background:(NSColor*)color; + +@end + +@implementation FullscreenTabStripBackgroundView + +- (instancetype)initWithFrame:(NSRect)frame background:(NSColor*)color { + if ((self = [super initWithFrame:frame])) { + windowBackgroundColor_.reset([color copy]); + } + return self; +} + +// Override this method so that we can paint the toolbar in this view. +// This method first fill itself with the toolbar's background. After that, +// it will paint the window's theme if applicable. +- (void)drawRect:(NSRect)frame { + [windowBackgroundColor_ set]; + NSRectFillUsingOperation(frame, NSCompositeDestinationOver); + + [FramedBrowserWindow drawWindowThemeInDirtyRect:frame + forView:self + bounds:[self bounds] + forceBlackBackground:NO]; +} + +@end + @interface BrowserWindowFullscreenTransition () <CAAnimationDelegate, CALayerDelegate> { // Flag to keep track of whether we are entering or exiting fullscreen. @@ -100,7 +134,7 @@ NSRect finalFrame_; // This view draws the tabstrip background during the exit animation. - base::scoped_nsobject<TabStripBackgroundView> + base::scoped_nsobject<FullscreenTabStripBackgroundView> fullscreenTabStripBackgroundView_; // Locks and unlocks the FullSizeContentWindow. @@ -328,7 +362,9 @@ [primaryWindow_ forceContentViewFrame:relativeContentFinalFrame]; fullscreenTabStripBackgroundView_.reset( - [[TabStripBackgroundView alloc] initWithFrame:finalFrame_]); + [[FullscreenTabStripBackgroundView alloc] + initWithFrame:finalFrame_ + background:primaryWindowInitialBackgroundColor_]); [fullscreenTabStripBackgroundView_ setFrameOrigin:NSZeroPoint]; [contentView addSubview:fullscreenTabStripBackgroundView_.get() positioned:NSWindowBelow
diff --git a/chrome/browser/ui/cocoa/floating_bar_backing_view.h b/chrome/browser/ui/cocoa/floating_bar_backing_view.h index a55b1239..bfd4114 100644 --- a/chrome/browser/ui/cocoa/floating_bar_backing_view.h +++ b/chrome/browser/ui/cocoa/floating_bar_backing_view.h
@@ -7,10 +7,10 @@ #import <Cocoa/Cocoa.h> -#import "chrome/browser/ui/cocoa/tabs/tab_strip_background_view.h" +#import "chrome/browser/ui/cocoa/themed_window.h" // A custom view that draws the tab strip background for fullscreen windows. -@interface FloatingBarBackingView : TabStripBackgroundView +@interface FloatingBarBackingView : NSView<ThemedWindowDrawing> @end #endif // CHROME_BROWSER_UI_COCOA_FLOATING_BAR_BACKING_VIEW_H_
diff --git a/chrome/browser/ui/cocoa/floating_bar_backing_view.mm b/chrome/browser/ui/cocoa/floating_bar_backing_view.mm index b4c34d38..96a5fff 100644 --- a/chrome/browser/ui/cocoa/floating_bar_backing_view.mm +++ b/chrome/browser/ui/cocoa/floating_bar_backing_view.mm
@@ -4,10 +4,28 @@ #include "chrome/browser/ui/cocoa/floating_bar_backing_view.h" +#import "chrome/browser/ui/cocoa/framed_browser_window.h" #import "ui/base/cocoa/appkit_utils.h" @implementation FloatingBarBackingView +- (void)drawRect:(NSRect)rect { + NSWindow* window = [self window]; + BOOL isMainWindow = [window isMainWindow]; + + if (isMainWindow) + [[NSColor windowFrameColor] set]; + else + [[NSColor windowBackgroundColor] set]; + NSRectFill(rect); + + [FramedBrowserWindow drawWindowThemeInDirtyRect:rect + forView:self + bounds:[self bounds] + forceBlackBackground:YES]; + +} + // Eat all mouse events (and do *not* pass them on to the next responder!). - (void)mouseDown:(NSEvent*)event {} - (void)rightMouseDown:(NSEvent*)event {} @@ -27,4 +45,14 @@ ui::WindowTitlebarReceivedDoubleClick([self window], self); } +// ThemedWindowDrawing implementation. + +- (void)windowDidChangeTheme { + [self setNeedsDisplay:YES]; +} + +- (void)windowDidChangeActive { + [self setNeedsDisplay:YES]; +} + @end // @implementation FloatingBarBackingView
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_background_view.h b/chrome/browser/ui/cocoa/tabs/tab_strip_background_view.h index f75f7e0..5639540 100644 --- a/chrome/browser/ui/cocoa/tabs/tab_strip_background_view.h +++ b/chrome/browser/ui/cocoa/tabs/tab_strip_background_view.h
@@ -9,11 +9,11 @@ #import "chrome/browser/ui/cocoa/themed_window.h" -// A view that draws the theme and transparency effects behind the tab strip. -// It should be behind its overlapping sibling views (window controls, tab -// strip view, profile button and fullscreen button). +// A view that draws the theme image in the top area of the window (behind the +// tab strip area). It should be arranged so that its z-order is below its +// overlapping sibling views (window controls, tab strip view, profile button +// and fullscreen button). @interface TabStripBackgroundView : NSView<ThemedWindowDrawing> -@property(nonatomic) BOOL inATabDraggingOverlayWindow; @end #endif // CHROME_BROWSER_UI_COCOA_TABS_TAB_STRIP_BACKGROUND_VIEW_H_
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_background_view.mm b/chrome/browser/ui/cocoa/tabs/tab_strip_background_view.mm index 5d6e03f0..4b32010 100644 --- a/chrome/browser/ui/cocoa/tabs/tab_strip_background_view.mm +++ b/chrome/browser/ui/cocoa/tabs/tab_strip_background_view.mm
@@ -4,43 +4,21 @@ #import "chrome/browser/ui/cocoa/tabs/tab_strip_background_view.h" -#include "chrome/browser/themes/theme_properties.h" #import "chrome/browser/ui/cocoa/framed_browser_window.h" #import "ui/base/cocoa/nsview_additions.h" -#include "ui/base/theme_provider.h" -// TODO(sdy): Remove once we no longer support 10.9 (-Wunguarded-availability). -@class NSVisualEffectView; -extern NSString* const NSAppearanceNameVibrantDark; -extern NSString* const NSAppearanceNameVibrantLight; - -@interface NSAppearance (AllowsVibrancy) -@property(readonly) BOOL allowsVibrancy; -@end -// /TODO - -@interface TabStripThemeBackgroundView : NSView -@property(nonatomic) BOOL inATabDraggingOverlayWindow; -@end - -@implementation TabStripThemeBackgroundView - -@synthesize inATabDraggingOverlayWindow = inATabDraggingOverlayWindow_; +@implementation TabStripBackgroundView - (void)drawRect:(NSRect)dirtyRect { // Only the top corners are rounded. For simplicity, round all 4 corners but // draw the bottom corners outside of the visible bounds. float cornerRadius = 4.0; - bool isFullscreen = (self.window.styleMask & NSFullScreenWindowMask) != 0; - NSRect roundedRect = [self bounds]; - if (!isFullscreen) { - roundedRect.origin.y -= cornerRadius; - roundedRect.size.height += cornerRadius; - [[NSBezierPath bezierPathWithRoundedRect:roundedRect - xRadius:cornerRadius - yRadius:cornerRadius] addClip]; - } + roundedRect.origin.y -= cornerRadius; + roundedRect.size.height += cornerRadius; + [[NSBezierPath bezierPathWithRoundedRect:roundedRect + xRadius:cornerRadius + yRadius:cornerRadius] addClip]; BOOL themed = [FramedBrowserWindow drawWindowThemeInDirtyRect:dirtyRect forView:self bounds:roundedRect @@ -48,151 +26,28 @@ // Draw a 1px border on the top edge and top corners. if (themed) { - if (!isFullscreen) { - CGFloat lineWidth = [self cr_lineWidth]; - // Inset the vertical lines by 0.5px so that the top line gets a full - // pixel. Outset the horizontal lines by 0.5px so that they are not - // visible, but still get the rounded corners to get a border. - NSRect strokeRect = - NSInsetRect(roundedRect, -lineWidth / 2, lineWidth / 2); - NSBezierPath* path = - [NSBezierPath bezierPathWithRoundedRect:strokeRect - xRadius:cornerRadius - yRadius:cornerRadius]; - [path setLineWidth:lineWidth]; - [[NSColor colorWithCalibratedWhite:1.0 alpha:0.5] set]; - [path stroke]; - } - } else if (!inATabDraggingOverlayWindow_) { - // If the window is not themed, and not being used to drag tabs between - // browser windows, decrease the tab strip background's translucency by - // overlaying it with a partially-transparent gray. The gray is somewhat - // opaque for Incognito mode, very opaque for non-Incognito mode, and - // completely opaque when the window is not active. - if (const ui::ThemeProvider* themeProvider = - [[self window] themeProvider]) { - NSColor* overlayColor = nil; - if (self.window.isMainWindow) { - NSAppearance* appearance = self.effectiveAppearance; - if ([appearance respondsToSelector:@selector(allowsVibrancy)] && - appearance.allowsVibrancy) { - overlayColor = themeProvider->GetNSColor( - ThemeProperties::COLOR_FRAME_VIBRANCY_OVERLAY); - } else if (themeProvider->InIncognitoMode()) { - overlayColor = [NSColor colorWithSRGBRed:20 / 255. - green:22 / 255. - blue:24 / 255. - alpha:1]; - } else { - overlayColor = - themeProvider->GetNSColor(ThemeProperties::COLOR_FRAME); - } - } else { - overlayColor = - themeProvider->GetNSColor(ThemeProperties::COLOR_FRAME_INACTIVE); - } - - if (overlayColor) { - [overlayColor set]; - NSRectFillUsingOperation(dirtyRect, NSCompositeSourceOver); - } - } + CGFloat lineWidth = [self cr_lineWidth]; + // Inset the vertical lines by 0.5px so that the top line gets a full pixel. + // Outset the horizontal lines by 0.5px so that they are not visible, but + // still get the rounded corners to get a border. + NSRect strokeRect = NSInsetRect(roundedRect, -lineWidth/2, lineWidth/2); + NSBezierPath* path = [NSBezierPath bezierPathWithRoundedRect:strokeRect + xRadius:cornerRadius + yRadius:cornerRadius]; + [path setLineWidth:lineWidth]; + [[NSColor colorWithCalibratedWhite:1.0 alpha:0.5] set]; + [path stroke]; } } -@end - -@implementation TabStripBackgroundView { - // Weak, owned by its superview. - TabStripThemeBackgroundView* themeBackgroundView_; - - // Weak, owned by its superview. - NSVisualEffectView* visualEffectView_; -} - -- (instancetype)initWithFrame:(NSRect)frame { - if ((self = [super initWithFrame:frame])) { - themeBackgroundView_ = [[[TabStripThemeBackgroundView alloc] - initWithFrame:self.bounds] autorelease]; - themeBackgroundView_.autoresizingMask = - NSViewWidthSizable | NSViewHeightSizable; - [self addSubview:themeBackgroundView_]; - } - return self; -} - -- (BOOL)inATabDraggingOverlayWindow { - return themeBackgroundView_.inATabDraggingOverlayWindow; -} - -- (void)setInATabDraggingOverlayWindow:(BOOL)inATabDraggingOverlayWindow { - themeBackgroundView_.inATabDraggingOverlayWindow = - inATabDraggingOverlayWindow; -} - -- (void)updateVisualEffectView { - const ui::ThemeProvider* themeProvider = [[self window] themeProvider]; - const bool isFullscreen = - (self.window.styleMask & NSFullScreenWindowMask) != 0; - - // Visual effects cause higher power consumption in full screen. - if (!isFullscreen && themeProvider->UsingSystemTheme()) { - if (!visualEffectView_) { - visualEffectView_ = - [[[NSVisualEffectView alloc] initWithFrame:self.bounds] autorelease]; - if (!visualEffectView_) - return; - - visualEffectView_.autoresizingMask = - NSViewWidthSizable | NSViewHeightSizable; - visualEffectView_.appearance = - [NSAppearance appearanceNamed:themeProvider->InIncognitoMode() - ? NSAppearanceNameVibrantDark - : NSAppearanceNameVibrantLight]; - [self addSubview:visualEffectView_]; - [visualEffectView_ addSubview:themeBackgroundView_]; - } - } else { - if (visualEffectView_) { - [self addSubview:themeBackgroundView_]; - [visualEffectView_ removeFromSuperview]; - visualEffectView_ = nil; - } - } -} - -- (void)viewWillMoveToWindow:(NSWindow*)newWindow { - // AppKit calls this method when the view's position in the view hierarchy - // changes, even if its parent window won't change. - if (newWindow == self.window) - return; - if (self.window) - [self.window removeObserver:self forKeyPath:@"styleMask"]; - if (newWindow) - [newWindow addObserver:self forKeyPath:@"styleMask" options:0 context:nil]; -} - -- (void)observeValueForKeyPath:(NSString*)keyPath - ofObject:(id)object - change:(NSDictionary*)change - context:(void*)context { - DCHECK_EQ(object, self.window); - DCHECK([keyPath isEqualToString:@"styleMask"]); - [self updateVisualEffectView]; -} // ThemedWindowDrawing implementation. - (void)windowDidChangeTheme { - [self updateVisualEffectView]; - [themeBackgroundView_ setNeedsDisplay:YES]; + [self setNeedsDisplay:YES]; } - (void)windowDidChangeActive { - // TODO(sdy): It shouldn't be necessary to update the visual effect view - // here, since it only changes when the theme changes), but the window isn't - // associated with a themeProvider at init time. - [self updateVisualEffectView]; - [themeBackgroundView_ setNeedsDisplay:YES]; + [self setNeedsDisplay:YES]; } @end
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_background_view_unittest.mm b/chrome/browser/ui/cocoa/tabs/tab_strip_background_view_unittest.mm deleted file mode 100644 index 6151556..0000000 --- a/chrome/browser/ui/cocoa/tabs/tab_strip_background_view_unittest.mm +++ /dev/null
@@ -1,92 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "chrome/browser/ui/cocoa/tabs/tab_strip_background_view.h" - -#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h" -#include "ui/base/default_theme_provider.h" - -@class NSVisualEffectView; - -namespace { - -bool ContainsViewOfClass(NSView* view, Class cls) { - if ([view isKindOfClass:cls]) - return true; - for (NSView* subview in view.subviews) { - if (ContainsViewOfClass(subview, cls)) - return true; - } - return false; -} - -class TabStripBackgroundViewTest : public CocoaTest { - protected: - const base::scoped_nsobject<TabStripBackgroundView> - tab_strip_background_view_{ - [[TabStripBackgroundView alloc] initWithFrame:NSZeroRect]}; -}; - -class MockThemeProvider : public ui::DefaultThemeProvider { - public: - bool UsingSystemTheme() const override { return using_system_theme_; } - - void SetUsingSystemTheme(bool using_system_theme) { - using_system_theme_ = using_system_theme; - } - - private: - bool using_system_theme_ = true; -}; - -} // namespace - -@interface TabStripBackgroundViewTestWindow : NSWindow -@property(nonatomic) const ui::ThemeProvider* themeProvider; -@end - -@implementation TabStripBackgroundViewTestWindow -@synthesize themeProvider = themeProvider_; -@end - -TEST_F(TabStripBackgroundViewTest, TestVisualEffectView) { - // TODO(sdy): Remove once we no longer support 10.9. - // Skip this test when running on an OS without NSVisualEffectView. - if (![NSVisualEffectView class]) - return; - - auto has_visual_effect_view = [&]() { - return ContainsViewOfClass(tab_strip_background_view_, - [NSVisualEffectView class]); - }; - - EXPECT_FALSE(has_visual_effect_view()); - - base::scoped_nsobject<TabStripBackgroundViewTestWindow> - scoped_window([[TabStripBackgroundViewTestWindow alloc] init]); - TabStripBackgroundViewTestWindow* window = scoped_window.get(); - - MockThemeProvider theme_provider; - window.themeProvider = &theme_provider; - - [window.contentView addSubview:tab_strip_background_view_]; - - [window makeKeyAndOrderFront:nil]; - [tab_strip_background_view_ windowDidChangeActive]; - EXPECT_TRUE(has_visual_effect_view()); - - window.styleMask |= NSFullScreenWindowMask; - EXPECT_FALSE(has_visual_effect_view()); - - window.styleMask &= ~NSFullScreenWindowMask; - EXPECT_TRUE(has_visual_effect_view()); - - theme_provider.SetUsingSystemTheme(false); - [tab_strip_background_view_ windowDidChangeTheme]; - EXPECT_FALSE(has_visual_effect_view()); - - theme_provider.SetUsingSystemTheme(true); - [tab_strip_background_view_ windowDidChangeTheme]; - EXPECT_TRUE(has_visual_effect_view()); -}
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_controller.h b/chrome/browser/ui/cocoa/tabs/tab_strip_controller.h index c533adcc..a9566eaa 100644 --- a/chrome/browser/ui/cocoa/tabs/tab_strip_controller.h +++ b/chrome/browser/ui/cocoa/tabs/tab_strip_controller.h
@@ -293,6 +293,10 @@ // Returns the alert state associated with the contents. - (TabAlertState)alertStateForContents:(content::WebContents*)contents; + +// Leaving visual effects enabled when fullscreen results in higher power +// consumption. This is used to disable effects when fullscreen. +- (void)setVisualEffectsDisabledForFullscreen:(BOOL)disabled; @end @interface TabStripController(TestingAPI)
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm b/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm index 5eff50bb3..116c0211 100644 --- a/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm +++ b/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm
@@ -2410,4 +2410,8 @@ } } +- (void)setVisualEffectsDisabledForFullscreen:(BOOL)fullscreen { + [tabStripView_ setVisualEffectsDisabledForFullscreen:fullscreen]; +} + @end
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_view.h b/chrome/browser/ui/cocoa/tabs/tab_strip_view.h index 2a570489..55ec16c 100644 --- a/chrome/browser/ui/cocoa/tabs/tab_strip_view.h +++ b/chrome/browser/ui/cocoa/tabs/tab_strip_view.h
@@ -19,6 +19,8 @@ @interface TabStripView : BackgroundGradientView<URLDropTarget> { @private + TabStripController* controller_; // Weak; owns us. + NSTimeInterval lastMouseUp_; // Handles being a drag-and-drop target. @@ -30,15 +32,26 @@ // its tip. BOOL dropArrowShown_; NSPoint dropArrowPosition_; + BOOL inATabDraggingOverlayWindow_; + BOOL visualEffectsDisabledForFullscreen_; } -@property(assign, nonatomic) TabStripController* controller; @property(assign, nonatomic) BOOL dropArrowShown; @property(assign, nonatomic) NSPoint dropArrowPosition; +@property(assign, nonatomic) BOOL inATabDraggingOverlayWindow; // Name starts with "get" because methods staring with "new" return retained // objects according to Cocoa's create rule. - (NewTabButton*)getNewTabButton; + +// Leaving visual effects enabled when fullscreen results in higher power +// consumption. This is used to disable effects when fullscreen. +- (void)setVisualEffectsDisabledForFullscreen:(BOOL)fullscreen; +@end + +// Interface for the controller to set and clear the weak reference to itself. +@interface TabStripView (TabStripControllerInterface) +- (void)setController:(TabStripController*)controller; @end // Protected methods subclasses can override to alter behavior. Clients should
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_view.mm b/chrome/browser/ui/cocoa/tabs/tab_strip_view.mm index 2f430eac7..a59f0204 100644 --- a/chrome/browser/ui/cocoa/tabs/tab_strip_view.mm +++ b/chrome/browser/ui/cocoa/tabs/tab_strip_view.mm
@@ -12,6 +12,8 @@ #include "base/mac/sdk_forward_declarations.h" #include "chrome/browser/themes/theme_properties.h" #include "chrome/browser/themes/theme_service.h" +#import "chrome/browser/ui/cocoa/browser_window_controller.h" +#import "chrome/browser/ui/cocoa/browser_window_layout.h" #import "chrome/browser/ui/cocoa/new_tab_button.h" #import "chrome/browser/ui/cocoa/tabs/tab_strip_controller.h" #import "chrome/browser/ui/cocoa/tabs/tab_view.h" @@ -27,9 +29,9 @@ @implementation TabStripView -@synthesize controller = controller_; @synthesize dropArrowShown = dropArrowShown_; @synthesize dropArrowPosition = dropArrowPosition_; +@synthesize inATabDraggingOverlayWindow = inATabDraggingOverlayWindow_; - (id)initWithFrame:(NSRect)frame { self = [super initWithFrame:frame]; @@ -96,6 +98,43 @@ } - (void)drawRect:(NSRect)dirtyRect { + const ui::ThemeProvider* themeProvider = [[self window] themeProvider]; + bool hasCustomThemeImage = themeProvider && + themeProvider->HasCustomImage(IDR_THEME_FRAME); + BOOL supportsVibrancy = [self visualEffectView] != nil; + BOOL isMainWindow = [[self window] isMainWindow]; + + // If in Material Design mode, decrease the tabstrip background's translucency + // by overlaying it with a partially-transparent gray (but only if not themed, + // and not being used to drag tabs between browser windows). The gray is + // somewhat opaque for Incognito mode, very opaque for non-Incognito mode, and + // completely opaque when the window is not active. + if (themeProvider && !hasCustomThemeImage && !inATabDraggingOverlayWindow_) { + NSColor* theColor = nil; + if (isMainWindow) { + if (supportsVibrancy && + !themeProvider->HasCustomColor(ThemeProperties::COLOR_FRAME)) { + theColor = themeProvider->GetNSColor( + ThemeProperties::COLOR_FRAME_VIBRANCY_OVERLAY); + } else if (!supportsVibrancy && themeProvider->InIncognitoMode()) { + theColor = [NSColor colorWithSRGBRed:20 / 255. + green:22 / 255. + blue:24 / 255. + alpha:1]; + } else { + theColor = themeProvider->GetNSColor(ThemeProperties::COLOR_FRAME); + } + } else { + theColor = themeProvider->GetNSColor( + ThemeProperties::COLOR_FRAME_INACTIVE); + } + + if (theColor) { + [theColor set]; + NSRectFillUsingOperation(dirtyRect, NSCompositeSourceOver); + } + } + [self drawBottomEdge:dirtyRect]; // Draw drop-indicator arrow (if appropriate). @@ -308,14 +347,85 @@ newTabButton_.reset([button retain]); } +- (NSVisualEffectView*)visualEffectView { + // NSVisualEffectView is only available on OS X 10.10 and higher. + if (!base::mac::IsAtLeastOS10_10()) + return nil; + + NSView* rootView = [[self window] contentView]; + if (!chrome::ShouldUseFullSizeContentView()) { + rootView = [rootView superview]; + } + + Class nsVisualEffectViewClass = NSClassFromString(@"NSVisualEffectView"); + DCHECK(nsVisualEffectViewClass); + for (NSView* view in [rootView subviews]) { + if ([view isKindOfClass:nsVisualEffectViewClass]) { + return base::mac::ObjCCast<NSVisualEffectView>(view); + } + } + return nil; +} + +- (void)setController:(TabStripController*)controller { + controller_ = controller; + // If tearing down the browser window, there's nothing more to do. + if (!controller_) { + return; + } + + // Finish configuring the NSVisualEffectView so that it matches the window's + // theme. + NSVisualEffectView* visualEffectView = [self visualEffectView]; + const ui::ThemeProvider* themeProvider = [[self window] themeProvider]; + if (!visualEffectView || !themeProvider) { + return; + } + + // Themes with custom frame images don't use vibrancy. Otherwise, if Incognito + // use Material Dark. + if (themeProvider->HasCustomImage(IDR_THEME_FRAME) || + themeProvider->HasCustomColor(ThemeProperties::COLOR_FRAME)) { + [visualEffectView setState:NSVisualEffectStateInactive]; + } else if (themeProvider->InIncognitoMode()) { + [visualEffectView setMaterial:NSVisualEffectMaterialDark]; + [visualEffectView setAppearance: + [NSAppearance appearanceNamed:NSAppearanceNameVibrantDark]]; + } +} + // ThemedWindowDrawing implementation. - (void)windowDidChangeTheme { [self setNeedsDisplay:YES]; + [self updateVisualEffectState]; } - (void)windowDidChangeActive { [self setNeedsDisplay:YES]; } +- (void)setVisualEffectsDisabledForFullscreen:(BOOL)disabled { + visualEffectsDisabledForFullscreen_ = disabled; + [self updateVisualEffectState]; +} + +- (void)updateVisualEffectState { + // Configure the NSVisualEffectView so that it does nothing if the user has + // switched to a custom theme, or uses vibrancy if the user has switched back + // to the default theme. + NSVisualEffectView* visualEffectView = [self visualEffectView]; + const ui::ThemeProvider* themeProvider = [[self window] themeProvider]; + if (!visualEffectView || !themeProvider) { + return; + } + if (visualEffectsDisabledForFullscreen_ || + themeProvider->HasCustomImage(IDR_THEME_FRAME) || + themeProvider->HasCustomColor(ThemeProperties::COLOR_FRAME)) { + [visualEffectView setState:NSVisualEffectStateInactive]; + } else { + [visualEffectView setState:NSVisualEffectStateFollowsWindowActiveState]; + } +} + @end
diff --git a/chrome/browser/ui/cocoa/tabs/tab_window_controller.h b/chrome/browser/ui/cocoa/tabs/tab_window_controller.h index 7267464..e9904d9 100644 --- a/chrome/browser/ui/cocoa/tabs/tab_window_controller.h +++ b/chrome/browser/ui/cocoa/tabs/tab_window_controller.h
@@ -18,7 +18,7 @@ @class FastResizeView; @class FocusTracker; -@class TabStripBackgroundView; +@class NSVisualEffectView; @class TabStripView; @class TabView; @@ -26,7 +26,10 @@ @private // Wrapper view around web content, and the developer tools view. base::scoped_nsobject<FastResizeView> tabContentArea_; - base::scoped_nsobject<TabStripBackgroundView> tabStripBackgroundView_; + base::scoped_nsobject<NSView> tabStripBackgroundView_; + + // Used to blur the titlebar. nil if window does not have titlebar. + base::scoped_nsobject<NSVisualEffectView> visualEffectView_; // The tab strip overlaps the titlebar of the window. base::scoped_nsobject<TabStripView> tabStripView_;
diff --git a/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm b/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm index f53ea1d..73d0f3e 100644 --- a/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm +++ b/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm
@@ -16,11 +16,25 @@ #include "ui/base/material_design/material_design_controller.h" #include "ui/base/theme_provider.h" -// TODO(sdy): Remove once we no longer support 10.9 (-Wunguarded-availability). -@interface NSWindow (TitlebarAppearsTransparent) -@property BOOL titlebarAppearsTransparent; +@interface TabWindowController () +- (void)setUseOverlay:(BOOL)useOverlay; + +// The tab strip background view should always be inserted as the back-most +// subview of the root view. It cannot be a subview of the contentView, as that +// would cause it to become layer backed, which would cause it to draw on top +// of non-layer backed content like the window controls. +- (void)insertTabStripBackgroundViewIntoWindow:(NSWindow*)window + titleBar:(BOOL)hasTitleBar; + +// Called when NSWindowWillEnterFullScreenNotification notification received. +// Makes visual effects view hidden as it should not be displayed in fullscreen. +- (void)windowWillEnterFullScreenNotification:(NSNotification*)notification; + +// Called when NSWindowWillExitFullScreenNotification notification received. +// Makes visual effects view visible since it was hidden in fullscreen. +- (void)windowWillExitFullScreenNotification:(NSNotification*)notification; + @end -// /TODO @interface TabWindowOverlayWindow : NSWindow @end @@ -71,9 +85,7 @@ [chromeContentView_ setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; [chromeContentView_ setWantsLayer:YES]; - - NSView* contentView = self.window.contentView; - [contentView addSubview:chromeContentView_]; + [[[self window] contentView] addSubview:chromeContentView_]; tabContentArea_.reset( [[FastResizeView alloc] initWithFrame:[chromeContentView_ bounds]]); @@ -85,12 +97,14 @@ // When making a tab dragging window (setUseOverlay:), this view stays in // the parent window so that it can be translucent, while the tab strip view // moves to the child window and stays opaque. + NSView* windowView = [window contentView]; CGFloat paintHeight = [FramedBrowserWindow browserFrameViewPaintHeight]; tabStripBackgroundView_.reset([[TabStripBackgroundView alloc] - initWithFrame:NSMakeRect(0, NSMaxY([contentView bounds]) - paintHeight, - NSWidth([contentView bounds]), paintHeight)]); + initWithFrame:NSMakeRect(0, NSMaxY([windowView bounds]) - paintHeight, + NSWidth([windowView bounds]), paintHeight)]); [tabStripBackgroundView_ setAutoresizingMask:NSViewWidthSizable | NSViewMinYMargin]; + [self insertTabStripBackgroundViewIntoWindow:window titleBar:hasTitleBar]; tabStripView_.reset([[TabStripView alloc] initWithFrame:NSMakeRect( @@ -98,18 +112,25 @@ [tabStripView_ setAutoresizingMask:NSViewWidthSizable | NSViewMinYMargin]; if (hasTabStrip) - [contentView addSubview:tabStripView_]; - - if ([window respondsToSelector:@selector(setTitlebarAppearsTransparent:)]) - [window setTitlebarAppearsTransparent:YES]; + [windowView addSubview:tabStripView_]; if (chrome::ShouldUseFullSizeContentView()) { - [contentView addSubview:tabStripBackgroundView_]; - } else { - NSView* rootView = contentView.superview; - [rootView addSubview:tabStripBackgroundView_ - positioned:NSWindowBelow - relativeTo:nil]; + // |windowWillEnterFullScreen:| and |windowWillExitFullScreen:| are + // already called because self is a delegate for the window. However this + // class is designed for subclassing and can not implement + // NSWindowDelegate methods (because subclasses can do so as well and they + // should be able to). TODO(crbug.com/654656): Move |visualEffectView_| to + // subclass. + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(windowWillEnterFullScreenNotification:) + name:NSWindowWillEnterFullScreenNotification + object:window]; + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(windowWillExitFullScreenNotification:) + name:NSWindowWillExitFullScreenNotification + object:window]; } } return self; @@ -189,7 +210,7 @@ // content view (rather than using setContentView:) because the overlay // window has a different content size (due to it being borderless). [[overlayWindow_ contentView] addSubview:[self tabStripView]]; - [tabStripBackgroundView_ setInATabDraggingOverlayWindow:YES]; + [[self tabStripView] setInATabDraggingOverlayWindow:YES]; [[overlayWindow_ contentView] addSubview:originalContentView_]; [overlayWindow_ orderFront:nil]; @@ -208,7 +229,7 @@ [[window contentView] addSubview:[self tabStripView] positioned:NSWindowBelow relativeTo:[self avatarView]]; - [tabStripBackgroundView_ setInATabDraggingOverlayWindow:NO]; + [[self tabStripView] setInATabDraggingOverlayWindow:NO]; [[window contentView] updateTrackingAreas]; [focusBeforeOverlay_ restoreFocusInWindow:window]; @@ -361,10 +382,75 @@ closeDeferred_ = YES; } +- (void)insertTabStripBackgroundViewIntoWindow:(NSWindow*)window + titleBar:(BOOL)hasTitleBar { + DCHECK(tabStripBackgroundView_); + NSView* rootView = [[window contentView] superview]; + + // In Material Design on 10.10 and higher, the top portion of the window is + // blurred using an NSVisualEffectView. + Class nsVisualEffectViewClass = NSClassFromString(@"NSVisualEffectView"); + if (!nsVisualEffectViewClass) { + DCHECK(!chrome::ShouldUseFullSizeContentView()); + [rootView addSubview:tabStripBackgroundView_ + positioned:NSWindowBelow + relativeTo:nil]; + return; + } + + [window setTitlebarAppearsTransparent:YES]; + + // If the window has a normal titlebar, then do not add NSVisualEffectView. + if (hasTitleBar) + return; + + visualEffectView_.reset( + [[nsVisualEffectViewClass alloc] + initWithFrame:[tabStripBackgroundView_ frame]]); + DCHECK(visualEffectView_); + + [visualEffectView_ setAutoresizingMask: + [tabStripBackgroundView_ autoresizingMask]]; + [tabStripBackgroundView_ + setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; + + // Set to a default appearance and material. If this is an Incognito window + // the material and vibrancy should be dark but this method gets called at + // the start of -[BrowserWindowController initWithBrowser:takeOwnership:], + // before the |browser_| ivar has been set. Without a browser object we + // can't check the window's theme. The final setup happens in + // -[TabStripView setController:], at which point we have access to the theme. + [visualEffectView_ setAppearance: + [NSAppearance appearanceNamed:NSAppearanceNameVibrantLight]]; + [visualEffectView_ setMaterial:NSVisualEffectMaterialLight]; + [visualEffectView_ setBlendingMode:NSVisualEffectBlendingModeBehindWindow]; + [visualEffectView_ setState:NSVisualEffectStateFollowsWindowActiveState]; + + if (chrome::ShouldUseFullSizeContentView()) { + [[window contentView] addSubview:visualEffectView_]; + } else { + [rootView addSubview:visualEffectView_ + positioned:NSWindowBelow + relativeTo:nil]; + } + + // Make the |tabStripBackgroundView_| a child of the NSVisualEffectView. + [tabStripBackgroundView_ setFrame:[visualEffectView_ bounds]]; + [visualEffectView_ addSubview:tabStripBackgroundView_]; +} + // Called when the size of the window content area has changed. Override to // position specific views. Base class implementation does nothing. - (void)layoutSubviews { NOTIMPLEMENTED(); } +- (void)windowWillEnterFullScreenNotification:(NSNotification*)notification { + [[visualEffectView_ animator] setAlphaValue:0.0]; +} + +- (void)windowWillExitFullScreenNotification:(NSNotification*)notification { + [[visualEffectView_ animator] setAlphaValue:1.0]; +} + @end
diff --git a/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc b/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc index 7fd6656..fb2ed5a2 100644 --- a/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc
@@ -237,6 +237,11 @@ } } +void CoreOobeHandler::ShowActiveDirectoryPasswordChangeScreen( + const std::string& username) { + CallJSOrDefer("showActiveDirectoryPasswordChangeScreen", username); +} + void CoreOobeHandler::ShowSignInUI(const std::string& email) { CallJSOrDefer("showSigninUI", email); }
diff --git a/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.h b/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.h index 30136ad..659f1cc9 100644 --- a/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.h
@@ -119,6 +119,8 @@ void SetClientAreaSize(int width, int height) override; void ShowDeviceResetScreen() override; void ShowEnableDebuggingScreen() override; + void ShowActiveDirectoryPasswordChangeScreen( + const std::string& username) override; void InitDemoModeDetection() override; void StopDemoModeDetection() override;
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc index 03933fc..efacc14 100644 --- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -416,6 +416,8 @@ &GaiaScreenHandler::HandleAuthExtensionLoaded); AddCallback("completeAdAuthentication", &GaiaScreenHandler::HandleCompleteAdAuthentication); + AddCallback("completeAdPasswordChange", + &GaiaScreenHandler::HandleCompleteAdPasswordChange); } void GaiaScreenHandler::OnPortalDetectionCompleted( @@ -503,36 +505,74 @@ const Key& key, authpolicy::ErrorType error, const std::string& uid) { - if (error == authpolicy::ERROR_NONE && !uid.empty()) { - const AccountId account_id( - GetAccountId(username, uid, AccountType::ACTIVE_DIRECTORY)); - UserContext user_context(account_id); - user_context.SetKey(key); - user_context.SetAuthFlow(UserContext::AUTH_FLOW_ACTIVE_DIRECTORY); - user_context.SetIsUsingOAuth(false); - user_context.SetUserType( - user_manager::UserType::USER_TYPE_ACTIVE_DIRECTORY); - Delegate()->CompleteLogin(user_context); - } else { - // TODO(rsorokin): Proper error handling. - DLOG(ERROR) << "Failed to auth " << username << ", code " << error; - LoadAuthExtension(true, false /* offline */); + switch (error) { + case authpolicy::ERROR_NONE: { + DCHECK(!uid.empty()); + const AccountId account_id( + GetAccountId(username, uid, AccountType::ACTIVE_DIRECTORY)); + UserContext user_context(account_id); + user_context.SetKey(key); + user_context.SetAuthFlow(UserContext::AUTH_FLOW_ACTIVE_DIRECTORY); + user_context.SetIsUsingOAuth(false); + user_context.SetUserType( + user_manager::UserType::USER_TYPE_ACTIVE_DIRECTORY); + Delegate()->CompleteLogin(user_context); + break; + } + case authpolicy::ERROR_PASSWORD_EXPIRED: + core_oobe_actor_->ShowActiveDirectoryPasswordChangeScreen(username); + break; + case authpolicy::ERROR_UNKNOWN: + case authpolicy::ERROR_DBUS_FAILURE: + case authpolicy::ERROR_PARSE_UPN_FAILED: + case authpolicy::ERROR_BAD_USER_NAME: + case authpolicy::ERROR_BAD_PASSWORD: + case authpolicy::ERROR_CANNOT_RESOLVE_KDC: + case authpolicy::ERROR_KINIT_FAILED: + case authpolicy::ERROR_NET_FAILED: + case authpolicy::ERROR_SMBCLIENT_FAILED: + case authpolicy::ERROR_PARSE_FAILED: + case authpolicy::ERROR_PARSE_PREG_FAILED: + case authpolicy::ERROR_BAD_GPOS: + case authpolicy::ERROR_LOCAL_IO: + case authpolicy::ERROR_NOT_JOINED: + case authpolicy::ERROR_NOT_LOGGED_IN: + case authpolicy::ERROR_STORE_POLICY_FAILED: + LoadAuthExtension(true, false /* offline */); + break; + default: + // TODO(rsorokin): Proper error handling. + DLOG(WARNING) << "Unhandled error code: " << error; + LoadAuthExtension(true, false /* offline */); } } void GaiaScreenHandler::HandleCompleteAdAuthentication( - const std::string& user_name, + const std::string& username, const std::string& password) { - Delegate()->SetDisplayEmail(user_name); - set_populated_email(user_name); + Delegate()->SetDisplayEmail(username); + set_populated_email(username); login::GetPipeReadEnd( password, base::Bind(&GaiaScreenHandler::OnPasswordPipeReady, - weak_factory_.GetWeakPtr(), user_name, Key(password))); + weak_factory_.GetWeakPtr(), username, Key(password))); } -void GaiaScreenHandler::OnPasswordPipeReady(const std::string& user_name, +void GaiaScreenHandler::HandleCompleteAdPasswordChange( + const std::string& username, + const std::string& old_password, + const std::string& new_password) { + Delegate()->SetDisplayEmail(username); + set_populated_email(username); + + login::GetPipeReadEnd( + old_password + "\n" + new_password + "\n" + new_password, + base::Bind(&GaiaScreenHandler::OnPasswordPipeReady, + weak_factory_.GetWeakPtr(), username, Key(new_password))); +} + +void GaiaScreenHandler::OnPasswordPipeReady(const std::string& username, const Key& key, base::ScopedFD password_fd) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); @@ -543,9 +583,9 @@ chromeos::AuthPolicyClient* client = chromeos::DBusThreadManager::Get()->GetAuthPolicyClient(); client->AuthenticateUser( - user_name, password_fd.get(), + username, password_fd.get(), base::Bind(&GaiaScreenHandler::DoAdAuth, weak_factory_.GetWeakPtr(), - user_name, key)); + username, key)); } void GaiaScreenHandler::HandleCompleteAuthentication(
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h index a3b8da0..a81b462 100644 --- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h
@@ -98,9 +98,13 @@ const std::string& password, bool using_saml); - void HandleCompleteAdAuthentication(const std::string& user_name, + void HandleCompleteAdAuthentication(const std::string& username, const std::string& password); + void HandleCompleteAdPasswordChange(const std::string& username, + const std::string& old_password, + const std::string& new_password); + void HandleUsingSAMLAPI(); void HandleScrapedPasswordCount(int password_count); void HandleScrapedPasswordVerificationFailed(); @@ -139,7 +143,7 @@ const std::string& uid); // Callback for writing password into pipe. - void OnPasswordPipeReady(const std::string& user_name, + void OnPasswordPipeReady(const std::string& username, const Key& key, base::ScopedFD password_fd);
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc index 50d3396..3b893b2 100644 --- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
@@ -518,6 +518,14 @@ IDS_LOGIN_UNRECOVERABLE_CRYPTOHOME_ERROR_CONTINUE); builder->Add("unrecoverableCryptohomeErrorRecreatingProfile", IDS_LOGIN_UNRECOVERABLE_CRYPTOHOME_ERROR_WAIT_MESSAGE); + + builder->Add("adEnterOldPasswordHint", IDS_AD_PASSWORD_CHANGE_OLD_PASSWORD); + builder->Add("adEnterNewPasswordHint", IDS_AD_PASSWORD_CHANGE_NEW_PASSWORD); + builder->Add("adRepeatNewPasswordHint", + IDS_AD_PASSWORD_CHANGE_REPEAT_NEW_PASSWORD); + builder->Add("adPasswordChangeMessage", IDS_AD_PASSWORD_CHANGE_MESSAGE); + builder->Add("adOldPasswordError", IDS_AD_PASSWORD_CHANGE_INVALID_PASSWORD); + builder->Add("adNewPasswordError", IDS_AD_PASSWORD_CHANGE_PASSWORDS_MISMATCH); } void SigninScreenHandler::RegisterMessages() {
diff --git a/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc b/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc index 5564716..e12782d 100644 --- a/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc +++ b/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc
@@ -42,6 +42,7 @@ void RegisterMessages() override; // ntp_tiles::NTPTilesInternalsMessageHandlerClient + bool SupportsNTPTiles() override; bool DoesSourceExist(ntp_tiles::NTPTileSource source) override; std::unique_ptr<ntp_tiles::MostVisitedSites> MakeMostVisitedSites() override; std::unique_ptr<ntp_tiles::PopularSites> MakePopularSites() override; @@ -62,6 +63,11 @@ handler_.RegisterMessages(this); } +bool ChromeNTPTilesInternalsMessageHandlerClient::SupportsNTPTiles() { + Profile* profile = Profile::FromWebUI(web_ui()); + return !(profile->IsGuestSession() || profile->IsOffTheRecord()); +} + bool ChromeNTPTilesInternalsMessageHandlerClient::DoesSourceExist( ntp_tiles::NTPTileSource source) { switch (source) {
diff --git a/chrome/renderer/chrome_render_thread_observer.cc b/chrome/renderer/chrome_render_thread_observer.cc index bd3836f..32ed66b 100644 --- a/chrome/renderer/chrome_render_thread_observer.cc +++ b/chrome/renderer/chrome_render_thread_observer.cc
@@ -279,9 +279,9 @@ void ChromeRenderThreadObserver::RegisterMojoInterfaces( content::AssociatedInterfaceRegistry* associated_interfaces) { - associated_interfaces->AddInterface( - base::Bind(&ChromeRenderThreadObserver::OnRendererInterfaceRequest, - base::Unretained(this))); + associated_interfaces->AddInterface(base::Bind( + &ChromeRenderThreadObserver::OnRendererConfigurationAssociatedRequest, + base::Unretained(this))); } void ChromeRenderThreadObserver::UnregisterMojoInterfaces( @@ -331,7 +331,7 @@ content_setting_rules_ = rules; } -void ChromeRenderThreadObserver::OnRendererInterfaceRequest( +void ChromeRenderThreadObserver::OnRendererConfigurationAssociatedRequest( chrome::mojom::RendererConfigurationAssociatedRequest request) { DCHECK(!renderer_configuration_binding_.is_bound()); renderer_configuration_binding_.Bind(std::move(request));
diff --git a/chrome/renderer/chrome_render_thread_observer.h b/chrome/renderer/chrome_render_thread_observer.h index d8ed9a1..91540065 100644 --- a/chrome/renderer/chrome_render_thread_observer.h +++ b/chrome/renderer/chrome_render_thread_observer.h
@@ -65,7 +65,7 @@ void SetContentSettingRules( const RendererContentSettingRules& rules) override; - void OnRendererInterfaceRequest( + void OnRendererConfigurationAssociatedRequest( chrome::mojom::RendererConfigurationAssociatedRequest request); void OnSetFieldTrialGroup(const std::string& trial_name,
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index cfaf9d82..e0cfab3 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -4620,7 +4620,6 @@ "../browser/ui/cocoa/tab_contents/sad_tab_mac_unittest.mm", "../browser/ui/cocoa/tabs/alert_indicator_button_cocoa_unittest.mm", "../browser/ui/cocoa/tabs/tab_controller_unittest.mm", - "../browser/ui/cocoa/tabs/tab_strip_background_view_unittest.mm", "../browser/ui/cocoa/tabs/tab_strip_controller_unittest.mm", "../browser/ui/cocoa/tabs/tab_strip_view_unittest.mm", "../browser/ui/cocoa/tabs/tab_view_unittest.mm",
diff --git a/components/cronet/android/cronet_impl_native_proguard.cfg b/components/cronet/android/cronet_impl_native_proguard.cfg index c0493225..383cc049 100644 --- a/components/cronet/android/cronet_impl_native_proguard.cfg +++ b/components/cronet/android/cronet_impl_native_proguard.cfg
@@ -1,7 +1,6 @@ # Proguard config for apps that depend on cronet_impl_native_java.jar. -keep class org.chromium.net.impl.CronetUrlRequest$HeadersList --keep class org.chromium.net.impl.ChromiumUrlRequest$ResponseHeadersMap # Suppress unnecessary warnings. -dontnote org.chromium.net.ProxyChangeListener$ProxyReceiver
diff --git a/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc b/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc index 4dce944..9f876ee 100644 --- a/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc +++ b/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc
@@ -44,6 +44,9 @@ void NTPTilesInternalsMessageHandler::HandleRegisterForEvents( const base::ListValue* args) { + if (!client_->SupportsNTPTiles()) { + return; + } DCHECK(args->empty()); SendSourceInfo(); @@ -54,6 +57,9 @@ void NTPTilesInternalsMessageHandler::HandleUpdate( const base::ListValue* args) { + if (!client_->SupportsNTPTiles()) { + return; + } const base::DictionaryValue* dict = nullptr; DCHECK_EQ(1u, args->GetSize()); args->GetDictionary(0, &dict);
diff --git a/components/ntp_tiles/webui/ntp_tiles_internals_message_handler_client.h b/components/ntp_tiles/webui/ntp_tiles_internals_message_handler_client.h index 4a917008..d26972d 100644 --- a/components/ntp_tiles/webui/ntp_tiles_internals_message_handler_client.h +++ b/components/ntp_tiles/webui/ntp_tiles_internals_message_handler_client.h
@@ -31,6 +31,9 @@ // Returns the PrefService for the embedder and containing WebUI page. virtual PrefService* GetPrefs() = 0; + // False if in a browser mode (e.g. incognito) where tiles aren't supported. + virtual bool SupportsNTPTiles() = 0; + // Returns true if the given source is enabled (even if, in practice, none of // the tiles would come from it). virtual bool DoesSourceExist(NTPTileSource source) = 0;
diff --git a/components/password_manager/core/browser/BUILD.gn b/components/password_manager/core/browser/BUILD.gn index 503a718..c76864f 100644 --- a/components/password_manager/core/browser/BUILD.gn +++ b/components/password_manager/core/browser/BUILD.gn
@@ -52,6 +52,8 @@ "form_saver.h", "form_saver_impl.cc", "form_saver_impl.h", + "http_password_migrator.cc", + "http_password_migrator.h", "import/csv_reader.cc", "import/csv_reader.h", "import/password_csv_reader.cc", @@ -271,6 +273,7 @@ "facet_manager_unittest.cc", "form_fetcher_impl_unittest.cc", "form_saver_impl_unittest.cc", + "http_password_migrator_unittest.cc", "import/csv_reader_unittest.cc", "import/password_csv_reader_unittest.cc", "import/password_importer_unittest.cc",
diff --git a/components/password_manager/core/browser/http_password_migrator.cc b/components/password_manager/core/browser/http_password_migrator.cc new file mode 100644 index 0000000..9f331071 --- /dev/null +++ b/components/password_manager/core/browser/http_password_migrator.cc
@@ -0,0 +1,60 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/password_manager/core/browser/http_password_migrator.h" + +#include "components/password_manager/core/browser/password_store.h" +#include "url/gurl.h" +#include "url/url_constants.h" + +namespace password_manager { + +HttpPasswordMigrator::HttpPasswordMigrator(const GURL& https_origin, + PasswordStore* password_store, + Consumer* consumer) + : consumer_(consumer), password_store_(password_store) { + DCHECK(password_store_); + DCHECK(https_origin.is_valid()); + DCHECK(https_origin.SchemeIs(url::kHttpsScheme)) << https_origin; + + GURL::Replacements rep; + rep.SetSchemeStr(url::kHttpScheme); + GURL http_origin = https_origin.ReplaceComponents(rep); + PasswordStore::FormDigest form(autofill::PasswordForm::SCHEME_HTML, + http_origin.GetOrigin().spec(), http_origin); + password_store_->GetLogins(form, this); +} + +HttpPasswordMigrator::~HttpPasswordMigrator() = default; + +void HttpPasswordMigrator::OnGetPasswordStoreResults( + std::vector<std::unique_ptr<autofill::PasswordForm>> results) { + // Android and PSL matches are ignored. + results.erase( + std::remove_if(results.begin(), results.end(), + [](const std::unique_ptr<autofill::PasswordForm>& form) { + return form->is_affiliation_based_match || + form->is_public_suffix_match; + }), + results.end()); + + // Add the new credentials to the password store. The HTTP forms aren't + // removed for now. + for (const auto& form : results) { + GURL::Replacements rep; + rep.SetSchemeStr(url::kHttpsScheme); + form->origin = form->origin.ReplaceComponents(rep); + form->signon_realm = form->origin.spec(); + form->action = form->origin; + form->form_data = autofill::FormData(); + form->generation_upload_status = autofill::PasswordForm::NO_SIGNAL_SENT; + form->skip_zero_click = false; + password_store_->AddLogin(*form); + } + + if (consumer_) + consumer_->ProcessMigratedForms(std::move(results)); +} + +} // namespace password_manager
diff --git a/components/password_manager/core/browser/http_password_migrator.h b/components/password_manager/core/browser/http_password_migrator.h new file mode 100644 index 0000000..cf054487 --- /dev/null +++ b/components/password_manager/core/browser/http_password_migrator.h
@@ -0,0 +1,58 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_HTTP_PASSWORD_MIGRATOR_H_ +#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_HTTP_PASSWORD_MIGRATOR_H_ + +#include <memory> +#include <vector> + +#include "base/macros.h" +#include "components/password_manager/core/browser/password_store_consumer.h" + +namespace autofill { +struct PasswordForm; +} + +class GURL; + +namespace password_manager { + +class PasswordStore; + +// The class is responsible for migrating the passwords saved on HTTP to HTTPS +// origin. +class HttpPasswordMigrator : public PasswordStoreConsumer { + public: + // API to be implemented by an embedder of HttpPasswordMigrator. + class Consumer { + public: + virtual ~Consumer() = default; + + // Notify the embedder that |forms| were migrated to HTTPS. |forms| contain + // the updated HTTPS scheme. + virtual void ProcessMigratedForms( + std::vector<std::unique_ptr<autofill::PasswordForm>> forms) = 0; + }; + + // |https_origin| should specify a valid HTTPS URL. + HttpPasswordMigrator(const GURL& https_origin, + PasswordStore* password_store, + Consumer* consumer); + ~HttpPasswordMigrator() override; + + // PasswordStoreConsumer: + void OnGetPasswordStoreResults( + std::vector<std::unique_ptr<autofill::PasswordForm>> results) override; + + private: + Consumer* consumer_; + PasswordStore* password_store_; + + DISALLOW_COPY_AND_ASSIGN(HttpPasswordMigrator); +}; + +} // namespace password_manager + +#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_HTTP_PASSWORD_MIGRATOR_H_
diff --git a/components/password_manager/core/browser/http_password_migrator_unittest.cc b/components/password_manager/core/browser/http_password_migrator_unittest.cc new file mode 100644 index 0000000..ab7bb55 --- /dev/null +++ b/components/password_manager/core/browser/http_password_migrator_unittest.cc
@@ -0,0 +1,131 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/password_manager/core/browser/http_password_migrator.h" + +#include "base/memory/ptr_util.h" +#include "base/message_loop/message_loop.h" +#include "base/strings/utf_string_conversions.h" +#include "components/password_manager/core/browser/mock_password_store.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace password_manager { +namespace { + +using autofill::PasswordForm; +using testing::_; +using testing::ElementsAre; +using testing::Pointee; + +constexpr char kTestHttpsURL[] = "https://example.org/"; +constexpr char kTestHttpURL[] = "http://example.org/"; +constexpr char kTestSubdomainHttpURL[] = "http://login.example.org/"; + +// Creates a dummy http form with some basic arbitrary values. +PasswordForm CreateTestForm() { + PasswordForm form; + form.origin = GURL(kTestHttpURL); + form.signon_realm = form.origin.spec(); + form.action = GURL(kTestHttpURL); + form.username_value = base::ASCIIToUTF16("user"); + form.password_value = base::ASCIIToUTF16("password"); + return form; +} + +// Creates a dummy http PSL-matching form with some basic arbitrary values. +PasswordForm CreateTestPSLForm() { + PasswordForm form; + form.origin = GURL(kTestSubdomainHttpURL); + form.signon_realm = form.origin.spec(); + form.action = GURL(kTestSubdomainHttpURL); + form.username_value = base::ASCIIToUTF16("user2"); + form.password_value = base::ASCIIToUTF16("password2"); + form.is_public_suffix_match = true; + return form; +} + +// Creates an Android credential. +PasswordForm CreateAndroidCredential() { + PasswordForm form; + form.username_value = base::ASCIIToUTF16("user3"); + form.password_value = base::ASCIIToUTF16("password3"); + form.signon_realm = "android://hash@com.example.android/"; + form.origin = GURL(form.signon_realm); + form.action = GURL(); + form.is_affiliation_based_match = true; + return form; +} + +class MockConsumer : public HttpPasswordMigrator::Consumer { + public: + MOCK_METHOD1(ProcessForms, + void(const std::vector<autofill::PasswordForm*>& forms)); + + void ProcessMigratedForms( + std::vector<std::unique_ptr<autofill::PasswordForm>> forms) override { + std::vector<autofill::PasswordForm*> raw_forms(forms.size()); + std::transform(forms.begin(), forms.end(), raw_forms.begin(), + [](const std::unique_ptr<autofill::PasswordForm>& form) { + return form.get(); + }); + ProcessForms(raw_forms); + } +}; + +class HttpPasswordMigratorTest : public testing::Test { + public: + HttpPasswordMigratorTest() { + mock_store_ = new testing::StrictMock<MockPasswordStore>; + } + + ~HttpPasswordMigratorTest() override { mock_store_->ShutdownOnUIThread(); } + + MockConsumer& consumer() { return consumer_; } + MockPasswordStore& store() { return *mock_store_; } + + private: + base::MessageLoop message_loop_; // Used by mock_store_. + MockConsumer consumer_; + scoped_refptr<MockPasswordStore> mock_store_; + + DISALLOW_COPY_AND_ASSIGN(HttpPasswordMigratorTest); +}; + +TEST_F(HttpPasswordMigratorTest, EmptyStore) { + PasswordStore::FormDigest form(autofill::PasswordForm::SCHEME_HTML, + kTestHttpURL, GURL(kTestHttpURL)); + EXPECT_CALL(store(), GetLogins(form, _)); + HttpPasswordMigrator migrator(GURL(kTestHttpsURL), &store(), &consumer()); + + EXPECT_CALL(consumer(), ProcessForms(std::vector<autofill::PasswordForm*>())); + migrator.OnGetPasswordStoreResults( + std::vector<std::unique_ptr<autofill::PasswordForm>>()); +} + +TEST_F(HttpPasswordMigratorTest, FullStore) { + PasswordStore::FormDigest form_digest(autofill::PasswordForm::SCHEME_HTML, + kTestHttpURL, GURL(kTestHttpURL)); + EXPECT_CALL(store(), GetLogins(form_digest, _)); + HttpPasswordMigrator migrator(GURL(kTestHttpsURL), &store(), &consumer()); + + PasswordForm form = CreateTestForm(); + PasswordForm psl_form = CreateTestPSLForm(); + PasswordForm android_form = CreateAndroidCredential(); + PasswordForm expected_form = form; + expected_form.origin = GURL(kTestHttpsURL); + expected_form.signon_realm = expected_form.origin.spec(); + expected_form.action = expected_form.origin; + + EXPECT_CALL(store(), AddLogin(expected_form)); + EXPECT_CALL(consumer(), ProcessForms(ElementsAre(Pointee(expected_form)))); + std::vector<std::unique_ptr<autofill::PasswordForm>> results; + results.push_back(base::MakeUnique<PasswordForm>(psl_form)); + results.push_back(base::MakeUnique<PasswordForm>(form)); + results.push_back(base::MakeUnique<PasswordForm>(android_form)); + migrator.OnGetPasswordStoreResults(std::move(results)); +} + +} // namespace +} // namespace password_manager
diff --git a/content/renderer/media/media_stream_audio_processor_options.cc b/content/renderer/media/media_stream_audio_processor_options.cc index 466ae9d5..cc5d7662 100644 --- a/content/renderer/media/media_stream_audio_processor_options.cc +++ b/content/renderer/media/media_stream_audio_processor_options.cc
@@ -467,6 +467,8 @@ stats->echo_delay_std_ms = apm_stats.delay_standard_deviation; stats->residual_echo_likelihood = apm_stats.residual_echo_likelihood; + stats->residual_echo_likelihood_recent_max = + apm_stats.residual_echo_likelihood_recent_max; } std::vector<webrtc::Point> GetArrayGeometryPreferringConstraints(
diff --git a/ios/BUILD.gn b/ios/BUILD.gn index 2b7e97d..79a7f39 100644 --- a/ios/BUILD.gn +++ b/ios/BUILD.gn
@@ -41,11 +41,6 @@ "//ios/testing:all_tests", "//ios/web:all_tests", "//ios/web/shell/test:all_tests", - - # Those dependencies are currently only used from downstream code - # and will be removed once the dependent code has been upstreamed. - "//ios/chrome/share_extension", - "//ios/chrome/today_extension", ] } }
diff --git a/ios/chrome/browser/google/BUILD.gn b/ios/chrome/browser/google/BUILD.gn index d7b940b..7750824 100644 --- a/ios/chrome/browser/google/BUILD.gn +++ b/ios/chrome/browser/google/BUILD.gn
@@ -19,6 +19,7 @@ "//components/prefs", "//ios/chrome/browser/browser_state", "//ios/public/provider/chrome/browser", + "//ios/public/provider/chrome/browser/distribution", ] }
diff --git a/ios/chrome/browser/google/google_brand.mm b/ios/chrome/browser/google/google_brand.mm index df5ae652..1405fe5 100644 --- a/ios/chrome/browser/google/google_brand.mm +++ b/ios/chrome/browser/google/google_brand.mm
@@ -5,6 +5,7 @@ #include "ios/chrome/browser/google/google_brand.h" #include "ios/public/provider/chrome/browser/chrome_browser_provider.h" +#include "ios/public/provider/chrome/browser/distribution/app_distribution_provider.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -17,7 +18,9 @@ if (!ios::GetChromeBrowserProvider()) return false; - brand->assign(ios::GetChromeBrowserProvider()->GetDistributionBrandCode()); + brand->assign(ios::GetChromeBrowserProvider() + ->GetAppDistributionProvider() + ->GetDistributionBrandCode()); return true; }
diff --git a/ios/chrome/browser/net/BUILD.gn b/ios/chrome/browser/net/BUILD.gn index b628ccce..2d147eb 100644 --- a/ios/chrome/browser/net/BUILD.gn +++ b/ios/chrome/browser/net/BUILD.gn
@@ -21,10 +21,6 @@ "ios_chrome_network_delegate.h", "ios_chrome_url_request_context_getter.cc", "ios_chrome_url_request_context_getter.h", - "metrics_network_client.h", - "metrics_network_client.mm", - "metrics_network_client_manager.h", - "metrics_network_client_manager.mm", "net_types.h", "proxy_service_factory.cc", "proxy_service_factory.h", @@ -59,7 +55,6 @@ testonly = true sources = [ "cookie_util_unittest.mm", - "metrics_network_client_unittest.mm", "retryable_url_fetcher_unittest.mm", ] deps = [
diff --git a/ios/chrome/browser/net/metrics_network_client.h b/ios/chrome/browser/net/metrics_network_client.h deleted file mode 100644 index 90b37fb..0000000 --- a/ios/chrome/browser/net/metrics_network_client.h +++ /dev/null
@@ -1,19 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_NET_METRICS_NETWORK_CLIENT_H_ -#define IOS_CHROME_BROWSER_NET_METRICS_NETWORK_CLIENT_H_ - -#import "ios/net/clients/crn_forwarding_network_client.h" - -@class MetricsNetworkClientManager; - -// MetricsNetworkClient records UMA metrics about the network requests. -@interface MetricsNetworkClient : CRNForwardingNetworkClient - -- (instancetype)initWithManager:(MetricsNetworkClientManager*)manager; - -@end - -#endif // IOS_CHROME_BROWSER_NET_METRICS_NETWORK_CLIENT_H_
diff --git a/ios/chrome/browser/net/metrics_network_client.mm b/ios/chrome/browser/net/metrics_network_client.mm deleted file mode 100644 index 1ac8e73..0000000 --- a/ios/chrome/browser/net/metrics_network_client.mm +++ /dev/null
@@ -1,89 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "ios/chrome/browser/net/metrics_network_client.h" - -#import "base/ios/weak_nsobject.h" -#include "base/logging.h" -#include "base/metrics/histogram_macros.h" -#include "base/strings/sys_string_conversions.h" -#import "ios/chrome/browser/net/metrics_network_client_manager.h" -#include "ios/web/public/url_util.h" -#include "net/base/net_errors.h" -#include "net/http/http_response_headers.h" -#include "net/url_request/url_request.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -@interface MetricsNetworkClient () { - BOOL _histogramUpdated; - // Pointer to the load time record for this request. This will be created - // and owned by |_manager|, and it will remain valid as long as |_manager| is. - __unsafe_unretained PageLoadTimeRecord* _loadTimeRecord; - // Pointer to the creating manager, which is owned by a tab. All network - // requests for the tab are destroyed before the tab is, so this pointer - // will always be valid as long as the owning client is alive. - __unsafe_unretained MetricsNetworkClientManager* _manager; - // A pointer to the request, kept so it can be referred to later. - scoped_refptr<net::HttpResponseHeaders> _nativeHeaders; -} -- (void)updateHistogram:(NSInteger)code; -@end - -@implementation MetricsNetworkClient - -- (void)updateHistogram:(NSInteger)code { - DCHECK(!_histogramUpdated) << "Histogram should not be updated twice."; - // The |error| must be in the |net::kErrorDomain|. All those errors are - // defined in |net/base/net_error_list.h|, must be negative values that - // fits in an |int|. See |net/base/net_errors.h| for more information. - DCHECK_LE(code, 0) << "Net error codes should be negative."; - DCHECK_GT(code, INT_MIN) << "Net error code should fit in an int."; - // On iOS, we cannot distinguish between main frames, images and other - // subresources. Consequently, all the codes are aggregated in - // |ErrorCodesForMainFrame3|. - // The other histograms (such as |ErrorCodesForHTTPSGoogleMainFrame2|, - // |ErrorCodesForImages| and |ErrorCodesForSubresources2|) are not filled. - UMA_HISTOGRAM_SPARSE_SLOWLY("Net.ErrorCodesForMainFrame3", - static_cast<int>(-code)); - _histogramUpdated = YES; -} - -- (instancetype)initWithManager:(MetricsNetworkClientManager*)manager { - if ((self = [super init])) { - _manager = manager; - } - return self; -} - -#pragma mark CRNNetworkClientProtocol methods - -- (void)didCreateNativeRequest:(net::URLRequest*)nativeRequest { - [super didCreateNativeRequest:nativeRequest]; - GURL url = web::GURLByRemovingRefFromGURL(nativeRequest->original_url()); - _loadTimeRecord = - [_manager recordForPageLoad:url time:nativeRequest->creation_time()]; - _nativeHeaders = nativeRequest->response_headers(); -} - -- (void)didFailWithNSErrorCode:(NSInteger)nsErrorCode - netErrorCode:(int)netErrorCode { - [super didFailWithNSErrorCode:nsErrorCode netErrorCode:netErrorCode]; - - // Ignore NSURLErrorCancelled errors, which are sometimes created to - // silently abort loads. - - if (nsErrorCode != NSURLErrorCancelled) { - [self updateHistogram:netErrorCode]; - } -} - -- (void)didFinishLoading { - [super didFinishLoading]; - [self updateHistogram:net::OK]; -} - -@end
diff --git a/ios/chrome/browser/net/metrics_network_client_manager.h b/ios/chrome/browser/net/metrics_network_client_manager.h deleted file mode 100644 index dc0c43b..0000000 --- a/ios/chrome/browser/net/metrics_network_client_manager.h +++ /dev/null
@@ -1,38 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_CHROME_BROWSER_NET_METRICS_NETWORK_CLIENT_MANAGER_H_ -#define IOS_CHROME_BROWSER_NET_METRICS_NETWORK_CLIENT_MANAGER_H_ - -#import <Foundation/Foundation.h> - -#import "base/time/time.h" -#import "ios/net/clients/crn_forwarding_network_client_factory.h" -#include "url/gurl.h" - -@interface PageLoadTimeRecord : NSObject -@end - -// Factory that creates MetricsNetworkClient instances. -// Each Tab that cares to report page load metrics should create an instance -// of this class add add it to its request tracker. -@interface MetricsNetworkClientManager : CRNForwardingNetworkClientFactory - -// Called by the tab when a new page load is about to start, to signal the -// current page URL. -- (void)pageLoadStarted:(GURL)url; - -// Called by the tab when the page load is complete. -- (void)pageLoadCompleted; - -// Return a page load time record that will be used to record a load of |url| -// that started at |time|. Returns nil if |url| doesn't match the current page -// url. The page load record is owned by the target, and the caller should not -// take ownership of it. -// This method should only be called on the IO thread. -- (PageLoadTimeRecord*)recordForPageLoad:(const GURL&)url - time:(base::TimeTicks)time; -@end - -#endif // IOS_CHROME_BROWSER_NET_METRICS_NETWORK_CLIENT_MANAGER_H_
diff --git a/ios/chrome/browser/net/metrics_network_client_manager.mm b/ios/chrome/browser/net/metrics_network_client_manager.mm deleted file mode 100644 index 38ee975..0000000 --- a/ios/chrome/browser/net/metrics_network_client_manager.mm +++ /dev/null
@@ -1,134 +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. - -#import "ios/chrome/browser/net/metrics_network_client_manager.h" - -#import "base/ios/weak_nsobject.h" -#import "base/location.h" -#include "base/mac/bind_objc_block.h" -#include "base/mac/scoped_nsobject.h" -#include "base/metrics/histogram.h" -#import "ios/chrome/browser/net/metrics_network_client.h" -#include "ios/web/public/web_thread.h" -#include "url/gurl.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -@interface PageLoadTimeRecord () - -@property(nonatomic, readonly) GURL url; -@property(nonatomic, readonly) base::TimeTicks creationTime; -@property(nonatomic, assign) BOOL alreadyCounted; - -- (instancetype)initWithURL:(const GURL&)url time:(base::TimeTicks)time; - -@end - -@implementation PageLoadTimeRecord { - GURL _url; - base::TimeTicks _creationTime; - BOOL _alreadyCounted; -} - -@synthesize url = _url; -@synthesize creationTime = _creationTime; -@synthesize alreadyCounted = _alreadyCounted; - -- (instancetype)initWithURL:(const GURL&)url time:(base::TimeTicks)time { - if ((self = [super init])) { - _url = url; - _creationTime = time; - } - return self; -} - -@end - -@interface MetricsNetworkClientManager () - -// IO-thread-only methods. -- (void)handlePageLoadStarted:(const GURL&)url; -- (void)handlePageLoadCompleted; - -@end - -@implementation MetricsNetworkClientManager { - // Set of page load time objects created. Beyond deallocation and - // creation, should only be accessed on the IO thread. - base::scoped_nsobject<NSMutableSet> _pageLoadTimes; - // Current URL being loaded by the tab that owns this object. Only accessible - // on the IO thread. - GURL _pageURL; -} - -- (instancetype)init { - if ((self = [super init])) { - _pageLoadTimes.reset([NSMutableSet set]); - } - return self; -} - -- (Class)clientClass { - return [MetricsNetworkClient class]; -} - -#pragma mark CRWForwardingNetworkClientFactory methods - -- (CRNForwardingNetworkClient*)clientHandlingRequest: - (const net::URLRequest&)request { - return [[MetricsNetworkClient alloc] initWithManager:self]; -} - -#pragma mark - public UI-thread methods - -- (void)pageLoadStarted:(GURL)url { - DCHECK_CURRENTLY_ON(web::WebThread::UI); - web::WebThread::PostTask(web::WebThread::IO, FROM_HERE, base::BindBlockArc(^{ - [self handlePageLoadStarted:url]; - })); -} - -- (void)pageLoadCompleted { - DCHECK_CURRENTLY_ON(web::WebThread::UI); - web::WebThread::PostTask(web::WebThread::IO, FROM_HERE, base::BindBlockArc(^{ - [self handlePageLoadCompleted]; - })); -} - -#pragma mark - public IO-thread methods - -- (PageLoadTimeRecord*)recordForPageLoad:(const GURL&)url - time:(base::TimeTicks)time { - DCHECK_CURRENTLY_ON(web::WebThread::IO); - base::scoped_nsobject<PageLoadTimeRecord> plt; - if (!_pageURL.spec().empty() && url == _pageURL) { - plt.reset([[PageLoadTimeRecord alloc] initWithURL:url time:time]); - [_pageLoadTimes addObject:plt]; - } - return plt.get(); -} - -#pragma mark - IO-thread handlers for UI thread methods. - -- (void)handlePageLoadStarted:(const GURL&)url { - DCHECK_CURRENTLY_ON(web::WebThread::IO); - [_pageLoadTimes removeAllObjects]; - _pageURL = url; -} - -- (void)handlePageLoadCompleted { - DCHECK_CURRENTLY_ON(web::WebThread::IO); - for (PageLoadTimeRecord* plt in _pageLoadTimes.get()) { - if (plt.url == _pageURL && !plt.alreadyCounted) { - plt.alreadyCounted = YES; - base::TimeDelta elapsed = base::TimeTicks::Now() - plt.creationTime; - UMA_HISTOGRAM_MEDIUM_TIMES("Tabs.iOS_PostRedirectPLT", elapsed); - break; - } - } -} - -@end
diff --git a/ios/chrome/browser/net/metrics_network_client_unittest.mm b/ios/chrome/browser/net/metrics_network_client_unittest.mm deleted file mode 100644 index ed93c28a..0000000 --- a/ios/chrome/browser/net/metrics_network_client_unittest.mm +++ /dev/null
@@ -1,76 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ios/chrome/browser/net/metrics_network_client.h" - -#include "base/mac/scoped_nsobject.h" -#include "base/test/histogram_tester.h" -#include "net/base/net_errors.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -// Dummy client to be registered as underlying client for the -// MetricsNetworkClient. -@interface MetricsMockClient : CRNForwardingNetworkClient -@end - -@implementation MetricsMockClient - -- (void)didFailWithNSErrorCode:(NSInteger)nsErrorCode - netErrorCode:(int)netErrorCode { -} - -- (void)didFinishLoading { -} - -@end - -namespace { - -// Name for the histogram the MetricsNetworkClient has to update. -const char kHistogramName[] = "Net.ErrorCodesForMainFrame3"; - -class MetricsNetworkClientTest : public testing::Test { - public: - MetricsNetworkClientTest() - : histogram_tester_(), client_([[MetricsNetworkClient alloc] init]) { - // Setup a dummy underlying client to avoid DCHECKs. - base::scoped_nsobject<MetricsMockClient> underying_client( - [[MetricsMockClient alloc] init]); - [client_ setUnderlyingClient:underying_client]; - } - - // Returns true if there are no samples for "Net.ErrorCodesForMainFrame3". - void VerifyNoSamples() { - histogram_tester_.ExpectTotalCount(kHistogramName, 0); - } - - protected: - base::HistogramTester histogram_tester_; - base::scoped_nsobject<MetricsNetworkClient> client_; -}; - -} // namespace - -TEST_F(MetricsNetworkClientTest, HistogramUpdatedOnErrors) { - int net_error = net::ERR_FAILED; - VerifyNoSamples(); - // NSURLErrorCancelled errors must not update the histogram. - [client_ didFailWithNSErrorCode:NSURLErrorCancelled netErrorCode:net_error]; - VerifyNoSamples(); - // Other iOS errors update the histogram. - [client_ didFailWithNSErrorCode:NSURLErrorCannotConnectToHost - netErrorCode:net_error]; - // |net_error| is negative, the histogram reports the opposite value. - histogram_tester_.ExpectUniqueSample(kHistogramName, -net_error, 1); -} - -TEST_F(MetricsNetworkClientTest, HistogramUpdatedOnSuccess) { - VerifyNoSamples(); - [client_ didFinishLoading]; - histogram_tester_.ExpectUniqueSample(kHistogramName, -net::OK, 1); -}
diff --git a/ios/chrome/browser/providers/chromium_browser_provider.h b/ios/chrome/browser/providers/chromium_browser_provider.h index cc5c31b1..ddd0e00 100644 --- a/ios/chrome/browser/providers/chromium_browser_provider.h +++ b/ios/chrome/browser/providers/chromium_browser_provider.h
@@ -20,8 +20,6 @@ ios::ChromeIdentityService* GetChromeIdentityService() override; UITextField<TextFieldStyling>* CreateStyledTextField( CGRect frame) const override NS_RETURNS_RETAINED; - void InitializeCastService(id main_tab_model) const override; - void AttachTabHelpers(web::WebState* web_state, id tab) const override; VoiceSearchProvider* GetVoiceSearchProvider() const override; id<LogoVendor> CreateLogoVendor(ios::ChromeBrowserState* browser_state, id<UrlLoader> loader) const override
diff --git a/ios/chrome/browser/providers/chromium_browser_provider.mm b/ios/chrome/browser/providers/chromium_browser_provider.mm index 3d5ed08..ab35120 100644 --- a/ios/chrome/browser/providers/chromium_browser_provider.mm +++ b/ios/chrome/browser/providers/chromium_browser_provider.mm
@@ -59,11 +59,6 @@ return [[ChromiumStyledTextField alloc] initWithFrame:CGRectZero]; } -void ChromiumBrowserProvider::InitializeCastService(id main_tab_model) const {} - -void ChromiumBrowserProvider::AttachTabHelpers(web::WebState* web_state, - id tab) const {} - VoiceSearchProvider* ChromiumBrowserProvider::GetVoiceSearchProvider() const { return voice_search_provider_.get(); }
diff --git a/ios/chrome/browser/tabs/BUILD.gn b/ios/chrome/browser/tabs/BUILD.gn index 8a5b6e5..3ac08a4 100644 --- a/ios/chrome/browser/tabs/BUILD.gn +++ b/ios/chrome/browser/tabs/BUILD.gn
@@ -74,7 +74,6 @@ "//ios/chrome/browser/metrics", "//ios/chrome/browser/metrics:metrics_internal", "//ios/chrome/browser/native_app_launcher:native_app_launcher_internal", - "//ios/chrome/browser/net", "//ios/chrome/browser/passwords", "//ios/chrome/browser/passwords:passwords_internal", "//ios/chrome/browser/reading_list",
diff --git a/ios/chrome/browser/tabs/tab.mm b/ios/chrome/browser/tabs/tab.mm index f1119e3..db9e457 100644 --- a/ios/chrome/browser/tabs/tab.mm +++ b/ios/chrome/browser/tabs/tab.mm
@@ -70,7 +70,6 @@ #include "ios/chrome/browser/metrics/ios_chrome_origins_seen_service_factory.h" #import "ios/chrome/browser/metrics/tab_usage_recorder.h" #import "ios/chrome/browser/native_app_launcher/native_app_navigation_controller.h" -#import "ios/chrome/browser/net/metrics_network_client_manager.h" #import "ios/chrome/browser/passwords/credential_manager.h" #import "ios/chrome/browser/passwords/js_credential_manager.h" #import "ios/chrome/browser/passwords/password_controller.h" @@ -130,7 +129,6 @@ #import "ios/web/navigation/crw_session_entry.h" #import "ios/web/navigation/navigation_item_impl.h" #import "ios/web/navigation/navigation_manager_impl.h" -#include "ios/web/net/request_tracker_impl.h" #include "ios/web/public/favicon_status.h" #include "ios/web/public/favicon_url.h" #include "ios/web/public/interstitials/web_interstitial.h" @@ -333,10 +331,6 @@ // C++ observer to implement the credential management JavaScript API. std::unique_ptr<CredentialManager> credentialManager_; - - // Client factory created for metrics tracking. The Tab will signal page - // load starts and finishes to this. - base::scoped_nsobject<MetricsNetworkClientManager> metricsClientManager_; } // Returns the current sessionEntry for the sesionController associated with @@ -506,16 +500,6 @@ [owner_ updateSnapshotWithOverlay:YES visibleFrameOnly:YES]; } -// Registers |factory| with |tracker| on the IO thread. -void AddNetworkClientFactoryOnIOThread( - web::RequestTrackerImpl* tracker, - CRNForwardingNetworkClientFactory* factory) { - base::scoped_nsobject<CRNForwardingNetworkClientFactory> scoped_factory( - [factory retain]); - tracker->PostIOTask(base::Bind(&net::RequestTracker::AddNetworkClientFactory, - tracker, scoped_factory)); -} - } // anonymous namespace @implementation Tab @@ -649,11 +633,6 @@ self.webState, ios::TopSitesFactory::GetForBrowserState(original_browser_state).get()); [self setShouldObserveFaviconChanges:YES]; - web::RequestTrackerImpl* requestTracker = - webStateImpl_->GetRequestTracker(); - - metricsClientManager_.reset([[MetricsNetworkClientManager alloc] init]); - AddNetworkClientFactoryOnIOThread(requestTracker, metricsClientManager_); if (parentModel && parentModel.syncedWindowDelegate) { IOSChromeSessionTabHelper::FromWebState(self.webState) @@ -1798,7 +1777,6 @@ postNotificationName: kTabClosingCurrentDocumentNotificationForCrashReporting object:self]; - [metricsClientManager_ pageLoadStarted:URL]; } - (void)webCancelStartLoadingRequest { @@ -1902,7 +1880,6 @@ [self handleExportableFile:headers.get()]; } - [metricsClientManager_ pageLoadCompleted]; [parentTabModel_ notifyTabChanged:self]; if (parentTabModel_) {
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm index 6749fc2..31d9288 100644 --- a/ios/chrome/browser/ui/browser_view_controller.mm +++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -941,7 +941,8 @@ _tabStripController.reset(); _infoBarContainer.reset(); _readingListMenuNotifier.reset(); - _bookmarkModel->RemoveObserver(_bookmarkModelBridge.get()); + if (_bookmarkModel) + _bookmarkModel->RemoveObserver(_bookmarkModelBridge.get()); [_model removeObserver:self]; [[UpgradeCenter sharedInstance] unregisterClient:self]; [[NSNotificationCenter defaultCenter] removeObserver:self]; @@ -1656,10 +1657,13 @@ _imageFetcher->SetRequestContextGetter(_browserState->GetRequestContext()); _dominantColorCache.reset([[NSMutableDictionary alloc] init]); - // Register for bookmark changed notification. - _bookmarkModelBridge.reset(new BrowserBookmarkModelBridge(self)); + // Register for bookmark changed notification (BookmarkModel may be null + // during testing, so explicitly support this). _bookmarkModel = ios::BookmarkModelFactory::GetForBrowserState(_browserState); - _bookmarkModel->AddObserver(_bookmarkModelBridge.get()); + if (_bookmarkModel) { + _bookmarkModelBridge.reset(new BrowserBookmarkModelBridge(self)); + _bookmarkModel->AddObserver(_bookmarkModelBridge.get()); + } } - (void)ensureViewCreated { @@ -2155,7 +2159,7 @@ // TODO(noyau): this is incorrect, the caller should know that the model is // not loaded yet. - if (!_bookmarkModel->loaded()) + if (!_bookmarkModel || !_bookmarkModel->loaded()) return filesReferencedByTabs; std::vector<bookmarks::BookmarkModel::URLAndTitle> bookmarks; @@ -2482,19 +2486,19 @@ }; [_contextMenuCoordinator addItemWithTitle:title action:action]; } - - if (reading_list::switches::IsReadingListEnabled()) { - NSString* innerText = params.link_text; - if ([innerText length] > 0) { - // Add to reading list. - title = l10n_util::GetNSStringWithFixup( - IDS_IOS_CONTENT_CONTEXT_ADDTOREADINGLIST); - action = ^{ - Record(ACTION_READ_LATER, isImage, isLink); - [weakSelf addToReadingListURL:link title:innerText]; - }; - [_contextMenuCoordinator addItemWithTitle:title action:action]; - } + } + if (link.SchemeIsHTTPOrHTTPS() && + reading_list::switches::IsReadingListEnabled()) { + NSString* innerText = params.link_text; + if ([innerText length] > 0) { + // Add to reading list. + title = l10n_util::GetNSStringWithFixup( + IDS_IOS_CONTENT_CONTEXT_ADDTOREADINGLIST); + action = ^{ + Record(ACTION_READ_LATER, isImage, isLink); + [weakSelf addToReadingListURL:link title:innerText]; + }; + [_contextMenuCoordinator addItemWithTitle:title action:action]; } } // Copy Link.
diff --git a/ios/chrome/browser/ui/main/browser_view_wrangler_unittest.mm b/ios/chrome/browser/ui/main/browser_view_wrangler_unittest.mm index c9b4648..8b20b01 100644 --- a/ios/chrome/browser/ui/main/browser_view_wrangler_unittest.mm +++ b/ios/chrome/browser/ui/main/browser_view_wrangler_unittest.mm
@@ -7,8 +7,6 @@ #import <UIKit/UIKit.h> #include "base/mac/scoped_nsobject.h" -#include "components/bookmarks/test/bookmark_test_helpers.h" -#include "ios/chrome/browser/bookmarks/bookmark_model_factory.h" #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h" #import "ios/chrome/browser/tabs/tab_model.h" #import "ios/chrome/browser/ui/browser_view_controller.h" @@ -22,14 +20,8 @@ BrowserViewWranglerTest() { TestChromeBrowserState::Builder test_cbs_builder; chrome_browser_state_ = test_cbs_builder.Build(); - chrome_browser_state_->CreateBookmarkModel(false); - bookmarks::BookmarkModel* bookmark_model = - ios::BookmarkModelFactory::GetForBrowserState( - chrome_browser_state_.get()); - bookmarks::test::WaitForBookmarkModelToLoad(bookmark_model); } - // SessionWindow, used to create the TabModel, needs to run on the web thread. web::TestWebThreadBundle thread_bundle_; std::unique_ptr<TestChromeBrowserState> chrome_browser_state_; };
diff --git a/ios/chrome/browser/ui/suggestions/BUILD.gn b/ios/chrome/browser/ui/suggestions/BUILD.gn index 4b9e43a..d99d9c5 100644 --- a/ios/chrome/browser/ui/suggestions/BUILD.gn +++ b/ios/chrome/browser/ui/suggestions/BUILD.gn
@@ -5,11 +5,14 @@ source_set("suggestions") { configs += [ "//build/config/compiler:enable_arc" ] sources = [ + "expandable_item.h", "suggestions_article_item.h", "suggestions_article_item.mm", "suggestions_collection_updater.h", "suggestions_collection_updater.mm", "suggestions_commands.h", + "suggestions_expandable_item.h", + "suggestions_expandable_item.mm", "suggestions_item.h", "suggestions_item.mm", "suggestions_item_actions.h", @@ -21,6 +24,7 @@ "//ios/chrome/browser/ui", "//ios/chrome/browser/ui/collection_view", "//ios/third_party/material_roboto_font_loader_ios", + "//ui/base", ] public_deps = [ "//ios/third_party/material_components_ios", @@ -31,10 +35,13 @@ testonly = true sources = [ "suggestions_article_item_unittest.mm", + "suggestions_expandable_item_unittest.mm", + "suggestions_item_unittest.mm", ] deps = [ ":suggestions", "//ios/chrome/browser/ui/collection_view", "//testing/gtest", + "//third_party/ocmock", ] }
diff --git a/ios/chrome/browser/ui/suggestions/expandable_item.h b/ios/chrome/browser/ui/suggestions/expandable_item.h new file mode 100644 index 0000000..b96c112 --- /dev/null +++ b/ios/chrome/browser/ui/suggestions/expandable_item.h
@@ -0,0 +1,18 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_UI_SUGGESTIONS_EXPANDABLE_ITEM_H_ +#define IOS_CHROME_BROWSER_UI_SUGGESTIONS_EXPANDABLE_ITEM_H_ + +#import <UIKit/UIKit.h> + +// Protocol allowing a CollectionViewItem to be expanded. +@protocol SuggestionsExpandableArticle + +// Whether the cells should be in expanded mode. +@property(nonatomic) BOOL expanded; + +@end + +#endif // IOS_CHROME_BROWSER_UI_SUGGESTIONS_EXPANDABLE_ITEM_H_
diff --git a/ios/chrome/browser/ui/suggestions/suggestions_collection_updater.h b/ios/chrome/browser/ui/suggestions/suggestions_collection_updater.h index 48424b8..aadb227 100644 --- a/ios/chrome/browser/ui/suggestions/suggestions_collection_updater.h +++ b/ios/chrome/browser/ui/suggestions/suggestions_collection_updater.h
@@ -7,7 +7,7 @@ #import <UIKit/UIKit.h> -@class CollectionViewController; +@class SuggestionsViewController; // Updater for a CollectionViewController populating it with some items and // handling the items addition. @@ -15,7 +15,7 @@ // |collectionViewController| this Updater will update. - (instancetype)initWithCollectionViewController: - (CollectionViewController*)collectionViewController + (SuggestionsViewController*)collectionViewController NS_DESIGNATED_INITIALIZER; - (instancetype)init NS_UNAVAILABLE;
diff --git a/ios/chrome/browser/ui/suggestions/suggestions_collection_updater.mm b/ios/chrome/browser/ui/suggestions/suggestions_collection_updater.mm index 51814e35..01c6d0c 100644 --- a/ios/chrome/browser/ui/suggestions/suggestions_collection_updater.mm +++ b/ios/chrome/browser/ui/suggestions/suggestions_collection_updater.mm
@@ -4,10 +4,13 @@ #import "ios/chrome/browser/ui/suggestions/suggestions_collection_updater.h" +#include "base/mac/foundation_util.h" #import "ios/chrome/browser/ui/collection_view/collection_view_controller.h" #import "ios/chrome/browser/ui/collection_view/collection_view_model.h" #import "ios/chrome/browser/ui/suggestions/suggestions_article_item.h" +#import "ios/chrome/browser/ui/suggestions/suggestions_expandable_item.h" #import "ios/chrome/browser/ui/suggestions/suggestions_item.h" +#import "ios/chrome/browser/ui/suggestions/suggestions_view_controller.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -23,11 +26,11 @@ } // namespace @implementation SuggestionsCollectionUpdater { - CollectionViewController* _collectionViewController; + SuggestionsViewController* _collectionViewController; } - (instancetype)initWithCollectionViewController: - (CollectionViewController*)collectionViewController { + (SuggestionsViewController*)collectionViewController { self = [super init]; if (self) { _collectionViewController = collectionViewController; @@ -48,6 +51,19 @@ @"spawn on multiple lines" image:[UIImage imageNamed:@"distillation_success"]] toSectionWithIdentifier:sectionIdentifier]; + SuggestionsExpandableItem* expandableItem = + [[SuggestionsExpandableItem alloc] + initWithType:ItemTypeExpand + title:@"Title of an Expandable Article" + subtitle:@"This Article can be expanded to display " + @"additional information or interaction " + @"options" + image:[UIImage imageNamed:@"distillation_fail"] + detailText:@"Details shown only when the article is " + @"expanded. It can be displayed on " + @"multiple lines."]; + expandableItem.delegate = collectionViewController; + [model addItem:expandableItem toSectionWithIdentifier:sectionIdentifier]; sectionIdentifier++; } }
diff --git a/ios/chrome/browser/ui/suggestions/suggestions_expandable_item.h b/ios/chrome/browser/ui/suggestions/suggestions_expandable_item.h new file mode 100644 index 0000000..174ab5c8 --- /dev/null +++ b/ios/chrome/browser/ui/suggestions/suggestions_expandable_item.h
@@ -0,0 +1,57 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_CHROME_BROWSER_UI_SUGGESTIONS_SUGGESTIONS_EXPANDABLE_ITEM_H_ +#define IOS_CHROME_BROWSER_UI_SUGGESTIONS_SUGGESTIONS_EXPANDABLE_ITEM_H_ + +#import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h" +#import "ios/chrome/browser/ui/suggestions/expandable_item.h" +#import "ios/third_party/material_components_ios/src/components/CollectionCells/src/MaterialCollectionCells.h" + +@class SuggestionsExpandableCell; + +// Delegate for the SuggestionsExpandableCell. The delegate will take care of +// the expansion/collapsing of the cell. +@protocol SuggestionsExpandableCellDelegate + +- (void)expandCell:(UICollectionViewCell*)cell; +- (void)collapseCell:(UICollectionViewCell*)cell; + +@end + +// Item for an expandable article in the suggestions. An expandable article can +// be expanded, displaying more informations/interactions. +@interface SuggestionsExpandableItem + : CollectionViewItem<SuggestionsExpandableArticle> + +// Init the article with a |title|, a |subtitle| an |image| and some |detail| +// displayed only when the article is expanded. |type| is the type of the item. +- (instancetype)initWithType:(NSInteger)type + title:(NSString*)title + subtitle:(NSString*)subtitle + image:(UIImage*)image + detailText:(NSString*)detail NS_DESIGNATED_INITIALIZER; + +- (instancetype)initWithType:(NSInteger)type NS_UNAVAILABLE; + +// Delegate for the configured cells. +@property(nonatomic, weak) id<SuggestionsExpandableCellDelegate> delegate; + +@end + +// Corresponding cell of an expandable article. +@interface SuggestionsExpandableCell : MDCCollectionViewCell + +@property(nonatomic, weak) id<SuggestionsExpandableCellDelegate> delegate; +@property(nonatomic, readonly, strong) UILabel* titleLabel; +@property(nonatomic, readonly, strong) UILabel* subtitleLabel; +@property(nonatomic, readonly, strong) UILabel* detailLabel; +@property(nonatomic, strong) UIImageView* imageView; + +- (void)expand; +- (void)collapse; + +@end + +#endif // IOS_CHROME_BROWSER_UI_SUGGESTIONS_SUGGESTIONS_EXPANDABLE_ITEM_H_
diff --git a/ios/chrome/browser/ui/suggestions/suggestions_expandable_item.mm b/ios/chrome/browser/ui/suggestions/suggestions_expandable_item.mm new file mode 100644 index 0000000..761294e --- /dev/null +++ b/ios/chrome/browser/ui/suggestions/suggestions_expandable_item.mm
@@ -0,0 +1,237 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/ui/suggestions/suggestions_expandable_item.h" + +#import "ios/chrome/browser/ui/uikit_ui_util.h" +#include "ui/base/l10n/l10n_util_mac.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +namespace { +const CGFloat kImageSize = 80; +const CGFloat kStandardSpacing = 8; +} + +#pragma mark - SuggestionsExpandableItem + +@implementation SuggestionsExpandableItem { + NSString* _title; + NSString* _subtitle; + UIImage* _image; + NSString* _detail; +} + +@synthesize delegate = _delegate; +@synthesize expanded = _expanded; + +- (instancetype)initWithType:(NSInteger)type + title:(NSString*)title + subtitle:(NSString*)subtitle + image:(UIImage*)image + detailText:(NSString*)detail { + self = [super initWithType:type]; + if (self) { + self.cellClass = [SuggestionsExpandableCell class]; + _title = [title copy]; + _subtitle = [subtitle copy]; + _image = image; + _detail = [detail copy]; + } + return self; +} + +#pragma mark - CollectionViewItem + +- (void)configureCell:(SuggestionsExpandableCell*)cell { + [super configureCell:cell]; + cell.delegate = self.delegate; + cell.titleLabel.text = _title; + cell.subtitleLabel.text = _subtitle; + cell.imageView.image = _image; + cell.detailLabel.text = _detail; + if (self.expanded) + [cell expand]; + else + [cell collapse]; +} + +@end + +#pragma mark - SuggestionsExpandableCell + +@interface SuggestionsExpandableCell () { + UIView* _articleContainer; + UIButton* _interactionButton; + UIButton* _expandButton; + BOOL _expanded; + NSArray<NSLayoutConstraint*>* _expandedConstraints; + NSArray<NSLayoutConstraint*>* _collapsedConstraints; +} + +// Callback for the UI action showing the details. +- (void)expand:(id)sender; +// Callback for the UI action hiding the details. +- (void)collapse:(id)sender; + +@end + +@implementation SuggestionsExpandableCell + +@synthesize titleLabel = _titleLabel; +@synthesize subtitleLabel = _subtitleLabel; +@synthesize detailLabel = _detailLabel; +@synthesize imageView = _imageView; +@synthesize delegate = _delegate; + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + _expanded = NO; + _titleLabel = [[UILabel alloc] initWithFrame:CGRectZero]; + _subtitleLabel = [[UILabel alloc] initWithFrame:CGRectZero]; + _imageView = [[UIImageView alloc] initWithFrame:CGRectZero]; + _articleContainer = [[UIView alloc] initWithFrame:CGRectZero]; + _expandButton = [UIButton buttonWithType:UIButtonTypeSystem]; + _detailLabel = [[UILabel alloc] initWithFrame:CGRectZero]; + _interactionButton = [UIButton buttonWithType:UIButtonTypeSystem]; + + _subtitleLabel.numberOfLines = 0; + [_expandButton setTitle:@"See more" forState:UIControlStateNormal]; + _detailLabel.numberOfLines = 0; + [_interactionButton setTitle:@"Less interaction" + forState:UIControlStateNormal]; + + _imageView.translatesAutoresizingMaskIntoConstraints = NO; + _titleLabel.translatesAutoresizingMaskIntoConstraints = NO; + _subtitleLabel.translatesAutoresizingMaskIntoConstraints = NO; + _articleContainer.translatesAutoresizingMaskIntoConstraints = NO; + _expandButton.translatesAutoresizingMaskIntoConstraints = NO; + _detailLabel.translatesAutoresizingMaskIntoConstraints = NO; + _interactionButton.translatesAutoresizingMaskIntoConstraints = NO; + + [_expandButton addTarget:self + action:@selector(expand:) + forControlEvents:UIControlEventTouchUpInside]; + [_interactionButton addTarget:self + action:@selector(collapse:) + forControlEvents:UIControlEventTouchUpInside]; + + [_articleContainer addSubview:_imageView]; + [_articleContainer addSubview:_titleLabel]; + [_articleContainer addSubview:_subtitleLabel]; + + [self.contentView addSubview:_articleContainer]; + [self.contentView addSubview:_expandButton]; + + [NSLayoutConstraint activateConstraints:@[ + [self.contentView.centerXAnchor + constraintEqualToAnchor:_expandButton.centerXAnchor], + [_expandButton.topAnchor + constraintEqualToAnchor:_articleContainer.bottomAnchor], + [_expandButton.bottomAnchor + constraintEqualToAnchor:self.contentView.bottomAnchor], + [_articleContainer.bottomAnchor + constraintGreaterThanOrEqualToAnchor:_imageView.bottomAnchor + constant:kStandardSpacing], + [_articleContainer.bottomAnchor + constraintGreaterThanOrEqualToAnchor:_subtitleLabel.bottomAnchor + constant:kStandardSpacing], + ]]; + + ApplyVisualConstraintsWithMetrics( + @[ + @"H:|[container]|", @"H:|-[title]-[image(imageSize)]-|", + @"H:|-[text]-[image]", @"V:|-[image(imageSize)]", + @"V:|-[title]-[text]", @"V:|[container]" + ], + @{ + @"image" : _imageView, + @"title" : _titleLabel, + @"text" : _subtitleLabel, + @"container" : _articleContainer + }, + @{ @"imageSize" : @(kImageSize) }); + + _expandedConstraints = @[ + [_detailLabel.topAnchor + constraintEqualToAnchor:_articleContainer.bottomAnchor], + [_detailLabel.bottomAnchor + constraintEqualToAnchor:_interactionButton.topAnchor], + [_interactionButton.bottomAnchor + constraintEqualToAnchor:self.contentView.bottomAnchor], + [_detailLabel.leadingAnchor + constraintEqualToAnchor:self.contentView.leadingAnchor], + [_detailLabel.trailingAnchor + constraintEqualToAnchor:self.contentView.trailingAnchor] + ]; + _collapsedConstraints = @[ + [self.contentView.centerXAnchor + constraintEqualToAnchor:_expandButton.centerXAnchor], + [_expandButton.topAnchor + constraintEqualToAnchor:_articleContainer.bottomAnchor], + [_expandButton.bottomAnchor + constraintEqualToAnchor:self.contentView.bottomAnchor] + ]; + } + return self; +} + +#pragma mark - Private + +- (void)expand:(id)sender { + [self.delegate expandCell:self]; +} + +- (void)collapse:(id)sender { + [self.delegate collapseCell:self]; +} + +- (void)expand { + if (_expanded) + return; + _expanded = YES; + + [self.contentView addSubview:_detailLabel]; + [self.contentView addSubview:_interactionButton]; + [_expandButton removeFromSuperview]; + + [NSLayoutConstraint deactivateConstraints:_collapsedConstraints]; + [NSLayoutConstraint activateConstraints:_expandedConstraints]; +} + +- (void)collapse { + if (!_expanded) + return; + _expanded = NO; + + [_detailLabel removeFromSuperview]; + [_interactionButton removeFromSuperview]; + [self.contentView addSubview:_expandButton]; + + [NSLayoutConstraint deactivateConstraints:_expandedConstraints]; + [NSLayoutConstraint activateConstraints:_collapsedConstraints]; +} + +#pragma mark - UIView + +// Implements -layoutSubviews as per instructions in documentation for +// +[MDCCollectionViewCell cr_preferredHeightForWidth:forItem:]. +- (void)layoutSubviews { + [super layoutSubviews]; + + // Adjust the text label preferredMaxLayoutWidth when the parent's width + // changes, for instance on screen rotation. + CGFloat parentWidth = CGRectGetWidth(self.contentView.bounds); + _subtitleLabel.preferredMaxLayoutWidth = parentWidth - kImageSize - 3 * 8; + _detailLabel.preferredMaxLayoutWidth = parentWidth; + + // Re-layout with the new preferred width to allow the label to adjust its + // height. + [super layoutSubviews]; +} + +@end
diff --git a/ios/chrome/browser/ui/suggestions/suggestions_expandable_item_unittest.mm b/ios/chrome/browser/ui/suggestions/suggestions_expandable_item_unittest.mm new file mode 100644 index 0000000..906abf7 --- /dev/null +++ b/ios/chrome/browser/ui/suggestions/suggestions_expandable_item_unittest.mm
@@ -0,0 +1,104 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/ui/suggestions/suggestions_expandable_item.h" + +#import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h" +#include "testing/gtest/include/gtest/gtest.h" +#import "third_party/ocmock/OCMock/OCMock.h" +#include "third_party/ocmock/gtest_support.h" + +// Test subclass of the SuggestionsExpandableCell. +@interface TestSuggestionsExpandableCell : SuggestionsExpandableCell + +@property(nonatomic) BOOL expandCalled; +@property(nonatomic) BOOL collapseCalled; + +@end + +@implementation TestSuggestionsExpandableCell + +@synthesize expandCalled; +@synthesize collapseCalled; + +- (void)expand { + [super expand]; + self.expandCalled = YES; +} + +- (void)collapse { + [super collapse]; + self.collapseCalled = YES; +} + +@end + +namespace { + +// Tests that configureCell: set all the fields of the cell. +TEST(SuggestionsExpandableItemTest, CellIsConfigured) { + NSString* title = @"testTitle"; + NSString* subtitle = @"testSubtitle"; + UIImage* image = [[UIImage alloc] init]; + NSString* details = @"testDetails"; + id mockDelegate = [OCMockObject + mockForProtocol:@protocol(SuggestionsExpandableCellDelegate)]; + + SuggestionsExpandableItem* item = + [[SuggestionsExpandableItem alloc] initWithType:0 + title:title + subtitle:subtitle + image:image + detailText:details]; + item.delegate = mockDelegate; + SuggestionsExpandableCell* cell = [[[item cellClass] alloc] init]; + EXPECT_TRUE([cell isMemberOfClass:[SuggestionsExpandableCell class]]); + + [item configureCell:cell]; + EXPECT_EQ(title, cell.titleLabel.text); + EXPECT_EQ(subtitle, cell.subtitleLabel.text); + EXPECT_EQ(image, cell.imageView.image); + EXPECT_EQ(details, cell.detailLabel.text); + EXPECT_EQ(mockDelegate, cell.delegate); +} + +// Tests that if the expanded property of the item is YES, the |expand| method +// of the cell is called during configuration. +TEST(SuggestionsExpandableItemTest, CellIsExpanded) { + SuggestionsExpandableItem* item = + [[SuggestionsExpandableItem alloc] initWithType:0 + title:@"title" + subtitle:@"subtitle" + image:nil + detailText:@"detail"]; + TestSuggestionsExpandableCell* cell = + [[TestSuggestionsExpandableCell alloc] init]; + item.cellClass = [TestSuggestionsExpandableCell class]; + + item.expanded = YES; + [item configureCell:cell]; + ASSERT_TRUE(cell.expandCalled); + ASSERT_FALSE(cell.collapseCalled); +} + +// Tests that if the expanded property of the item is NO, the |collapse| method +// of the cell is called during configuration. +TEST(SuggestionsExpandableItemTest, CellIsCollapsed) { + SuggestionsExpandableItem* item = + [[SuggestionsExpandableItem alloc] initWithType:0 + title:@"title" + subtitle:@"subtitle" + image:nil + detailText:@"detail"]; + TestSuggestionsExpandableCell* cell = + [[TestSuggestionsExpandableCell alloc] init]; + item.cellClass = [TestSuggestionsExpandableCell class]; + + item.expanded = NO; + [item configureCell:cell]; + ASSERT_TRUE(cell.collapseCalled); + ASSERT_FALSE(cell.expandCalled); +} + +} // namespace
diff --git a/ios/chrome/browser/ui/suggestions/suggestions_item_unittest.mm b/ios/chrome/browser/ui/suggestions/suggestions_item_unittest.mm new file mode 100644 index 0000000..d5ae0f85 --- /dev/null +++ b/ios/chrome/browser/ui/suggestions/suggestions_item_unittest.mm
@@ -0,0 +1,26 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/ui/suggestions/suggestions_item.h" + +#import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +// Tests that configureCell: set all the fields of the cell. +TEST(SuggestionsItemTest, CellIsConfigured) { + NSString* title = @"testTitle"; + NSString* subtitle = @"testSubtitle"; + SuggestionsItem* item = + [[SuggestionsItem alloc] initWithType:0 title:title subtitle:subtitle]; + SuggestionsCell* cell = [[[item cellClass] alloc] init]; + EXPECT_TRUE([cell isMemberOfClass:[SuggestionsCell class]]); + + [item configureCell:cell]; + EXPECT_EQ(title, [cell.titleButton titleForState:UIControlStateNormal]); + EXPECT_EQ(subtitle, cell.detailTextLabel.text); +} + +} // namespace
diff --git a/ios/chrome/browser/ui/suggestions/suggestions_view_controller.h b/ios/chrome/browser/ui/suggestions/suggestions_view_controller.h index b058da8..8d81fd01 100644 --- a/ios/chrome/browser/ui/suggestions/suggestions_view_controller.h +++ b/ios/chrome/browser/ui/suggestions/suggestions_view_controller.h
@@ -8,11 +8,13 @@ #import <UIKit/UIKit.h> #import "ios/chrome/browser/ui/collection_view/collection_view_controller.h" +#import "ios/chrome/browser/ui/suggestions/suggestions_expandable_item.h" @protocol SuggestionsCommands; // CollectionViewController to display the suggestions items. -@interface SuggestionsViewController : CollectionViewController +@interface SuggestionsViewController + : CollectionViewController<SuggestionsExpandableCellDelegate> // Handler for the commands sent by the SuggestionsViewController. @property(nonatomic, weak) id<SuggestionsCommands> suggestionCommandHandler;
diff --git a/ios/chrome/browser/ui/suggestions/suggestions_view_controller.mm b/ios/chrome/browser/ui/suggestions/suggestions_view_controller.mm index a27da97a..84a8ef63 100644 --- a/ios/chrome/browser/ui/suggestions/suggestions_view_controller.mm +++ b/ios/chrome/browser/ui/suggestions/suggestions_view_controller.mm
@@ -4,9 +4,11 @@ #import "ios/chrome/browser/ui/suggestions/suggestions_view_controller.h" +#include "base/mac/foundation_util.h" #import "ios/chrome/browser/ui/collection_view/cells/MDCCollectionViewCell+Chrome.h" #import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h" #import "ios/chrome/browser/ui/collection_view/collection_view_model.h" +#import "ios/chrome/browser/ui/suggestions/expandable_item.h" #import "ios/chrome/browser/ui/suggestions/suggestions_collection_updater.h" #import "ios/chrome/browser/ui/suggestions/suggestions_commands.h" #import "ios/chrome/browser/ui/suggestions/suggestions_item_actions.h" @@ -15,10 +17,18 @@ #error "This file requires ARC support." #endif +namespace { +const NSTimeInterval kAnimationDuration = 0.35; +} // namespace + @interface SuggestionsViewController ()<SuggestionsItemActions> @property(nonatomic, strong) SuggestionsCollectionUpdater* collectionUpdater; +// Expand or collapse the |cell|, if it is a SuggestionsExpandableCell, +// according to |expand|. +- (void)expand:(BOOL)expand cell:(UICollectionViewCell*)cell; + @end @implementation SuggestionsViewController @@ -54,6 +64,16 @@ forItem:item]; } +#pragma mark - SuggestionsExpandableCellDelegate + +- (void)collapseCell:(UICollectionViewCell*)cell { + [self expand:NO cell:cell]; +} + +- (void)expandCell:(UICollectionViewCell*)cell { + [self expand:YES cell:cell]; +} + #pragma mark - SuggestionsItemActions - (void)addNewItem:(id)sender { @@ -70,4 +90,29 @@ toSection:inputSection]; } +#pragma mark - Private + +- (void)expand:(BOOL)expand cell:(UICollectionViewCell*)cell { + NSIndexPath* indexPath = [self.collectionView indexPathForCell:cell]; + CollectionViewItem* item = + [self.collectionViewModel itemAtIndexPath:indexPath]; + if ([item conformsToProtocol:@protocol(SuggestionsExpandableArticle)]) { + id<SuggestionsExpandableArticle> expandableItem = + (id<SuggestionsExpandableArticle>)item; + + NSInteger sectionIdentifier = [self.collectionViewModel + sectionIdentifierForSection:indexPath.section]; + + expandableItem.expanded = expand; + [self reconfigureCellsForItems:@[ item ] + inSectionWithIdentifier:sectionIdentifier]; + + [UIView + animateWithDuration:kAnimationDuration + animations:^{ + [self.collectionView.collectionViewLayout invalidateLayout]; + }]; + } +} + @end
diff --git a/ios/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc b/ios/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc index ecf5386..c36e931e5 100644 --- a/ios/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc +++ b/ios/chrome/browser/ui/webui/ntp_tiles_internals_ui.cc
@@ -34,6 +34,7 @@ void RegisterMessages() override; // ntp_tiles::NTPTilesInternalsMessageHandlerClient + bool SupportsNTPTiles() override; bool DoesSourceExist(ntp_tiles::NTPTileSource source) override; std::unique_ptr<ntp_tiles::MostVisitedSites> MakeMostVisitedSites() override; std::unique_ptr<ntp_tiles::PopularSites> MakePopularSites() override; @@ -54,6 +55,11 @@ handler_.RegisterMessages(this); } +bool IOSNTPTilesInternalsMessageHandlerBridge::SupportsNTPTiles() { + auto* state = ios::ChromeBrowserState::FromWebUIIOS(web_ui()); + return !state->HasOffTheRecordChromeBrowserState(); +} + bool IOSNTPTilesInternalsMessageHandlerBridge::DoesSourceExist( ntp_tiles::NTPTileSource source) { switch (source) {
diff --git a/ios/chrome/browser/web/browsing_egtest.mm b/ios/chrome/browser/web/browsing_egtest.mm index e136731c..f23a1faa 100644 --- a/ios/chrome/browser/web/browsing_egtest.mm +++ b/ios/chrome/browser/web/browsing_egtest.mm
@@ -580,7 +580,15 @@ // Tests that submitting a POST-based form by tapping the 'Go' button on the // keyboard navigates to the correct URL and the back button works as expected // afterwards. -- (void)testBrowsingPostEntryWithKeyboard { +// TODO(crbug.com/670380): Enable this test on device. +#if TARGET_IPHONE_SIMULATOR +#define MAYBE_testBrowsingPostEntryWithKeyboard \ + testBrowsingPostEntryWithKeyboard +#else +#define MAYBE_testBrowsingPostEntryWithKeyboard \ + FLAKY_testBrowsingPostEntryWithKeyboard +#endif +- (void)MAYBE_testBrowsingPostEntryWithKeyboard { // Create map of canned responses and set up the test HTML server. std::map<GURL, std::string> responses; const GURL URL =
diff --git a/ios/chrome/common/app_group/BUILD.gn b/ios/chrome/common/app_group/BUILD.gn index 10c0883..2f482d83 100644 --- a/ios/chrome/common/app_group/BUILD.gn +++ b/ios/chrome/common/app_group/BUILD.gn
@@ -36,6 +36,7 @@ } source_set("main_app") { + configs += [ "//build/config/compiler:enable_arc" ] sources = [ "app_group_metrics_mainapp.h", "app_group_metrics_mainapp.mm",
diff --git a/ios/chrome/common/app_group/app_group_metrics_mainapp.h b/ios/chrome/common/app_group/app_group_metrics_mainapp.h index af693f27..5115bf03 100644 --- a/ios/chrome/common/app_group/app_group_metrics_mainapp.h +++ b/ios/chrome/common/app_group/app_group_metrics_mainapp.h
@@ -8,7 +8,6 @@ #import <Foundation/Foundation.h> #include <stdint.h> -#include "base/mac/scoped_block.h" #include "ios/chrome/common/app_group/app_group_constants.h" namespace app_group { @@ -20,8 +19,7 @@ // Iterates through the extensions pending logs and deletes them. // Calls |callback| on each log before deleting. -void ProcessPendingLogs( - const base::mac::ScopedBlock<ProceduralBlockWithData>& callback); +void ProcessPendingLogs(ProceduralBlockWithData callback); // Enables the metrics collecting in extensions. The extensions will // use |clientID| as client ID, and |brandCode| as brand code in the logs.
diff --git a/ios/chrome/common/app_group/app_group_metrics_mainapp.mm b/ios/chrome/common/app_group/app_group_metrics_mainapp.mm index 3e32438..b33cfec0 100644 --- a/ios/chrome/common/app_group/app_group_metrics_mainapp.mm +++ b/ios/chrome/common/app_group/app_group_metrics_mainapp.mm
@@ -7,16 +7,18 @@ #include <stdint.h> #include "base/logging.h" -#include "base/mac/scoped_nsobject.h" #include "ios/chrome/common/app_group/app_group_constants.h" #include "ios/chrome/common/app_group/app_group_metrics.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + namespace app_group { namespace main_app { -void ProcessPendingLogs( - const base::mac::ScopedBlock<ProceduralBlockWithData>& callback) { +void ProcessPendingLogs(ProceduralBlockWithData callback) { NSFileManager* file_manager = [NSFileManager defaultManager]; NSURL* store_url = [file_manager containerURLForSecurityApplicationGroupIdentifier:ApplicationGroup()]; @@ -34,7 +36,7 @@ [log_dir_url URLByAppendingPathComponent:pending_log isDirectory:NO]; if (callback) { NSData* log_content = [file_manager contentsAtPath:[file_url path]]; - callback.get()(log_content); + callback(log_content); } [file_manager removeItemAtURL:file_url error:nil]; } @@ -45,8 +47,8 @@ NSString* brand_code, int64_t install_date, int64_t enable_metrics_date) { - base::scoped_nsobject<NSUserDefaults> shared_defaults( - [[NSUserDefaults alloc] initWithSuiteName:ApplicationGroup()]); + NSUserDefaults* shared_defaults = + [[NSUserDefaults alloc] initWithSuiteName:ApplicationGroup()]; [shared_defaults setObject:client_id forKey:@(kChromeAppClientID)]; [shared_defaults @@ -60,8 +62,8 @@ } void DisableMetrics() { - base::scoped_nsobject<NSUserDefaults> shared_defaults( - [[NSUserDefaults alloc] initWithSuiteName:ApplicationGroup()]); + NSUserDefaults* shared_defaults = + [[NSUserDefaults alloc] initWithSuiteName:ApplicationGroup()]; [shared_defaults removeObjectForKey:@(kChromeAppClientID)]; }
diff --git a/ios/net/crn_http_protocol_handler.mm b/ios/net/crn_http_protocol_handler.mm index bb9ac3b..c067305 100644 --- a/ios/net/crn_http_protocol_handler.mm +++ b/ios/net/crn_http_protocol_handler.mm
@@ -663,11 +663,6 @@ if (tracker_) { // Set up any clients that can operate regardless of the request PushClients(tracker_->ClientsHandlingAnyRequest()); - } else { - // There was no request_group_id, so the request was from something like a - // data: or file: URL. - // Attach any global clients to the request. - PushClients(RequestTracker::GlobalClientsHandlingAnyRequest()); } // Now that all of the network clients are set up, if there was an error with
diff --git a/ios/net/request_tracker.h b/ios/net/request_tracker.h index 50fcc517..117b412 100644 --- a/ios/net/request_tracker.h +++ b/ios/net/request_tracker.h
@@ -78,14 +78,6 @@ // this tracker. void AddNetworkClientFactory(CRNForwardingNetworkClientFactory* factory); - // Registers a factory with the class that will be added to all trackers. - // Requests without associated trackers can add clients from these factories - // using GlobalClientsHandlingAnyRequest(). - // Only |-clientHandlingAnyRequest| will be called on |factory|, the other - // methods are not supported. - static void AddGlobalNetworkClientFactory( - CRNForwardingNetworkClientFactory* factory); - // Gets the request context associated with the tracker. virtual URLRequestContext* GetRequestContext() = 0; @@ -95,10 +87,6 @@ // may be empty. The caller is responsible for taking ownership of the clients // in the array. - // Static method that returns clients that can handle any request, for use - // in cases where a request isn't associated with any request_tracker. - static NSArray* GlobalClientsHandlingAnyRequest(); - // Returns clients that can handle any request. NSArray* ClientsHandlingAnyRequest(); // Returns clients that can handle |request|.
diff --git a/ios/net/request_tracker.mm b/ios/net/request_tracker.mm index f72921a3..85dce7f 100644 --- a/ios/net/request_tracker.mm +++ b/ios/net/request_tracker.mm
@@ -19,56 +19,6 @@ // Reference to the single instance of the RequestTrackerFactory. RequestTracker::RequestTrackerFactory* g_request_tracker_factory = nullptr; -// Array of network client factories that should be added to any new request -// tracker. -class GlobalNetworkClientFactories { - public: - static GlobalNetworkClientFactories* GetInstance() { - if (!g_global_network_client_factories) - g_global_network_client_factories = new GlobalNetworkClientFactories; - return g_global_network_client_factories; - } - - // Gets the factories. - NSArray* GetFactories() { - DCHECK(thread_checker_.CalledOnValidThread()); - return factories_.get(); - } - - // Adds a factory. - void AddFactory(CRNForwardingNetworkClientFactory* factory) { - DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK_EQ(NSNotFound, - static_cast<NSInteger>([factories_ indexOfObject:factory])); - DCHECK(!IsSelectorOverriden(factory, @selector(clientHandlingRequest:))); - DCHECK(!IsSelectorOverriden(factory, - @selector(clientHandlingResponse:request:))); - DCHECK(!IsSelectorOverriden( - factory, @selector(clientHandlingRedirect:url:response:))); - [factories_ addObject:factory]; - } - - // Returns true if |factory| re-implements |selector|. - // Only used for debugging. - bool IsSelectorOverriden(CRNForwardingNetworkClientFactory* factory, - SEL selector) { - return - [factory methodForSelector:selector] != - [CRNForwardingNetworkClientFactory instanceMethodForSelector:selector]; - } - - private: - GlobalNetworkClientFactories() : factories_([[NSMutableArray alloc] init]) {} - - base::scoped_nsobject<NSMutableArray> factories_; - base::ThreadChecker thread_checker_; - - static GlobalNetworkClientFactories* g_global_network_client_factories; -}; - -GlobalNetworkClientFactories* - GlobalNetworkClientFactories::g_global_network_client_factories = nullptr; - } // namespace RequestTracker::RequestTrackerFactory::~RequestTrackerFactory() { @@ -108,12 +58,6 @@ } } -// static -void RequestTracker::AddGlobalNetworkClientFactory( - CRNForwardingNetworkClientFactory* factory) { - GlobalNetworkClientFactories::GetInstance()->AddFactory(factory); -} - RequestTracker::RequestTracker() : client_factories_([[NSMutableArray alloc] init]), initialized_(false), @@ -139,22 +83,6 @@ DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(!initialized_); initialized_ = true; - for (CRNForwardingNetworkClientFactory* factory in - GlobalNetworkClientFactories::GetInstance()->GetFactories()) { - AddNetworkClientFactory(factory); - } -} - -// static -NSArray* RequestTracker::GlobalClientsHandlingAnyRequest() { - NSMutableArray* applicable_clients = [NSMutableArray array]; - for (CRNForwardingNetworkClientFactory* factory in - GlobalNetworkClientFactories::GetInstance()->GetFactories()) { - CRNForwardingNetworkClient* client = [factory clientHandlingAnyRequest]; - if (client) - [applicable_clients addObject:client]; - } - return applicable_clients; } NSArray* RequestTracker::ClientsHandlingAnyRequest() {
diff --git a/ios/public/provider/chrome/browser/chrome_browser_provider.h b/ios/public/provider/chrome/browser/chrome_browser_provider.h index 7547b6b7..38aef4f0 100644 --- a/ios/public/provider/chrome/browser/chrome_browser_provider.h +++ b/ios/public/provider/chrome/browser/chrome_browser_provider.h
@@ -96,17 +96,11 @@ // Initializes the cast service. Should be called soon after the given // |main_tab_model| is created. - // TODO(rohitrao): Change from |id| to |TabModel*| once TabModel is moved into - // the Chromium tree. - virtual void InitializeCastService(id main_tab_model) const; virtual void InitializeCastService(TabModel* main_tab_model) const; // Attaches any embedder-specific tab helpers to the given |web_state|. The // owning |tab| is included for helpers that need access to information that // is not yet available through web::WebState. - // TODO(rohitrao): Change from |id| to |Tab*| once Tab is moved into the - // Chromium tree. - virtual void AttachTabHelpers(web::WebState* web_state, id tab) const; virtual void AttachTabHelpers(web::WebState* web_state, Tab* tab) const; // Returns whether safe browsing is enabled. See the comment on
diff --git a/ios/public/provider/chrome/browser/chrome_browser_provider.mm b/ios/public/provider/chrome/browser/chrome_browser_provider.mm index 9e1d496..1c9a88d 100644 --- a/ios/public/provider/chrome/browser/chrome_browser_provider.mm +++ b/ios/public/provider/chrome/browser/chrome_browser_provider.mm
@@ -74,24 +74,11 @@ return nil; } -void ChromeBrowserProvider::InitializeCastService(id main_tab_model) const {} - void ChromeBrowserProvider::InitializeCastService( - TabModel* main_tab_model) const { - // Invokes the version taking an "id" as this is the only version currently - // overridden by the downstream provider. - InitializeCastService(static_cast<id>(main_tab_model)); -} + TabModel* main_tab_model) const {} void ChromeBrowserProvider::AttachTabHelpers(web::WebState* web_state, - id tab) const {} - -void ChromeBrowserProvider::AttachTabHelpers(web::WebState* web_state, - Tab* tab) const { - // Invokes the version taking an "id" as this is the only version currently - // overridden by the downstream provider. - AttachTabHelpers(web_state, static_cast<id>(tab)); -} + Tab* tab) const {} bool ChromeBrowserProvider::IsSafeBrowsingEnabled( const base::Closure& on_update_callback) {
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 30a468b..45b5967dc 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -829,25 +829,6 @@ ] } ], - "HttpFormWarning": [ - { - "platforms": [ - "android", - "chromeos", - "linux", - "mac", - "win" - ], - "experiments": [ - { - "name": "Enabled", - "enable_features": [ - "HttpFormWarning" - ] - } - ] - } - ], "IOSurfaceClearYosemite": [ { "platforms": [
diff --git a/third_party/WebKit/LayoutTests/LeakExpectations b/third_party/WebKit/LayoutTests/LeakExpectations index 2a1c0fe..c70b349 100644 --- a/third_party/WebKit/LayoutTests/LeakExpectations +++ b/third_party/WebKit/LayoutTests/LeakExpectations
@@ -98,6 +98,8 @@ crbug.com/506754 virtual/mojo-loading/http/tests/serviceworker/chromium/window-close-during-registration.html [ Leak ] crbug.com/506754 virtual/service-worker-navigation-preload/http/tests/serviceworker/chromium/resolve-after-window-close.html [ Leak ] crbug.com/506754 virtual/service-worker-navigation-preload/http/tests/serviceworker/chromium/window-close-during-registration.html [ Leak ] +crbug.com/506754 virtual/service-worker-navigation-preload-disabled/http/tests/serviceworker/chromium/resolve-after-window-close.html [ Leak ] +crbug.com/506754 virtual/service-worker-navigation-preload-disabled/http/tests/serviceworker/chromium/window-close-during-registration.html [ Leak ] # ----------------------------------------------------------------- # Untriaged but known leaks of ActiveDOMObject (Web Audio).
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index 2499915..5f431ab 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -102,7 +102,6 @@ crbug.com/632000 [ Win ] images/paint-subrect-grid.html [ Pass Failure ] crbug.com/636271 [ Mac10.10 ] paint/invalidation/resize-iframe-text.html [ Pass Failure ] -crbug.com/636271 [ Mac10.10 ] virtual/stable/paint/invalidation/resize-iframe-text.html [ Pass Failure ] crbug.com/639147 svg/wicd/test-rightsizing-b.xhtml [ Failure Pass ] @@ -2322,8 +2321,8 @@ crbug.com/678499 http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-script-preload-allowed.php [ Failure Pass ] crbug.com/678499 virtual/mojo-loading/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-script-preload-allowed.php [ Failure Pass ] -crbug.com/681391 virtual/gpu-rasterization/images/imagemap-circle-focus-ring.html [ NeedsManualRebaseline ] -crbug.com/681391 virtual/gpu-rasterization/images/imagemap-overflowing-circle-focus-ring.html [ NeedsManualRebaseline ] +crbug.com/681391 virtual/gpu-rasterization/images/imagemap-circle-focus-ring.html [ NeedsRebaseline ] +crbug.com/681391 virtual/gpu-rasterization/images/imagemap-overflowing-circle-focus-ring.html [ NeedsRebaseline ] crbug.com/680043 sensor/ambient-light-sensor.html [ Pass Failure ]
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/dangling-markup/resources/helper.js b/third_party/WebKit/LayoutTests/http/tests/security/dangling-markup/resources/helper.js index 7d5ad6d..100bcba 100644 --- a/third_party/WebKit/LayoutTests/http/tests/security/dangling-markup/resources/helper.js +++ b/third_party/WebKit/LayoutTests/http/tests/security/dangling-markup/resources/helper.js
@@ -4,6 +4,16 @@ })); } +function appendFrameAndGetElement(test, frame) { + return new Promise((resolve, reject) => { + frame.onload = test.step_func(_ => { + frame.onload = null; + resolve(frame.contentDocument.querySelector('#dangling')); + }); + document.body.appendChild(frame); + }); +} + function appendAndSubmit(test, frame) { return new Promise((resolve, reject) => { frame.onload = test.step_func(_ => { @@ -30,6 +40,22 @@ })); } +function assert_img_loaded(test, frame) { + appendFrameAndGetElement(test, frame) + .then(test.step_func_done(img => { + assert_equals(img.naturalHeight, 103, "Height"); + assert_equals(img.naturalWidth, 76, "Width"); + })); +} + +function assert_img_not_loaded(test, frame) { + appendFrameAndGetElement(test, frame) + .then(test.step_func_done(img => { + assert_equals(img.naturalHeight, 0, "Height"); + assert_equals(img.naturalWidth, 0, "Width"); + })); +} + function createFrame(markup) { var i = document.createElement('iframe'); i.srcdoc = `${markup}sekrit`;
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/dangling-markup/src-attribute.html b/third_party/WebKit/LayoutTests/http/tests/security/dangling-markup/src-attribute.html new file mode 100644 index 0000000..7c3639e --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/security/dangling-markup/src-attribute.html
@@ -0,0 +1,76 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="./resources/helper.js"></script> +<body> +<script> + // We're injecting markup via `srcdoc` so, confusingly, we need to + // entity-escape the "raw" content, and double-escape the "escaped" + // content. + var rawBrace = "<"; + var escapedBrace = "&lt;"; + var rawNewline = " "; + var escapedNewline = "&#10;"; + + var abeSizedPng = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEwAAABnAQMAAACQMjadAAAAA1BMVEX///+nxBvIAAAAEUlEQVQ4y2MYBaNgFIwCegAABG0AAd5G4RkAAAAASUVORK5CYII="; + var abeSizedPngWithNewline = abeSizedPng.replace("i", "i\n"); + + var should_block = [ + `<img id="dangling" src="http://127.0.0.1:8000/security/resources/abe.png?img=a${rawNewline}b${rawBrace}c">`, + ` + <img id="dangling" src="http://127.0.0.1:8000/security/resources/abe.png?img=a + b${rawBrace}c + "> + `, + ]; + + should_block.forEach(markup => { + async_test(t => { + var i = createFrame(`${markup}`); + assert_img_not_loaded(t, i); + }, markup.replace(/[\n\r]/g, '')); + }); + + var should_load = [ + + // `data:` and `javascript:` URLs don't check the content: + `<img id="dangling" src="${abeSizedPngWithNewline}">`, + + // Just one or the other isn't enough: + `<img id="dangling" src="http://127.0.0.1:8000/security/resources/abe.png?data=a${rawNewline}b">`, + `<img id="dangling" src="http://127.0.0.1:8000/security/resources/abe.png?img=a${rawBrace}b">`, + + // Entity-escaped characters don't trigger blocking: + `<img id="dangling" src="http://127.0.0.1:8000/security/resources/abe.png?data=a${escapedNewline}b">`, + `<img id="dangling" src="http://127.0.0.1:8000/security/resources/abe.png?img=a${escapedBrace}b">`, + `<img id="dangling" src="http://127.0.0.1:8000/security/resources/abe.png?img=a${escapedNewline}b${escapedBrace}c">`, + + // Leading and trailing whitespace is stripped: + ` + <img id="dangling" src=" + http://127.0.0.1:8000/security/resources/abe.png + "> + <input type=hidden name=csrf value=sekrit> + `, + ` + <img id="dangling" src=" + http://127.0.0.1:8000/security/resources/abe.png?img=${escapedBrace} + "> + <input type=hidden name=csrf value=sekrit> + `, + ` + <img id="dangling" src=" + http://127.0.0.1:8000/security/resources/abe.png?img=${escapedNewline} + "> + <input type=hidden name=csrf value=sekrit> + `, + ]; + + should_load.forEach(markup => { + async_test(t => { + var i = createFrame(`${markup} <element attr="" another=''>`); + assert_img_loaded(t, i); + }, markup.replace(/[\n\r]/g, '')); + }); +</script> +
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/stable/paint/invalidation/resize-iframe-text-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/stable/paint/invalidation/resize-iframe-text-expected.png new file mode 100644 index 0000000..3ff17ff --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/stable/paint/invalidation/resize-iframe-text-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/stable/paint/invalidation/resize-iframe-text-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/stable/paint/invalidation/resize-iframe-text-expected.txt index f2b69df4..f91329c 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/stable/paint/invalidation/resize-iframe-text-expected.txt +++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/stable/paint/invalidation/resize-iframe-text-expected.txt
@@ -2,23 +2,33 @@ "layers": [ { "name": "LayoutView #document", - "bounds": [800, 681], + "bounds": [800, 745], "contentsOpaque": true, "drawsContent": true, "paintInvalidations": [ { "object": "LayoutIFrame (positioned) IFRAME", - "rect": [0, 0, 800, 681], + "rect": [0, 0, 800, 745], "reason": "forced by layout" }, { "object": "LayoutView #document", - "rect": [0, 600, 800, 81], + "rect": [0, 600, 800, 145], "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 800, 34], + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow HTML", + "rect": [0, 0, 785, 745], + "reason": "forced by layout" + }, + { "object": "LayoutView #document", - "rect": [0, 600, 785, 81], + "rect": [0, 600, 785, 145], "reason": "incremental" }, { @@ -27,13 +37,18 @@ "reason": "forced by layout" }, { + "object": "LayoutBlockFlow H1", + "rect": [8, 700, 600, 37], + "reason": "became visible" + }, + { "object": "LayoutText #text", "rect": [8, 8, 346, 18], "reason": "forced by layout" }, { "object": "LayoutView #document", - "rect": [785, 0, 15, 681], + "rect": [785, 0, 15, 745], "reason": "scroll" }, { @@ -50,6 +65,10 @@ "reason": "incremental" }, { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { "object": "LayoutBlockFlow BODY", "reason": "forced by layout" }, @@ -84,6 +103,18 @@ { "object": "LayoutView #document", "reason": "incremental" + }, + { + "object": "LayoutBlockFlow HTML", + "reason": "forced by layout" + }, + { + "object": "LayoutBlockFlow H1", + "reason": "became visible" + }, + { + "object": "RootInlineBox", + "reason": "became visible" } ] }
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp index 8dd0107..150f6e08 100644 --- a/third_party/WebKit/Source/core/dom/Document.cpp +++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -2487,9 +2487,8 @@ frameHost()->eventHandlerRegistry().documentDetached(*this); - // Since |Document| class has multiple |LifecycleNotifier| as base class, - // we need to have |static_cast<SynchronousMutationNotifier>| here. - static_cast<SynchronousMutationNotifier*>(this)->notifyContextDestroyed(); + // Signal destruction to mutation observers. + SynchronousMutationNotifier::notifyContextDestroyed(); m_frame->selection().documentDetached(*this); // If this Document is associated with a live DocumentLoader, the @@ -4947,17 +4946,31 @@ KURL Document::completeURL(const String& url) const { String trimmed = url.stripWhiteSpace(); + KURL completed = completeURLWithOverride(url, m_baseURL); + bool newline = trimmed.contains('\n') || trimmed.contains('\r'); - bool brace = trimmed.contains('<'); - if (newline) - UseCounter::count(*this, UseCounter::DocumentCompleteURLContainingNewline); - if (brace) { - UseCounter::count(*this, - UseCounter::DocumentCompleteURLContainingOpenBrace); - } - if (newline && brace) { + bool lessThan = trimmed.contains('<'); + if ((newline || lessThan) && completed.protocolIsInHTTPFamily()) { + if (newline) { + UseCounter::count(*this, + UseCounter::DocumentCompleteURLHTTPContainingNewline); + } + if (lessThan) { + UseCounter::count(*this, + UseCounter::DocumentCompleteURLHTTPContainingLessThan); + } + if (newline && lessThan) { + UseCounter::count( + *this, + UseCounter::DocumentCompleteURLHTTPContainingNewlineAndLessThan); + + if (RuntimeEnabledFeatures::restrictCompleteURLCharacterSetEnabled()) + return KURL(); + } + } else if (newline || lessThan) { UseCounter::count( - *this, UseCounter::DocumentCompleteURLContainingNewlineAndOpenBrace); + *this, + UseCounter::DocumentCompleteURLNonHTTPContainingNewlineOrLessThan); } return completeURLWithOverride(url, m_baseURL); }
diff --git a/third_party/WebKit/Source/core/dom/IdleDeadlineTest.cpp b/third_party/WebKit/Source/core/dom/IdleDeadlineTest.cpp index 6d6e8af3..64c7232 100644 --- a/third_party/WebKit/Source/core/dom/IdleDeadlineTest.cpp +++ b/third_party/WebKit/Source/core/dom/IdleDeadlineTest.cpp
@@ -12,11 +12,29 @@ namespace blink { namespace { -class MockScheduler final : public TestingPlatformMockScheduler { +class MockScheduler final : public WebScheduler { public: MockScheduler() {} ~MockScheduler() override {} + + // WebScheduler implementation: + WebTaskRunner* loadingTaskRunner() override { return nullptr; } + WebTaskRunner* timerTaskRunner() override { return nullptr; } + void shutdown() override {} bool shouldYieldForHighPriorityWork() override { return true; } + bool canExceedIdleDeadlineIfRequired() override { return false; } + void postIdleTask(const WebTraceLocation&, WebThread::IdleTask*) override {} + void postNonNestableIdleTask(const WebTraceLocation&, + WebThread::IdleTask*) override {} + std::unique_ptr<WebViewScheduler> createWebViewScheduler( + InterventionReporter*, + WebViewScheduler::WebViewSchedulerSettings*) override { + return nullptr; + } + void suspendTimerQueue() override {} + void resumeTimerQueue() override {} + void addPendingNavigation(WebScheduler::NavigatingFrameType) override {} + void removePendingNavigation(WebScheduler::NavigatingFrameType) override {} private: DISALLOW_COPY_AND_ASSIGN(MockScheduler);
diff --git a/third_party/WebKit/Source/core/fetch/MemoryCacheCorrectnessTest.cpp b/third_party/WebKit/Source/core/fetch/MemoryCacheCorrectnessTest.cpp index 5da4703..04c63252 100644 --- a/third_party/WebKit/Source/core/fetch/MemoryCacheCorrectnessTest.cpp +++ b/third_party/WebKit/Source/core/fetch/MemoryCacheCorrectnessTest.cpp
@@ -232,7 +232,7 @@ EXPECT_NE(fresh200Nocache, fetched); } -TEST_F(MemoryCacheCorrectnessTest, RequestWithNoCahe) { +TEST_F(MemoryCacheCorrectnessTest, RequestWithNoCache) { ResourceRequest noCacheRequest; noCacheRequest.setHTTPHeaderField(HTTPNames::Cache_Control, "no-cache"); Resource* noCacheResource = resourceFromResourceRequest(noCacheRequest);
diff --git a/third_party/WebKit/Source/core/fetch/RawResourceTest.cpp b/third_party/WebKit/Source/core/fetch/RawResourceTest.cpp index 501cf024..acc22a82 100644 --- a/third_party/WebKit/Source/core/fetch/RawResourceTest.cpp +++ b/third_party/WebKit/Source/core/fetch/RawResourceTest.cpp
@@ -146,24 +146,26 @@ public: AddingClient(DummyClient* client, Resource* resource) - : m_dummyClient(client), - m_resource(resource), - m_removeClientTimer(this, &AddingClient::removeClient) {} + : m_dummyClient(client), m_resource(resource) {} ~AddingClient() override {} // ResourceClient implementation. void notifyFinished(Resource* resource) override { // First schedule an asynchronous task to remove the client. - // We do not expect the client to be called. - m_removeClientTimer.startOneShot(0, BLINK_FROM_HERE); + // We do not expect a client to be called if the client is removed before + // a callback invocation task queued inside addClient() is scheduled. + Platform::current() + ->currentThread() + ->scheduler() + ->loadingTaskRunner() + ->postTask(BLINK_FROM_HERE, WTF::bind(&AddingClient::removeClient, + wrapPersistent(this))); resource->addClient(m_dummyClient); } String debugName() const override { return "AddingClient"; } - void removeClient(TimerBase* timer) { - m_resource->removeClient(m_dummyClient); - } + void removeClient() { m_resource->removeClient(m_dummyClient); } DEFINE_INLINE_VIRTUAL_TRACE() { visitor->trace(m_dummyClient); @@ -174,7 +176,6 @@ private: Member<DummyClient> m_dummyClient; Member<Resource> m_resource; - Timer<AddingClient> m_removeClientTimer; }; TEST(RawResourceTest, RevalidationSucceeded) {
diff --git a/third_party/WebKit/Source/core/frame/Frame.cpp b/third_party/WebKit/Source/core/frame/Frame.cpp index 6f7a7402..d259c5d 100644 --- a/third_party/WebKit/Source/core/frame/Frame.cpp +++ b/third_party/WebKit/Source/core/frame/Frame.cpp
@@ -82,7 +82,13 @@ void Frame::disconnectOwnerElement() { if (m_owner) { - m_owner->clearContentFrame(); + // Ocassionally, provisional frames need to be detached, but it shouldn't + // affect the frame tree structure. Make sure the frame owner's content + // frame actually refers to this frame before clearing it. + // TODO(dcheng): https://crbug.com/578349 tracks the cleanup for this once + // it's no longer needed. + if (m_owner->contentFrame() == this) + m_owner->clearContentFrame(); m_owner = nullptr; } }
diff --git a/third_party/WebKit/Source/core/frame/FrameOwner.h b/third_party/WebKit/Source/core/frame/FrameOwner.h index 352d8ed4f..6149324 100644 --- a/third_party/WebKit/Source/core/frame/FrameOwner.h +++ b/third_party/WebKit/Source/core/frame/FrameOwner.h
@@ -27,6 +27,7 @@ virtual bool isLocal() const = 0; virtual bool isRemote() const = 0; + virtual Frame* contentFrame() const = 0; virtual void setContentFrame(Frame&) = 0; virtual void clearContentFrame() = 0; @@ -47,6 +48,9 @@ virtual const WebVector<WebPermissionType>& delegatedPermissions() const = 0; }; +// TODO(dcheng): This class is an internal implementation detail of provisional +// frames. Move this into WebLocalFrameImpl.cpp and remove existing dependencies +// on it. class CORE_EXPORT DummyFrameOwner : public GarbageCollectedFinalized<DummyFrameOwner>, public FrameOwner { @@ -58,6 +62,7 @@ DEFINE_INLINE_VIRTUAL_TRACE() { FrameOwner::trace(visitor); } // FrameOwner overrides: + Frame* contentFrame() const override { return nullptr; } void setContentFrame(Frame&) override {} void clearContentFrame() override {} SandboxFlags getSandboxFlags() const override { return SandboxNone; }
diff --git a/third_party/WebKit/Source/core/frame/UseCounter.h b/third_party/WebKit/Source/core/frame/UseCounter.h index dd8b614..2fa053d0 100644 --- a/third_party/WebKit/Source/core/frame/UseCounter.h +++ b/third_party/WebKit/Source/core/frame/UseCounter.h
@@ -1435,9 +1435,10 @@ V8AssigmentExpressionLHSIsCallInStrict = 1765, V8PromiseConstructorReturnedUndefined = 1766, FormSubmittedWithUnclosedFormControl = 1767, - DocumentCompleteURLContainingNewline = 1768, - DocumentCompleteURLContainingOpenBrace = 1769, - DocumentCompleteURLContainingNewlineAndOpenBrace = 1770, + DocumentCompleteURLHTTPContainingNewline = 1768, + DocumentCompleteURLHTTPContainingLessThan = 1769, + DocumentCompleteURLHTTPContainingNewlineAndLessThan = 1770, + DocumentCompleteURLNonHTTPContainingNewlineOrLessThan = 1771, // 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/HTMLFrameElementBase.h b/third_party/WebKit/Source/core/html/HTMLFrameElementBase.h index 2369fe5..b478452 100644 --- a/third_party/WebKit/Source/core/html/HTMLFrameElementBase.h +++ b/third_party/WebKit/Source/core/html/HTMLFrameElementBase.h
@@ -34,9 +34,9 @@ bool canContainRangeEndPoint() const final { return false; } // FrameOwner overrides: - ScrollbarMode scrollingMode() const override { return m_scrollingMode; } - int marginWidth() const override { return m_marginWidth; } - int marginHeight() const override { return m_marginHeight; } + ScrollbarMode scrollingMode() const final { return m_scrollingMode; } + int marginWidth() const final { return m_marginWidth; } + int marginHeight() const final { return m_marginHeight; } protected: HTMLFrameElementBase(const QualifiedName&, Document&);
diff --git a/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.h b/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.h index 6e9a4b3..bd608f31 100644 --- a/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.h +++ b/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.h
@@ -44,7 +44,6 @@ public: ~HTMLFrameOwnerElement() override; - Frame* contentFrame() const { return m_contentFrame; } DOMWindow* contentWindow() const; Document* contentDocument() const; @@ -76,10 +75,11 @@ }; // FrameOwner overrides: - void setContentFrame(Frame&) override; - void clearContentFrame() override; - void dispatchLoad() override; - SandboxFlags getSandboxFlags() const override { return m_sandboxFlags; } + Frame* contentFrame() const final { return m_contentFrame; } + void setContentFrame(Frame&) final; + void clearContentFrame() final; + void dispatchLoad() final; + SandboxFlags getSandboxFlags() const final { return m_sandboxFlags; } bool canRenderFallbackContent() const override { return false; } void renderFallbackContent() override {} ScrollbarMode scrollingMode() const override { return ScrollbarAuto; } @@ -106,8 +106,8 @@ private: // Intentionally private to prevent redundant checks when the type is // already HTMLFrameOwnerElement. - bool isLocal() const override { return true; } - bool isRemote() const override { return false; } + bool isLocal() const final { return true; } + bool isRemote() const final { return false; } bool isFrameOwnerElement() const final { return true; }
diff --git a/third_party/WebKit/Source/core/html/HTMLIFrameElement.h b/third_party/WebKit/Source/core/html/HTMLIFrameElement.h index c49204a..51ae060 100644 --- a/third_party/WebKit/Source/core/html/HTMLIFrameElement.h +++ b/third_party/WebKit/Source/core/html/HTMLIFrameElement.h
@@ -73,11 +73,10 @@ ReferrerPolicy referrerPolicyAttribute() override; + // FrameOwner overrides: bool allowFullscreen() const override { return m_allowFullscreen; } bool allowPaymentRequest() const override { return m_allowPaymentRequest; } - AtomicString csp() const override { return m_csp; } - const WebVector<WebPermissionType>& delegatedPermissions() const override { return m_delegatedPermissions; }
diff --git a/third_party/WebKit/Source/core/html/forms/SearchInputType.cpp b/third_party/WebKit/Source/core/html/forms/SearchInputType.cpp index 7ec269b6..97b1f0f7 100644 --- a/third_party/WebKit/Source/core/html/forms/SearchInputType.cpp +++ b/third_party/WebKit/Source/core/html/forms/SearchInputType.cpp
@@ -48,7 +48,10 @@ inline SearchInputType::SearchInputType(HTMLInputElement& element) : BaseTextInputType(element), - m_searchEventTimer(this, &SearchInputType::searchEventTimerFired) {} + m_searchEventTimer( + TaskRunnerHelper::get(TaskType::UserInteraction, &element.document()), + this, + &SearchInputType::searchEventTimerFired) {} InputType* SearchInputType::create(HTMLInputElement& element) { return new SearchInputType(element);
diff --git a/third_party/WebKit/Source/core/html/forms/SearchInputType.h b/third_party/WebKit/Source/core/html/forms/SearchInputType.h index 63fed234..be0efe9 100644 --- a/third_party/WebKit/Source/core/html/forms/SearchInputType.h +++ b/third_party/WebKit/Source/core/html/forms/SearchInputType.h
@@ -59,7 +59,7 @@ void startSearchEventTimer(); void updateCancelButtonVisibility(); - Timer<SearchInputType> m_searchEventTimer; + TaskRunnerTimer<SearchInputType> m_searchEventTimer; }; } // namespace blink
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in index 85aa7103..d30f1f5 100644 --- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in +++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
@@ -286,3 +286,4 @@ PerformancePaintTiming status=test HideNonceContentAttribute status=experimental UnclosedFormControlIsInvalid status=experimental +RestrictCompleteURLCharacterSet status=experimental
diff --git a/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp b/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp index d99808b..bf236c6 100644 --- a/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp +++ b/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp
@@ -131,9 +131,6 @@ return nullptr; } -TestingPlatformMockScheduler::TestingPlatformMockScheduler() {} -TestingPlatformMockScheduler::~TestingPlatformMockScheduler() {} - TestingPlatformSupport::TestingPlatformSupport() : TestingPlatformSupport(TestingPlatformSupport::Config()) {}
diff --git a/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.h b/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.h index cf90b81..1f816639 100644 --- a/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.h +++ b/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.h
@@ -84,33 +84,6 @@ bool isLeftSideVerticalScrollbar) override; }; -class TestingPlatformMockScheduler : public WebScheduler { - WTF_MAKE_NONCOPYABLE(TestingPlatformMockScheduler); - - public: - TestingPlatformMockScheduler(); - ~TestingPlatformMockScheduler() override; - - // WebScheduler implementation: - WebTaskRunner* loadingTaskRunner() override { return nullptr; } - WebTaskRunner* timerTaskRunner() override { return nullptr; } - void shutdown() override {} - bool shouldYieldForHighPriorityWork() override { return false; } - bool canExceedIdleDeadlineIfRequired() override { return false; } - void postIdleTask(const WebTraceLocation&, WebThread::IdleTask*) override {} - void postNonNestableIdleTask(const WebTraceLocation&, - WebThread::IdleTask*) override {} - std::unique_ptr<WebViewScheduler> createWebViewScheduler( - InterventionReporter*, - WebViewScheduler::WebViewSchedulerSettings*) override { - return nullptr; - } - void suspendTimerQueue() override {} - void resumeTimerQueue() override {} - void addPendingNavigation(WebScheduler::NavigatingFrameType) override {} - void removePendingNavigation(WebScheduler::NavigatingFrameType) override {} -}; - // A base class to override Platform methods for testing. You can override the // behavior by subclassing TestingPlatformSupport or using // ScopedTestingPlatformSupport (see below).
diff --git a/third_party/WebKit/Source/web/RemoteFrameOwner.h b/third_party/WebKit/Source/web/RemoteFrameOwner.h index 25d3977..5cce8db 100644 --- a/third_party/WebKit/Source/web/RemoteFrameOwner.h +++ b/third_party/WebKit/Source/web/RemoteFrameOwner.h
@@ -29,6 +29,7 @@ } // FrameOwner overrides: + Frame* contentFrame() const override { return m_frame.get(); } void setContentFrame(Frame&) override; void clearContentFrame() override; SandboxFlags getSandboxFlags() const override { return m_sandboxFlags; }
diff --git a/third_party/WebKit/Source/web/tests/FrameTestHelpers.cpp b/third_party/WebKit/Source/web/tests/FrameTestHelpers.cpp index a6ea7004..f249400a 100644 --- a/third_party/WebKit/Source/web/tests/FrameTestHelpers.cpp +++ b/third_party/WebKit/Source/web/tests/FrameTestHelpers.cpp
@@ -289,6 +289,26 @@ TestWebFrameClient::TestWebFrameClient() {} +// TODO(dcheng): https://crbug.com/578349 tracks the removal of this code. This +// override exists only to handle the confusing provisional frame case. +void TestWebFrameClient::frameDetached(WebLocalFrame* frame, DetachType type) { + if (type == DetachType::Remove && frame->parent()) { + // Since this may be detaching a provisional frame, make sure |child| is + // actually linked into the frame tree (i.e. it is present in its parent + // node's children list) before trying to remove it as a child. + for (WebFrame* child = frame->parent()->firstChild(); child; + child = child->nextSibling()) { + if (child == frame) + frame->parent()->removeChild(frame); + } + } + + if (frame->frameWidget()) + frame->frameWidget()->close(); + + frame->close(); +} + WebLocalFrame* TestWebFrameClient::createChildFrame( WebLocalFrame* parent, WebTreeScopeType scope,
diff --git a/third_party/WebKit/Source/web/tests/FrameTestHelpers.h b/third_party/WebKit/Source/web/tests/FrameTestHelpers.h index 35e217c..67c41b3da 100644 --- a/third_party/WebKit/Source/web/tests/FrameTestHelpers.h +++ b/third_party/WebKit/Source/web/tests/FrameTestHelpers.h
@@ -237,6 +237,7 @@ public: TestWebFrameClient(); + void frameDetached(WebLocalFrame*, DetachType) override; WebLocalFrame* createChildFrame(WebLocalFrame* parent, WebTreeScopeType, const WebString& name,
diff --git a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp index e280ce9..853ab22 100644 --- a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp +++ b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
@@ -8729,6 +8729,38 @@ remoteFrame->close(); } +TEST_F(WebFrameSwapTest, DetachProvisionalFrame) { + FrameTestHelpers::TestWebRemoteFrameClient remoteFrameClient; + WebRemoteFrameImpl* remoteFrame = WebRemoteFrameImpl::create( + WebTreeScopeType::Document, &remoteFrameClient); + swapAndVerifyMiddleChildConsistency("local->remote", mainFrame(), + remoteFrame); + + FrameTestHelpers::TestWebFrameClient client; + WebLocalFrameImpl* provisionalFrame = WebLocalFrameImpl::createProvisional( + &client, remoteFrame, WebSandboxFlags::None); + + // The provisional frame should have a local frame owner. + FrameOwner* owner = provisionalFrame->frame()->owner(); + ASSERT_TRUE(owner->isLocal()); + + // But the owner should point to |remoteFrame|, since the new frame is still + // provisional. + EXPECT_EQ(remoteFrame->frame(), owner->contentFrame()); + + // After detaching the provisional frame, the frame owner should still point + // at |remoteFrame|. + provisionalFrame->detach(); + + // The owner should not be affected by detaching the provisional frame, so it + // should still point to |remoteFrame|. + EXPECT_EQ(remoteFrame->frame(), owner->contentFrame()); + + // Manually reset to break WebViewHelper's dependency on the stack allocated + // TestWebFrameClient. + reset(); +} + void WebFrameTest::swapAndVerifySubframeConsistency(const char* const message, WebFrame* oldFrame, WebFrame* newFrame) {
diff --git a/third_party/WebKit/Source/wtf/text/StringImpl.cpp b/third_party/WebKit/Source/wtf/text/StringImpl.cpp index f8b6b7b..6654e30 100644 --- a/third_party/WebKit/Source/wtf/text/StringImpl.cpp +++ b/third_party/WebKit/Source/wtf/text/StringImpl.cpp
@@ -335,7 +335,7 @@ #if DCHECK_IS_ON() std::string StringImpl::asciiForDebugging() const { - CString ascii = String(substring(0, 128)).ascii(); + CString ascii = String(isolatedCopy()->substring(0, 128)).ascii(); return std::string(ascii.data(), ascii.length()); } #endif
diff --git a/third_party/WebKit/public/web/WebLocalFrame.h b/third_party/WebKit/public/web/WebLocalFrame.h index 50f78f2b..f050d49 100644 --- a/third_party/WebKit/public/web/WebLocalFrame.h +++ b/third_party/WebKit/public/web/WebLocalFrame.h
@@ -48,11 +48,23 @@ WebFrameClient*, WebFrame* opener = nullptr); - // Used to create a provisional local frame in prepration for replacing a - // remote frame if the load commits. The returned frame is only partially - // attached to the frame tree: it has the same parent as its potential - // replacee but is invisible to the rest of the frames in the frame tree. - // If the load commits, call swap() to fully attach this frame. + // Used to create a provisional local frame. Currently, it's possible for a + // provisional navigation not to commit (i.e. it might turn into a download), + // but this can only be determined by actually trying to load it. The loading + // process depends on having a corresponding LocalFrame in Blink to hold all + // the pending state. + // + // When a provisional frame is first created, it is only partially attached to + // the frame tree. This means that though a provisional frame might have a + // frame owner, the frame owner's content frame does not point back at the + // provisional frame. Similarly, though a provisional frame may have a parent + // frame pointer, the parent frame's children list will not contain the + // provisional frame. Thus, a provisional frame is invisible to the rest of + // Blink unless the navigation commits and the provisional frame is fully + // attached to the frame tree by calling swap(). + // + // Otherwise, if the load should not commit, call detach() to discard the + // frame. BLINK_EXPORT static WebLocalFrame* createProvisional(WebFrameClient*, WebRemoteFrame*, WebSandboxFlags);
diff --git a/tools/licenses.py b/tools/licenses.py index 9bdc018..45e783e 100755 --- a/tools/licenses.py +++ b/tools/licenses.py
@@ -185,7 +185,7 @@ os.path.join('third_party', 'WebKit'): { "Name": "WebKit", "URL": "http://webkit.org/", - "License": "BSD and GPL v2", + "License": "BSD and LGPL v2 and LGPL v2.1", # Absolute path here is resolved as relative to the source root. "License File": "/third_party/WebKit/LICENSE_FOR_ABOUT_CREDITS", },
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 11f243c..efdf0cbe 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -89107,9 +89107,12 @@ <int value="1765" label="V8AssigmentExpressionLHSIsCallInStrict"/> <int value="1766" label="V8PromiseConstructorReturnedUndefined"/> <int value="1767" label="FormSubmittedWithUnclosedFormControl"/> - <int value="1768" label="DocumentCompleteURLContainingNewline"/> - <int value="1769" label="DocumentCompleteURLContainingOpenBrace"/> - <int value="1770" label="DocumentCompleteURLContainingNewlineAndOpenBrace"/> + <int value="1768" label="DocumentCompleteURLHTTPContainingNewline"/> + <int value="1769" label="DocumentCompleteURLHTTPContainingLessThan"/> + <int value="1770" + label="DocumentCompleteURLHTTPContainingNewlineAndLessThan"/> + <int value="1771" + label="DocumentCompleteURLNonHTTPContainingNewlineOrLessThan"/> </enum> <enum name="FetchRequestMode" type="int">
diff --git a/tools/perf/benchmarks/memory.py b/tools/perf/benchmarks/memory.py index 4eb83b90..b0eafac 100644 --- a/tools/perf/benchmarks/memory.py +++ b/tools/perf/benchmarks/memory.py
@@ -41,6 +41,15 @@ chrome_trace_config.MemoryDumpConfig()) return tbm_options + def SetExtraBrowserOptions(self, options): + # Just before we measure memory we flush the system caches + # unfortunately this doesn't immediately take effect, instead + # the next page run is effected. Due to this the first page run + # has anomalous results. This option causes us to flush caches + # each time before Chrome starts so we effect even the first page + # - avoiding the bug. + options.clear_sytem_cache_for_browser_and_profile_on_start = True + # TODO(bashi): Workaround for http://crbug.com/532075. # @benchmark.Enabled('android') shouldn't be needed.
diff --git a/tools/perf/benchmarks/system_health.py b/tools/perf/benchmarks/system_health.py index 8053919..75a68813 100644 --- a/tools/perf/benchmarks/system_health.py +++ b/tools/perf/benchmarks/system_health.py
@@ -105,6 +105,15 @@ return page_sets.SystemHealthStorySet(platform=self.PLATFORM, take_memory_measurement=True) + def SetExtraBrowserOptions(self, options): + # Just before we measure memory we flush the system caches + # unfortunately this doesn't immediately take effect, instead + # the next story run is effected. Due to this the first story run + # has anomalous results. This option causes us to flush caches + # each time before Chrome starts so we effect even the first story + # - avoiding the bug. + options.clear_sytem_cache_for_browser_and_profile_on_start = True + @classmethod def ShouldTearDownStateAfterEachStoryRun(cls): return True
diff --git a/tools/perf/page_sets/system_health/browsing_stories.py b/tools/perf/page_sets/system_health/browsing_stories.py index b9d1a27..63769da4 100644 --- a/tools/perf/page_sets/system_health/browsing_stories.py +++ b/tools/perf/page_sets/system_health/browsing_stories.py
@@ -22,6 +22,8 @@ IS_SINGLE_PAGE_APP = False ITEM_SELECTOR = NotImplemented + # Defaults to using the body element if not set. + CONTAINER_SELECTOR = None ABSTRACT_STORY = True def _WaitForNavigation(self, action_runner): @@ -33,7 +35,9 @@ self.ITEM_SELECTOR, index) # Only scrolls if element is not currently in viewport. action_runner.WaitForElement(element_function=item_selector) - action_runner.ScrollPageToElement(element_function=item_selector) + action_runner.ScrollPageToElement( + element_function=item_selector, + container_selector=self.CONTAINER_SELECTOR) self._ClickLink(action_runner, item_selector) def _ClickLink(self, action_runner, element_function): @@ -195,6 +199,7 @@ NAME = 'browse:social:twitter' URL = 'https://www.twitter.com/nasa' ITEM_SELECTOR = '.Tweet-text' + CONTAINER_SELECTOR = '.NavigationSheet' SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY
diff --git a/ui/file_manager/file_manager/foreground/js/compiled_resources2.gyp b/ui/file_manager/file_manager/foreground/js/compiled_resources2.gyp index 5324e57..a9f45f16 100644 --- a/ui/file_manager/file_manager/foreground/js/compiled_resources2.gyp +++ b/ui/file_manager/file_manager/foreground/js/compiled_resources2.gyp
@@ -147,10 +147,14 @@ # 'target_name': 'quick_view_controller', # 'includes': ['../../../compile_js2.gypi'], # }, -# { -# 'target_name': 'quick_view_model', -# 'includes': ['../../../compile_js2.gypi'], -# }, + { + 'target_name': 'quick_view_model', + 'dependencies': [ + '../../../../../ui/webui/resources/js/compiled_resources2.gyp:cr', + '../../../../../ui/webui/resources/js/cr/compiled_resources2.gyp:event_target', + ], + 'includes': ['../../../compile_js2.gypi'], + }, # { # 'target_name': 'quick_view_uma', # 'includes': ['../../../compile_js2.gypi'],
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager.js b/ui/file_manager/file_manager/foreground/js/file_manager.js index 667e70aa..f779b039 100644 --- a/ui/file_manager/file_manager/foreground/js/file_manager.js +++ b/ui/file_manager/file_manager/foreground/js/file_manager.js
@@ -548,7 +548,8 @@ assert(this.metadataModel_), assert(this.selectionHandler_), assert(this.ui_.listContainer), assert(this.quickViewModel_), assert(this.taskController_), fileListSelectionModel, - assert(this.quickViewUma_), metadataBoxController, this.dialogType); + assert(this.quickViewUma_), metadataBoxController, this.dialogType, + assert(this.volumeManager_)); if (this.dialogType === DialogType.FULL_PAGE) { importer.importEnabled().then(
diff --git a/ui/file_manager/file_manager/foreground/js/quick_view_controller.js b/ui/file_manager/file_manager/foreground/js/quick_view_controller.js index f659b30..1b8e182b 100644 --- a/ui/file_manager/file_manager/foreground/js/quick_view_controller.js +++ b/ui/file_manager/file_manager/foreground/js/quick_view_controller.js
@@ -15,13 +15,14 @@ * @param {!QuickViewUma} quickViewUma * @param {!MetadataBoxController} metadataBoxController * @param {DialogType} dialogType + * @param {!VolumeManagerWrapper} volumeManager * * @constructor */ function QuickViewController( metadataModel, selectionHandler, listContainer, quickViewModel, taskController, fileListSelectionModel, quickViewUma, - metadataBoxController, dialogType) { + metadataBoxController, dialogType, volumeManager) { /** * @type {FilesQuickView} * @private @@ -83,6 +84,12 @@ this.dialogType_ = dialogType; /** + * @type {!VolumeManagerWrapper} + * @private + */ + this.volumeManager_ = volumeManager; + + /** * Current selection of selectionHandler. * * @type {!Array<!FileEntry>} @@ -102,6 +109,28 @@ } /** + * List of local volume types. + * + * In this context, "local" means that files in that volume are directly + * accessible from the Chrome browser process by Linux VFS paths. In this + * regard, media views are NOT local even though files in media views are + * actually stored in the local disk. + * + * Due to access control of WebView, non-local files can not be previewed + * with Quick View unless thumbnails are provided (which is the case with + * Drive). + * + * @type {!Array<!VolumeManagerCommon.VolumeType>} + * @const + * @private + */ +QuickViewController.LOCAL_VOLUME_TYPES_ = [ + VolumeManagerCommon.VolumeType.ARCHIVE, + VolumeManagerCommon.VolumeType.DOWNLOADS, + VolumeManagerCommon.VolumeType.REMOVABLE, +]; + +/** * Initialize the controller with quick view which will be lazily loaded. * @param {!FilesQuickView} quickView * @private @@ -258,7 +287,7 @@ this.quickViewUma_.onEntryChanged(entry); return Promise .all([ - this.metadataModel_.get([entry], ['thumbnailUrl', 'externalFileUrl']), + this.metadataModel_.get([entry], ['thumbnailUrl']), this.getAvailableTasks_(entry) ]) .then(function(values) { @@ -325,7 +354,13 @@ hasTask: tasks.length > 0, }; - if (item.externalFileUrl) { + var volumeInfo = this.volumeManager_.getVolumeInfo(entry); + var localFile = + volumeInfo && + QuickViewController.LOCAL_VOLUME_TYPES_.indexOf( + volumeInfo.volumeType) >= 0; + + if (!localFile) { switch (type) { case 'image': if (item.thumbnailUrl) { @@ -349,7 +384,7 @@ } break; } - // If the file is in Drive, we ask user to open it with external app. + // We ask user to open it with external app. return Promise.resolve(params); }
diff --git a/ui/login/display_manager.js b/ui/login/display_manager.js index 5ca41e2f..1ec9dec 100644 --- a/ui/login/display_manager.js +++ b/ui/login/display_manager.js
@@ -34,6 +34,8 @@ /** @const */ var SCREEN_DEVICE_DISABLED = 'device-disabled'; /** @const */ var SCREEN_UNRECOVERABLE_CRYPTOHOME_ERROR = 'unrecoverable-cryptohome-error'; +/** @const */ var SCREEN_ACTIVE_DIRECTORY_PASSWORD_CHANGE = + 'ad-password-change'; /* Accelerator identifiers. Must be kept in sync with webui_login_view.cc. */ /** @const */ var ACCELERATOR_CANCEL = 'cancel'; @@ -1003,6 +1005,15 @@ }; /** + * Shows password change screen for Active Directory users. + * @param {string} username Display name of the user whose password is being + * changed. + */ + DisplayManager.showActiveDirectoryPasswordChangeScreen = function(username) { + login.ActiveDirectoryPasswordChangeScreen.show(username); + }; + + /** * Clears error bubble. */ DisplayManager.clearErrors = function() {
diff --git a/ui/login/screen_container.css b/ui/login/screen_container.css index 2dd778817..ae57e49 100644 --- a/ui/login/screen_container.css +++ b/ui/login/screen_container.css
@@ -99,6 +99,7 @@ #oobe.kiosk-enable #inner-container, #oobe.oauth-enrollment #inner-container, #oobe.password-changed #inner-container, +#oobe.ad-password-change #inner-container, #oobe.reset #inner-container, #oobe.supervised-user-creation #inner-container, #oobe.supervised-user-creation-dialog #inner-container,