diff --git a/DEPS b/DEPS index 567f23dc..85937c6 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': '61b721c449d022cdadf56adf4ea1a0b7e2850f18', + 'skia_revision': '578f064a60b63ddfb00831e9e59a47060bfcefe0', # 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': '0dae245e03dc7694d44a1b2e6e0d13865bc5f1f6', + 'v8_revision': '4ed8f7edf5dc80fb6240780af0ddb2875081dc89', # 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. @@ -64,7 +64,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': '1d7018e92d315c883dca38dd083db44791761827', + 'pdfium_revision': '717a4fc857d66017cecc4c8f8285713135b9dc68', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling openmax_dl # and whatever else without interference from each other. @@ -96,7 +96,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': 'a75c463e8416e25de8c1d70ec210a1de89ea19a5', + 'catapult_revision': '90835c8a63dee2c4d38c223acc2a58e54574e333', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -232,7 +232,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' + '@' + '1c1bd4dc650bac02aa9a79037fd8e4da527fd857', # commit position 16857 + Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + 'b369f97c44d3c4c6e33843c2db0698c80fd929c9', # commit position 16867 'src/third_party/openmax_dl': Var('chromium_git') + '/external/webrtc/deps/third_party/openmax.git' + '@' + Var('openmax_dl_revision'),
diff --git a/WATCHLISTS b/WATCHLISTS index 9fa9e6ed..e5506e4 100644 --- a/WATCHLISTS +++ b/WATCHLISTS
@@ -1542,6 +1542,7 @@ 'arc': ['elijahtaylor+arcwatch@chromium.org', 'hidehiko+watch@chromium.org', 'lhchavez+watch@chromium.org', + 'victorhsieh+watch@chromium.org', 'yusukes+watch@chromium.org'], 'arc_auth': ['khmel+watch@chromium.org'], 'arc_kiosk': ['poromov+watch@chromium.org'],
diff --git a/android_webview/tools/automated_ui_tests/javatests/src/org/chromium/webview_ui_test/test/ActionModeTest.java b/android_webview/tools/automated_ui_tests/javatests/src/org/chromium/webview_ui_test/test/ActionModeTest.java index b9d58e1a..ffbcca9 100644 --- a/android_webview/tools/automated_ui_tests/javatests/src/org/chromium/webview_ui_test/test/ActionModeTest.java +++ b/android_webview/tools/automated_ui_tests/javatests/src/org/chromium/webview_ui_test/test/ActionModeTest.java
@@ -41,16 +41,17 @@ import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout; -import android.animation.ValueAnimator; import android.app.Activity; import android.app.Instrumentation; import android.content.Intent; import android.os.Build; import android.support.test.InstrumentationRegistry; +import android.support.test.espresso.Espresso; +import android.support.test.espresso.IdlingResource; +import android.support.test.espresso.IdlingResource.ResourceCallback; import android.support.test.espresso.NoMatchingViewException; import android.support.test.espresso.PerformException; import android.support.test.espresso.Root; -import android.support.test.espresso.ViewAction; import android.support.test.espresso.action.GeneralClickAction; import android.support.test.espresso.action.GeneralLocation; import android.support.test.espresso.action.Press; @@ -68,20 +69,18 @@ import org.hamcrest.Description; import org.hamcrest.Matcher; import org.hamcrest.TypeSafeMatcher; +import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.chromium.base.Log; import org.chromium.base.test.BaseJUnit4ClassRunner; import org.chromium.webview_ui_test.R; import org.chromium.webview_ui_test.WebViewUiTestActivity; import org.chromium.webview_ui_test.test.util.UseLayout; import org.chromium.webview_ui_test.test.util.WebViewUiTestRule; -import java.lang.reflect.Method; - /** * Tests for WebView ActionMode. */ @@ -105,6 +104,8 @@ public WebViewUiTestRule mWebViewActivityRule = new WebViewUiTestRule(WebViewUiTestActivity.class); + private ActionBarIdlingResource mActionBarIdlingResource; + @Before public void setUp() { mWebViewActivityRule.launchActivity(); @@ -114,21 +115,13 @@ onWebView(withId(R.id.webview)) .withElement(findElement(Locator.TAG_NAME, "p")) .check(webMatches(getText(), containsString("Hello world"))); - disableAnimation(); + mActionBarIdlingResource = new ActionBarIdlingResource(); + Espresso.registerIdlingResources(mActionBarIdlingResource); } - /** - * Only way to disable popup animations. - */ - private void disableAnimation() { - try { - // This is a hidden method to disable animations. It is also being used by CTS tests. - Method setDurationScale = ValueAnimator.class.getMethod( - "setDurationScale", float.class); - setDurationScale.invoke(null, 0.0f); - } catch (Exception e) { - Log.e(TAG, "Couldn't disable animation", e); - } + @After + public void tearDown() { + Espresso.unregisterIdlingResources(mActionBarIdlingResource); } /** @@ -138,9 +131,9 @@ @SmallTest @UseLayout("edittext_webview") public void testCopyPaste() { - onView(withId(R.id.webview)).perform(longClickOnLastWord()); + longClickOnLastWord(R.id.webview); clickPopupAction(COPY_ACTION); - onView(withId(R.id.edittext)).perform(longClickOnLastWord()); + longClickOnLastWord(R.id.edittext); clickPopupAction(PASTE_ACTION); onView(withId(R.id.edittext)) .check(matches(withText("world"))); @@ -153,10 +146,10 @@ @SmallTest @UseLayout("edittext_webview") public void testSelectAll() { - onView(withId(R.id.webview)).perform(longClickOnLastWord()); + longClickOnLastWord(R.id.webview); clickPopupAction("Select all"); clickPopupAction(COPY_ACTION); - onView(withId(R.id.edittext)).perform(longClickOnLastWord()); + longClickOnLastWord(R.id.edittext); clickPopupAction(PASTE_ACTION); onView(withId(R.id.edittext)) .check(matches(withText("Hello world"))); @@ -173,7 +166,7 @@ intending(anyIntent()) .respondWith(new Instrumentation.ActivityResult(Activity.RESULT_OK, new Intent())); - onView(withId(R.id.webview)).perform(longClickOnLastWord()); + longClickOnLastWord(R.id.webview); clickPopupAction(SHARE_ACTION); intended(allOf(hasAction(Intent.ACTION_CHOOSER), @@ -194,7 +187,7 @@ Intents.init(); intending(anyIntent()) .respondWith(new Instrumentation.ActivityResult(Activity.RESULT_OK, new Intent())); - onView(withId(R.id.webview)).perform(longClickOnLastWord()); + longClickOnLastWord(R.id.webview); clickPopupAction(WEB_SEARCH_ACTION); intended(allOf(hasAction(Intent.ACTION_WEB_SEARCH), hasExtras(allOf(hasEntry("com.android.browser.application_id", @@ -213,7 +206,7 @@ public void testAssist() { // TODO(aluo): Get SdkSuppress to work with the test runner if (Build.VERSION.SDK_INT < 24) return; - onView(withId(R.id.webview)).perform(longClickOnLastWord()); + longClickOnLastWord(R.id.webview); clickPopupAction(ASSIST_ACTION); UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); UiObject assistUi = device.findObject(new UiSelector().packageName(QUICK_SEARCH_BOX_PKG)); @@ -230,7 +223,7 @@ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { try { // On L and lower, use the espresso DEFAULT root matcher if ActionBar is detected - onView(withClassName(endsWith("widget.ActionBarContextView"))) + onView(withClassName(endsWith("ActionBarContextView"))) .check(matches(isDisplayed())); rootMatcher = DEFAULT; } catch (NoMatchingViewException | AssertionFailedError e) { @@ -241,27 +234,30 @@ // On M and above, can use the decoreView matcher rootMatcher = withDecorView(isEnabled()); } + try { onView(anyOf(withText(name), withContentDescription(name))) .inRoot(rootMatcher) .perform(click()); - } catch (PerformException e) { + } catch (PerformException | NoMatchingViewException e) { // Take care of case when the item is in the overflow menu onView(withContentDescription(MORE_OPTIONS_ACTION)) - .inRoot(withDecorView(isEnabled())) + .inRoot(rootMatcher) .perform(click()); onData(new MenuItemMatcher(equalTo(name))).inRoot(rootMatcher).perform(click()); } } /** - * This view action clicks on center right of a view to select the last word + * Perform a view action that clicks on the last word and start the idling resource + * to wait for completion of the popup menu */ - private static final ViewAction longClickOnLastWord() { + private final void longClickOnLastWord(int viewId) { // TODO(aluo): This function is not guaranteed to click on element. Change to // implementation that gets bounding box for elements using Javascript. - return actionWithAssertions( - new GeneralClickAction(Tap.LONG, GeneralLocation.CENTER_RIGHT, Press.FINGER)); + onView(withId(viewId)).perform(actionWithAssertions( + new GeneralClickAction(Tap.LONG, GeneralLocation.CENTER_RIGHT, Press.FINGER))); + mActionBarIdlingResource.start(); } /** @@ -285,4 +281,38 @@ description.appendDescriptionOf(mTitleMatcher); } } + + private class ActionBarIdlingResource implements IdlingResource { + private boolean mActionStarting; + private ResourceCallback mResourceCallback; + + ActionBarIdlingResource() { + mActionStarting = false; + mResourceCallback = null; + } + + @Override + public String getName() { + return "ActionBarIdlingResource"; + } + + @Override + public boolean isIdleNow() { + if (!mActionStarting) return true; + if (mWebViewActivityRule.isActionBarDisplayed()) { + mActionStarting = false; + if (mResourceCallback != null) mResourceCallback.onTransitionToIdle(); + } + return !mActionStarting; + } + + @Override + public void registerIdleTransitionCallback(ResourceCallback callback) { + mResourceCallback = callback; + } + + public void start() { + mActionStarting = true; + } + } }
diff --git a/android_webview/tools/automated_ui_tests/javatests/src/org/chromium/webview_ui_test/test/util/WebViewUiTestRule.java b/android_webview/tools/automated_ui_tests/javatests/src/org/chromium/webview_ui_test/test/util/WebViewUiTestRule.java index d60a16bd..c3e6a72 100644 --- a/android_webview/tools/automated_ui_tests/javatests/src/org/chromium/webview_ui_test/test/util/WebViewUiTestRule.java +++ b/android_webview/tools/automated_ui_tests/javatests/src/org/chromium/webview_ui_test/test/util/WebViewUiTestRule.java
@@ -4,7 +4,21 @@ package org.chromium.webview_ui_test.test.util; +import static android.support.test.espresso.matcher.RootMatchers.withDecorView; +import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant; +import static android.support.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed; +import static android.support.test.espresso.matcher.ViewMatchers.withChild; +import static android.support.test.espresso.matcher.ViewMatchers.withClassName; +import static android.support.test.espresso.matcher.ViewMatchers.withText; + +import static org.hamcrest.CoreMatchers.allOf; +import static org.hamcrest.Matchers.endsWith; +import static org.hamcrest.Matchers.hasItem; + import android.content.Intent; +import android.os.Build; +import android.support.test.espresso.BaseLayerComponent; +import android.support.test.espresso.DaggerBaseLayerComponent; import android.support.test.rule.ActivityTestRule; import android.webkit.WebView; @@ -25,6 +39,7 @@ private WebViewSyncWrapper mSyncWrapper; private String mLayout; + private BaseLayerComponent mBaseLayerComponent; public WebViewUiTestRule(Class<WebViewUiTestActivity> activityClass) { super(activityClass); @@ -81,4 +96,35 @@ Assert.fail(e.getMessage()); } } + + public boolean isActionBarDisplayed() { + if (mBaseLayerComponent == null) mBaseLayerComponent = DaggerBaseLayerComponent.create(); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + // For M and above + if (hasItem(withDecorView(withChild(allOf( + withClassName(endsWith("PopupBackgroundView")), + isCompletelyDisplayed())))).matches( + mBaseLayerComponent.activeRootLister().listActiveRoots())) { + return true; + } + } else { + // For L + if (hasItem(withDecorView(hasDescendant(allOf( + withClassName(endsWith("ActionMenuItemView")), + isCompletelyDisplayed())))).matches( + mBaseLayerComponent.activeRootLister().listActiveRoots())) { + return true; + } + + // Paste option is a popup on L + if (hasItem(withDecorView(withChild(withText("Paste")))).matches( + mBaseLayerComponent.activeRootLister().listActiveRoots())) { + return true; + } + } + + + return false; + } }
diff --git a/ash/OWNERS b/ash/OWNERS index 98b3759b..a3b6999b 100644 --- a/ash/OWNERS +++ b/ash/OWNERS
@@ -9,3 +9,5 @@ per-file ash_chromeos_strings.grdp=* per-file ash_switches.*=* per-file BUILD.gn=* + +# COMPONENT: UI>Shell
diff --git a/base/BUILD.gn b/base/BUILD.gn index 96ddf2f..c9bb0ea 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -385,6 +385,10 @@ "files/memory_mapped_file_win.cc", "files/scoped_file.cc", "files/scoped_file.h", + "files/scoped_platform_handle.cc", + "files/scoped_platform_handle.h", + "files/scoped_platform_handle_posix.cc", + "files/scoped_platform_handle_win.cc", "files/scoped_temp_dir.cc", "files/scoped_temp_dir.h", "format_macros.h", @@ -1949,6 +1953,7 @@ "files/file_util_unittest.cc", "files/important_file_writer_unittest.cc", "files/memory_mapped_file_unittest.cc", + "files/scoped_platform_handle_unittest.cc", "files/scoped_temp_dir_unittest.cc", "gmock_unittest.cc", "guid_unittest.cc",
diff --git a/base/files/scoped_platform_handle.cc b/base/files/scoped_platform_handle.cc new file mode 100644 index 0000000..a0c30155 --- /dev/null +++ b/base/files/scoped_platform_handle.cc
@@ -0,0 +1,31 @@ +// 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 "base/files/scoped_platform_handle.h" + +namespace base { + +ScopedPlatformHandle::ScopedPlatformHandle() : ScopedPlatformHandle(nullptr) {} + +ScopedPlatformHandle::ScopedPlatformHandle(std::nullptr_t) {} + +ScopedPlatformHandle::ScopedPlatformHandle(ScopedPlatformHandle&& other) = + default; + +ScopedPlatformHandle::ScopedPlatformHandle(HandleType handle) + : handle_(handle) {} + +ScopedPlatformHandle::ScopedPlatformHandle(ScopedHandleType handle) + : handle_(std::move(handle)) {} + +ScopedPlatformHandle::~ScopedPlatformHandle() {} + +ScopedPlatformHandle& ScopedPlatformHandle::operator=( + ScopedPlatformHandle&& other) = default; + +ScopedPlatformHandle::ScopedHandleType ScopedPlatformHandle::Take() { + return ScopedHandleType(release()); +} + +} // namespace base
diff --git a/base/files/scoped_platform_handle.h b/base/files/scoped_platform_handle.h new file mode 100644 index 0000000..cfff5a7 --- /dev/null +++ b/base/files/scoped_platform_handle.h
@@ -0,0 +1,75 @@ +// 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 BASE_FILES_SCOPED_PLATFORM_HANDLE_H_ +#define BASE_FILES_SCOPED_PLATFORM_HANDLE_H_ + +#include <stddef.h> +#include <stdint.h> + +#include "base/base_export.h" +#include "build/build_config.h" + +#if defined(OS_WIN) +#include <windows.h> + +#include "base/win/scoped_handle.h" +#elif defined(OS_POSIX) +#include "base/files/scoped_file.h" +#endif + +namespace base { + +// A ScopedPlatformHandle encapsulates ownership of either a Windows handle or +// a POSIX file descriptor, while presenting a common interface for the sake +// of simple, consistent, and safe ownership semantics. Platform-specific usage +// details are thus relegated to code which either acquires or uses the +// underlying platform resource. +class BASE_EXPORT ScopedPlatformHandle { + public: +#if defined(OS_WIN) + using HandleType = HANDLE; + using ScopedHandleType = win::ScopedHandle; +#elif defined(OS_POSIX) + using HandleType = int; + using ScopedHandleType = ScopedFD; +#endif + + // Constructors for an invalid ScopedPlatformHandle. + ScopedPlatformHandle(); + ScopedPlatformHandle(std::nullptr_t); + + ScopedPlatformHandle(ScopedPlatformHandle&& other); + + // These constructors always take ownership of the given handle. + explicit ScopedPlatformHandle(HandleType handle); + explicit ScopedPlatformHandle(ScopedHandleType handle); + + ~ScopedPlatformHandle(); + + ScopedPlatformHandle& operator=(ScopedPlatformHandle&& other); + + // Indicates whether this ScopedPlatformHandle is holding a valid handle. + bool is_valid() const; + + // Closes the handle. + void reset(); + + // Returns the platform-specific handle value. + HandleType get() const; + + // Returns the platform-specific handle value, releasing ownership of the + // handle. + HandleType release(); + + // Transfers ownership of the handle to a platform-specific scoper. + ScopedHandleType Take(); + + private: + ScopedHandleType handle_; +}; + +} // namespace base + +#endif // BASE_FILES_SCOPED_PLATFORM_HANDLE_H_
diff --git a/base/files/scoped_platform_handle_posix.cc b/base/files/scoped_platform_handle_posix.cc new file mode 100644 index 0000000..38ee85a6 --- /dev/null +++ b/base/files/scoped_platform_handle_posix.cc
@@ -0,0 +1,25 @@ +// 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 "base/files/scoped_platform_handle.h" + +namespace base { + +bool ScopedPlatformHandle::is_valid() const { + return handle_.is_valid(); +} + +void ScopedPlatformHandle::reset() { + handle_.reset(); +} + +ScopedPlatformHandle::HandleType ScopedPlatformHandle::get() const { + return handle_.get(); +} + +ScopedPlatformHandle::HandleType ScopedPlatformHandle::release() { + return handle_.release(); +} + +} // namespace base
diff --git a/base/files/scoped_platform_handle_unittest.cc b/base/files/scoped_platform_handle_unittest.cc new file mode 100644 index 0000000..1b295854 --- /dev/null +++ b/base/files/scoped_platform_handle_unittest.cc
@@ -0,0 +1,94 @@ +// 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 "base/files/scoped_platform_handle.h" + +#include "base/files/file.h" +#include "base/files/scoped_temp_dir.h" +#include "base/macros.h" +#include "base/strings/stringprintf.h" +#include "testing/gtest/include/gtest/gtest.h" + +#if defined(OS_WIN) +#include <windows.h> + +#include "base/win/scoped_handle.h" +#elif defined(OS_POSIX) +#include "base/files/scoped_file.h" +#endif + +namespace base { +namespace { + +class ScopedPlatformHandleTest : public testing::Test { + public: + ScopedPlatformHandleTest() { CHECK(temp_dir_.CreateUniqueTempDir()); } + + protected: + ScopedPlatformHandle CreateValidHandle() { + return ScopedPlatformHandle(OpenTempFile().TakePlatformFile()); + } + + private: + base::File OpenTempFile() { + base::File temp_file(temp_dir_.GetPath().AppendASCII( + base::StringPrintf("file_%d", next_file_id_)), + base::File::FLAG_CREATE | base::File::FLAG_WRITE); + ++next_file_id_; + return temp_file; + } + + ScopedTempDir temp_dir_; + int next_file_id_ = 1; + + DISALLOW_COPY_AND_ASSIGN(ScopedPlatformHandleTest); +}; + +TEST_F(ScopedPlatformHandleTest, Invalid) { + ScopedPlatformHandle default_value; + EXPECT_TRUE(!default_value.is_valid()); + + ScopedPlatformHandle null_value(nullptr); + EXPECT_TRUE(!null_value.is_valid()); + + default_value.reset(); + null_value.reset(); + EXPECT_TRUE(!default_value.is_valid()); + EXPECT_TRUE(!null_value.is_valid()); +} + +TEST_F(ScopedPlatformHandleTest, BasicUsage) { + ScopedPlatformHandle handle_a = CreateValidHandle(); + ScopedPlatformHandle handle_b = CreateValidHandle(); + EXPECT_TRUE(handle_a.is_valid()); + EXPECT_TRUE(handle_b.is_valid()); + + ScopedPlatformHandle::HandleType handle_a_value = handle_a.get(); + ScopedPlatformHandle::HandleType handle_b_value = handle_b.get(); + EXPECT_TRUE(handle_a.is_valid()); + EXPECT_TRUE(handle_b.is_valid()); + + ScopedPlatformHandle::ScopedHandleType scoped_handle = handle_a.Take(); + ScopedPlatformHandle::HandleType raw_handle = handle_b.release(); + EXPECT_FALSE(handle_a.is_valid()); + EXPECT_FALSE(handle_b.is_valid()); + + handle_a = ScopedPlatformHandle(std::move(scoped_handle)); + handle_b = ScopedPlatformHandle(raw_handle); + EXPECT_TRUE(handle_a.is_valid()); + EXPECT_TRUE(handle_b.is_valid()); + EXPECT_EQ(handle_a_value, handle_a.get()); + EXPECT_EQ(handle_b_value, handle_b.get()); + + handle_b = std::move(handle_a); + EXPECT_FALSE(handle_a.is_valid()); + EXPECT_TRUE(handle_b.is_valid()); + EXPECT_EQ(handle_a_value, handle_b.get()); + + handle_b.reset(); + EXPECT_FALSE(handle_b.is_valid()); +} + +} // namespace +} // namespace base
diff --git a/base/files/scoped_platform_handle_win.cc b/base/files/scoped_platform_handle_win.cc new file mode 100644 index 0000000..94235f2 --- /dev/null +++ b/base/files/scoped_platform_handle_win.cc
@@ -0,0 +1,25 @@ +// 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 "base/files/scoped_platform_handle.h" + +namespace base { + +bool ScopedPlatformHandle::is_valid() const { + return handle_.IsValid(); +} + +void ScopedPlatformHandle::reset() { + handle_.Close(); +} + +ScopedPlatformHandle::HandleType ScopedPlatformHandle::get() const { + return handle_.Get(); +} + +ScopedPlatformHandle::HandleType ScopedPlatformHandle::release() { + return handle_.Take(); +} + +} // namespace base
diff --git a/base/trace_event/memory_dump_manager.cc b/base/trace_event/memory_dump_manager.cc index 31016f9..f86b9e9 100644 --- a/base/trace_event/memory_dump_manager.cc +++ b/base/trace_event/memory_dump_manager.cc
@@ -156,7 +156,6 @@ MemoryDumpManager::MemoryDumpManager() : delegate_(nullptr), - is_coordinator_(false), memory_tracing_enabled_(0), tracing_process_id_(kInvalidTracingProcessId), dumper_registrations_ignored_for_testing_(false), @@ -214,14 +213,12 @@ heap_profiling_enabled_ = true; } -void MemoryDumpManager::Initialize(MemoryDumpManagerDelegate* delegate, - bool is_coordinator) { +void MemoryDumpManager::Initialize(MemoryDumpManagerDelegate* delegate) { { AutoLock lock(lock_); DCHECK(delegate); DCHECK(!delegate_); delegate_ = delegate; - is_coordinator_ = is_coordinator; EnableHeapProfilingIfNeeded(); } @@ -460,21 +457,10 @@ TRACE_ID_MANGLE(guid)); MemoryDumpCallback wrapped_callback = Bind(&OnGlobalDumpDone, callback); - // Technically there is no need to grab the |lock_| here as the delegate is - // long-lived and can only be set by Initialize(), which is locked and - // necessarily happens before memory_tracing_enabled_ == true. - // Not taking the |lock_|, though, is lakely make TSan barf and, at this point - // (memory-infra is enabled) we're not in the fast-path anymore. - MemoryDumpManagerDelegate* delegate; - { - AutoLock lock(lock_); - delegate = delegate_; - } - // The delegate will coordinate the IPC broadcast and at some point invoke // CreateProcessDump() to get a dump for the current process. MemoryDumpRequestArgs args = {guid, dump_type, level_of_detail}; - delegate->RequestGlobalMemoryDump(args, wrapped_callback); + delegate_->RequestGlobalMemoryDump(args, wrapped_callback); } void MemoryDumpManager::RequestGlobalDump( @@ -862,7 +848,7 @@ dump_scheduler_->NotifyPollingSupported(); // Only coordinator process triggers periodic global memory dumps. - if (is_coordinator_) + if (delegate_->IsCoordinator()) dump_scheduler_->NotifyPeriodicTriggerSupported(); } @@ -907,10 +893,6 @@ return session_state_->IsDumpModeAllowed(dump_mode); } -uint64_t MemoryDumpManager::GetTracingProcessId() const { - return delegate_->GetTracingProcessId(); -} - MemoryDumpManager::MemoryDumpProviderInfo::MemoryDumpProviderInfo( MemoryDumpProvider* dump_provider, const char* name,
diff --git a/base/trace_event/memory_dump_manager.h b/base/trace_event/memory_dump_manager.h index 92cc2f4..c1f565c 100644 --- a/base/trace_event/memory_dump_manager.h +++ b/base/trace_event/memory_dump_manager.h
@@ -22,6 +22,14 @@ #include "base/trace_event/process_memory_dump.h" #include "base/trace_event/trace_event.h" +// Forward declare |MemoryDumpManagerDelegateImplTest| so that we can make it a +// friend of |MemoryDumpManager| and give it access to |SetInstanceForTesting|. +namespace memory_instrumentation { + +class MemoryDumpManagerDelegateImplTest; + +} // namespace memory_instrumentation + namespace base { class SingleThreadTaskRunner; @@ -54,13 +62,10 @@ // On the other side, the MemoryDumpManager will not be fully operational // (i.e. will NACK any RequestGlobalMemoryDump()) until initialized. // Arguments: - // is_coordinator: if true this MemoryDumpManager instance will act as a - // coordinator and schedule periodic dumps (if enabled via TraceConfig); - // false when the MemoryDumpManager is initialized in a slave process. // delegate: inversion-of-control interface for embedder-specific behaviors // (multiprocess handshaking). See the lifetime and thread-safety // requirements in the |MemoryDumpManagerDelegate| docstring. - void Initialize(MemoryDumpManagerDelegate* delegate, bool is_coordinator); + void Initialize(MemoryDumpManagerDelegate* delegate); // (Un)Registers a MemoryDumpProvider instance. // Args: @@ -135,7 +140,10 @@ // retrieved by child processes only when tracing is enabled. This is // intended to express cross-process sharing of memory dumps on the // child-process side, without having to know its own child process id. - uint64_t GetTracingProcessId() const; + uint64_t GetTracingProcessId() const { return tracing_process_id_; } + void set_tracing_process_id(uint64_t tracing_process_id) { + tracing_process_id_ = tracing_process_id; + } // Returns the name for a the allocated_objects dump. Use this to declare // suballocator dumps from other dump providers. @@ -156,6 +164,7 @@ friend class MemoryDumpManagerDelegate; friend class MemoryDumpManagerTest; friend class MemoryDumpScheduler; + friend class memory_instrumentation::MemoryDumpManagerDelegateImplTest; // Descriptor used to hold information about registered MDPs. // Some important considerations about lifetime of this object: @@ -350,9 +359,6 @@ MemoryDumpManagerDelegate* delegate_; // Not owned. - // When true, this instance is in charge of coordinating periodic dumps. - bool is_coordinator_; - // Protects from concurrent accesses to the |dump_providers_*| and |delegate_| // to guard against disabling logging while dumping on another thread. Lock lock_; @@ -388,9 +394,7 @@ virtual void RequestGlobalMemoryDump(const MemoryDumpRequestArgs& args, const MemoryDumpCallback& callback) = 0; - // Returns tracing process id of the current process. This is used by - // MemoryDumpManager::GetTracingProcessId. - virtual uint64_t GetTracingProcessId() const = 0; + virtual bool IsCoordinator() const = 0; protected: MemoryDumpManagerDelegate() {}
diff --git a/base/trace_event/memory_dump_manager_unittest.cc b/base/trace_event/memory_dump_manager_unittest.cc index 51d4194..330c75d 100644 --- a/base/trace_event/memory_dump_manager_unittest.cc +++ b/base/trace_event/memory_dump_manager_unittest.cc
@@ -119,7 +119,8 @@ // requests locally to the MemoryDumpManager instead of performing IPC dances. class MemoryDumpManagerDelegateForTesting : public MemoryDumpManagerDelegate { public: - MemoryDumpManagerDelegateForTesting() { + MemoryDumpManagerDelegateForTesting(bool is_coordinator) + : is_coordinator_(is_coordinator) { ON_CALL(*this, RequestGlobalMemoryDump(_, _)) .WillByDefault(Invoke( this, &MemoryDumpManagerDelegateForTesting::CreateProcessDump)); @@ -129,13 +130,13 @@ void(const MemoryDumpRequestArgs& args, const MemoryDumpCallback& callback)); - uint64_t GetTracingProcessId() const override { - NOTREACHED(); - return MemoryDumpManager::kInvalidTracingProcessId; - } + bool IsCoordinator() const override { return is_coordinator_; } // Promote the CreateProcessDump to public so it can be used by test fixtures. using MemoryDumpManagerDelegate::CreateProcessDump; + + private: + bool is_coordinator_; }; class MockMemoryDumpProvider : public MemoryDumpProvider { @@ -220,13 +221,12 @@ mdm_.reset(new MemoryDumpManager()); MemoryDumpManager::SetInstanceForTesting(mdm_.get()); ASSERT_EQ(mdm_.get(), MemoryDumpManager::GetInstance()); - delegate_.reset(new MemoryDumpManagerDelegateForTesting); } void TearDown() override { MemoryDumpManager::SetInstanceForTesting(nullptr); - mdm_.reset(); delegate_.reset(); + mdm_.reset(); message_loop_.reset(); TraceLog::DeleteForTesting(); } @@ -248,7 +248,8 @@ protected: void InitializeMemoryDumpManager(bool is_coordinator) { mdm_->set_dumper_registrations_ignored_for_testing(true); - mdm_->Initialize(delegate_.get(), is_coordinator); + delegate_.reset(new MemoryDumpManagerDelegateForTesting(is_coordinator)); + mdm_->Initialize(delegate_.get()); } void RequestGlobalDumpAndWait(MemoryDumpType dump_type, @@ -897,7 +898,6 @@ // initialization gets NACK-ed cleanly. { EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0); - EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(0); RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, MemoryDumpLevelOfDetail::DETAILED); EXPECT_FALSE(last_callback_success_); @@ -906,9 +906,9 @@ // Now late-initialize the MemoryDumpManager and check that the // RequestGlobalDump completes successfully. { + InitializeMemoryDumpManager(false /* is_coordinator */); EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(1); EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1); - InitializeMemoryDumpManager(false /* is_coordinator */); RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED, MemoryDumpLevelOfDetail::DETAILED); EXPECT_TRUE(last_callback_success_);
diff --git a/build/android/gradle/dependencies.jinja b/build/android/gradle/dependencies.jinja index c7e884a8b..e978304 100644 --- a/build/android/gradle/dependencies.jinja +++ b/build/android/gradle/dependencies.jinja
@@ -3,16 +3,22 @@ {# found in the LICENSE file. #} {% macro expand_deps(variables, prefix) %} {% if variables is defined %} +{% if variables.prebuilts is defined %} {% for path in variables.prebuilts %} {{ prefix }} files("{{ path }}") {% endfor %} +{% endif %} +{% if variables.java_project_deps is defined %} {% for proj in variables.java_project_deps %} {{ prefix }} project(":{{ proj }}") {% endfor %} +{% endif %} +{% if variables.android_project_deps is defined %} {% for proj in variables.android_project_deps %} {{ prefix }} project(path: ":{{ proj }}", configuration: "debug") {% endfor %} {% endif %} +{% endif %} {% endmacro %} dependencies {
diff --git a/build/android/gradle/generate_gradle.py b/build/android/gradle/generate_gradle.py index 7a8ec32..2044aa37 100755 --- a/build/android/gradle/generate_gradle.py +++ b/build/android/gradle/generate_gradle.py
@@ -197,7 +197,10 @@ return self.DepsInfo()['type'] def ResZips(self): - return self.DepsInfo().get('owned_resources_zips') + return self.DepsInfo().get('owned_resources_zips', []) + + def ResDirs(self): + return self.DepsInfo().get('owned_resources_dirs', []) def JavaFiles(self): if self._java_files is None: @@ -213,7 +216,7 @@ return [p for p in self.JavaFiles() if not p.startswith('..')] def PrebuiltJars(self): - return self.Gradle()['dependent_prebuilt_jars'] + return self.Gradle().get('dependent_prebuilt_jars', []) def AllEntries(self): """Returns a list of all entries that the current entry depends on. @@ -236,36 +239,30 @@ class _ProjectContextGenerator(object): """Helper class to generate gradle build files""" def __init__(self, project_dir, build_vars, use_gradle_process_resources, - jinja_processor): + jinja_processor, split_projects): self.project_dir = project_dir self.build_vars = build_vars self.use_gradle_process_resources = use_gradle_process_resources self.jinja_processor = jinja_processor + self.split_projects = split_projects - def _GenJniLibs(self, entry): - native_section = entry.BuildConfig().get('native') - if native_section: - jni_libs = _CreateJniLibsDir( - constants.GetOutDirectory(), self.EntryOutputDir(entry), - native_section.get('libraries')) - else: - jni_libs = [] - return jni_libs + def _GenJniLibs(self, root_entry): + libraries = [] + for entry in self._GetEntries(root_entry): + libraries += entry.BuildConfig().get('native', []) + if libraries: + return _CreateJniLibsDir(constants.GetOutDirectory(), + self.EntryOutputDir(root_entry), libraries) + return [] - def _GenJavaDirs(self, entry): + def _GenJavaDirs(self, root_entry): + java_files = [] + for entry in self._GetEntries(root_entry): + java_files += entry.JavaFiles() java_dirs, excludes = _ComputeJavaSourceDirsAndExcludes( - constants.GetOutDirectory(), entry.JavaFiles()) - if self.Srcjars(entry): - java_dirs.append( - os.path.join(self.EntryOutputDir(entry), _SRCJARS_SUBDIR)) + constants.GetOutDirectory(), java_files) return java_dirs, excludes - def _GenResDirs(self, entry): - res_dirs = list(entry.DepsInfo().get('owned_resources_dirs', [])) - if entry.ResZips(): - res_dirs.append(os.path.join(self.EntryOutputDir(entry), _RES_SUBDIR)) - return res_dirs - def _GenCustomManifest(self, entry): """Returns the path to the generated AndroidManifest.xml. @@ -297,43 +294,75 @@ def _Relativize(self, entry, paths): return _RebasePath(paths, self.EntryOutputDir(entry)) - def EntryOutputDir(self, entry): - return os.path.join(self.project_dir, entry.GradleSubdir()) - - def Srcjars(self, entry): + def _Srcjars(self, entry): srcjars = _RebasePath(entry.Gradle().get('bundled_srcjars', [])) if not self.use_gradle_process_resources: srcjars += _RebasePath(entry.BuildConfig()['javac']['srcjars']) return srcjars - def GeneratedInputs(self, entry): - generated_inputs = [] - generated_inputs.extend(self.Srcjars(entry)) - generated_inputs.extend(_RebasePath(entry.ResZips())) - generated_inputs.extend(entry.GeneratedJavaFiles()) - generated_inputs.extend(entry.PrebuiltJars()) - return generated_inputs + def _GetEntries(self, entry): + if self.split_projects: + return [entry] + return entry.AllEntries() - def Generate(self, entry): - variables = {} - java_dirs, excludes = self._GenJavaDirs(entry) - variables['java_dirs'] = self._Relativize(entry, java_dirs) - variables['java_excludes'] = excludes - variables['jni_libs'] = self._Relativize(entry, self._GenJniLibs(entry)) - variables['res_dirs'] = self._Relativize(entry, self._GenResDirs(entry)) - android_manifest = entry.Gradle().get('android_manifest') - if not android_manifest: - android_manifest = self._GenCustomManifest(entry) - variables['android_manifest'] = self._Relativize(entry, android_manifest) + def EntryOutputDir(self, entry): + return os.path.join(self.project_dir, entry.GradleSubdir()) + + def AllSrcjars(self, root_entry): + srcjars = [] + for entry in self._GetEntries(root_entry): + srcjars += self._Srcjars(entry) + return set(srcjars) + + def AllResZips(self, root_entry): + res_zips = [] + for entry in self._GetEntries(root_entry): + res_zips += entry.ResZips() + return set(_RebasePath(res_zips)) + + def GeneratedInputs(self, root_entry): + generated_inputs = set(self.AllResZips(root_entry)) + generated_inputs.update(self.AllSrcjars(root_entry)) + for entry in self._GetEntries(root_entry): + generated_inputs.update(entry.GeneratedJavaFiles()) + generated_inputs.update(entry.PrebuiltJars()) + return set(generated_inputs) + + def Generate(self, root_entry): # TODO(agrieve): Add an option to use interface jars and see if that speeds # things up at all. - variables['prebuilts'] = self._Relativize(entry, entry.PrebuiltJars()) - deps = [_ProjectEntry.FromBuildConfigPath(p) - for p in entry.Gradle()['dependent_android_projects']] - variables['android_project_deps'] = [d.ProjectName() for d in deps] - deps = [_ProjectEntry.FromBuildConfigPath(p) - for p in entry.Gradle()['dependent_java_projects']] - variables['java_project_deps'] = [d.ProjectName() for d in deps] + variables = {} + java_dirs, excludes = self._GenJavaDirs(root_entry) + java_dirs.sort() + variables['java_dirs'] = self._Relativize(root_entry, java_dirs) + variables['java_dirs'].append(_SRCJARS_SUBDIR) + variables['java_excludes'] = excludes + variables['jni_libs'] = self._Relativize( + root_entry, set(self._GenJniLibs(root_entry))) + variables['prebuilts'] = [ + p for e in self._GetEntries(root_entry) for p in e.PrebuiltJars()] + variables['res_dirs'] = [ + p for e in self._GetEntries(root_entry) for p in e.ResDirs()] + for entry in self._GetEntries(root_entry): + variables['prebuilts'] += entry.PrebuiltJars() + variables['res_dirs'] += entry.ResDirs() + variables['prebuilts'] = self._Relativize( + root_entry, set(variables['prebuilts'])) + variables['res_dirs'] = self._Relativize( + root_entry, set(variables['res_dirs'])) + variables['res_dirs'].append(_RES_SUBDIR) + android_manifest = root_entry.Gradle().get('android_manifest') + if not android_manifest: + android_manifest = self._GenCustomManifest(root_entry) + variables['android_manifest'] = self._Relativize( + root_entry, android_manifest) + if self.split_projects: + deps = [_ProjectEntry.FromBuildConfigPath(p) + for p in root_entry.Gradle()['dependent_android_projects']] + variables['android_project_deps'] = [d.ProjectName() for d in deps] + deps = [_ProjectEntry.FromBuildConfigPath(p) + for p in root_entry.Gradle()['dependent_java_projects']] + variables['java_project_deps'] = [d.ProjectName() for d in deps] return variables @@ -611,6 +640,10 @@ parser.add_argument('--use-gradle-process-resources', action='store_true', help='Have gradle generate R.java rather than ninja') + parser.add_argument('--split-projects', + action='store_true', + help='Split projects by their gn deps rather than ' + 'combining all the dependencies of each target') args = parser.parse_args() if args.output_directory: constants.SetOutputDirectory(args.output_directory) @@ -619,12 +652,17 @@ devil_chromium.Initialize(output_directory=output_dir) run_tests_helper.SetLogLevel(args.verbose_count) + # TODO(wnwen): Fix packaging so that gradle resources work in this case. + if args.use_gradle_process_resources: + assert args.split_projects, ( + 'Gradle resources does not yet work without --split-projects.') + _gradle_output_dir = os.path.abspath( args.project_dir.replace('$CHROMIUM_OUTPUT_DIR', output_dir)) jinja_processor = jinja_template.JinjaProcessor(_FILE_DIR) build_vars = _ReadBuildVars(output_dir) generator = _ProjectContextGenerator(_gradle_output_dir, build_vars, - args.use_gradle_process_resources, jinja_processor) + args.use_gradle_process_resources, jinja_processor, args.split_projects) logging.warning('Creating project at: %s', generator.project_dir) if args.all: @@ -649,9 +687,10 @@ if args.all: main_entries = [e for e in main_entries if e.GetType() == 'android_apk'] - all_entries = _FindAllProjectEntries(main_entries) - logging.info('Found %d dependent build_config targets.', len(all_entries)) - entries = _CombineTestEntries(all_entries) + if args.split_projects: + main_entries = _FindAllProjectEntries(main_entries) + logging.info('Found %d dependent build_config targets.', len(main_entries)) + entries = _CombineTestEntries(main_entries) logging.info('Creating %d projects for targets.', len(entries)) logging.warning('Writing .gradle files...') @@ -669,10 +708,10 @@ generated_inputs.extend(generator.GeneratedInputs(entry)) zip_tuples.extend( (s, os.path.join(generator.EntryOutputDir(entry), _SRCJARS_SUBDIR)) - for s in generator.Srcjars(entry)) + for s in generator.AllSrcjars(entry)) zip_tuples.extend( (s, os.path.join(generator.EntryOutputDir(entry), _RES_SUBDIR)) - for s in _RebasePath(entry.ResZips())) + for s in generator.AllResZips(entry)) _WriteFile( os.path.join(generator.EntryOutputDir(entry), 'build.gradle'), data)
diff --git a/build/config/android/BUILD.gn b/build/config/android/BUILD.gn index 2d78933..fddca1b 100644 --- a/build/config/android/BUILD.gn +++ b/build/config/android/BUILD.gn
@@ -27,14 +27,10 @@ ] if (is_clang) { - rebased_android_toolchain_root = - rebase_path(android_toolchain_root, root_build_dir) - assert(rebased_android_toolchain_root != "") # Mark as used. if (current_cpu == "mips64el") { cflags += [ - # TODO(gordanac) Enable integrated-as. - "-fno-integrated-as", - "-B${rebased_android_toolchain_root}/bin", # Else /usr/bin/as gets picked up. + # Have to force IAS for mips64. + "-fintegrated-as", ] } } else {
diff --git a/cc/surfaces/compositor_frame_sink_support.cc b/cc/surfaces/compositor_frame_sink_support.cc index 96508cd..6829117 100644 --- a/cc/surfaces/compositor_frame_sink_support.cc +++ b/cc/surfaces/compositor_frame_sink_support.cc
@@ -158,6 +158,8 @@ if (!surface_manager_->using_surface_references()) return; + SurfaceId last_surface_id = reference_tracker_.current_surface_id(); + // Populate list of surface references to add and remove based on reference // surfaces in current frame compared with the last frame. The list of // surface references includes references from both the pending and active @@ -166,7 +168,6 @@ active_referenced_surfaces, pending_referenced_surfaces); - SurfaceId last_surface_id = reference_tracker_.current_surface_id(); UpdateSurfaceReferences(last_surface_id, local_surface_id); }
diff --git a/cc/surfaces/compositor_frame_sink_support_unittest.cc b/cc/surfaces/compositor_frame_sink_support_unittest.cc index 7f5342d1..5e8f1fc 100644 --- a/cc/surfaces/compositor_frame_sink_support_unittest.cc +++ b/cc/surfaces/compositor_frame_sink_support_unittest.cc
@@ -23,9 +23,10 @@ namespace test { namespace { -constexpr FrameSinkId kParentFrameSink(2, 1); -constexpr FrameSinkId kChildFrameSink1(65563, 1); -constexpr FrameSinkId kChildFrameSink2(65564, 1); +constexpr FrameSinkId kDisplayFrameSink(2, 0); +constexpr FrameSinkId kParentFrameSink(3, 0); +constexpr FrameSinkId kChildFrameSink1(65563, 0); +constexpr FrameSinkId kChildFrameSink2(65564, 0); constexpr FrameSinkId kArbitraryFrameSink(1337, 7331); std::vector<SurfaceId> empty_surface_ids() { @@ -77,7 +78,9 @@ : surface_manager_(SurfaceManager::LifetimeType::REFERENCES) {} ~CompositorFrameSinkSupportTest() override {} - CompositorFrameSinkSupport& parent_support() { return *supports_[0]; } + CompositorFrameSinkSupport& display_support() { return *supports_[0]; } + + CompositorFrameSinkSupport& parent_support() { return *supports_[1]; } Surface* parent_surface() { return parent_support().current_surface_for_testing(); } @@ -85,12 +88,12 @@ return parent_support().ReferenceTrackerForTesting(); } - CompositorFrameSinkSupport& child_support1() { return *supports_[1]; } + CompositorFrameSinkSupport& child_support1() { return *supports_[2]; } Surface* child_surface1() { return child_support1().current_surface_for_testing(); } - CompositorFrameSinkSupport& child_support2() { return *supports_[2]; } + CompositorFrameSinkSupport& child_support2() { return *supports_[3]; } Surface* child_surface2() { return child_support2().current_surface_for_testing(); } @@ -136,6 +139,10 @@ begin_frame_source_.get())); surface_manager_.SetDependencyTracker(std::move(dependency_tracker)); supports_.push_back(base::MakeUnique<CompositorFrameSinkSupport>( + this, &surface_manager_, kDisplayFrameSink, true /* is_root */, + true /* handles_frame_sink_id_invalidation */, + true /* needs_sync_points */)); + supports_.push_back(base::MakeUnique<CompositorFrameSinkSupport>( this, &surface_manager_, kParentFrameSink, false /* is_root */, true /* handles_frame_sink_id_invalidation */, true /* needs_sync_points */)); @@ -177,6 +184,38 @@ DISALLOW_COPY_AND_ASSIGN(CompositorFrameSinkSupportTest); }; +// The display root surface should have a surface reference from the top-level +// root added/removed when a CompositorFrame is submitted with a new SurfaceId. +TEST_F(CompositorFrameSinkSupportTest, RootSurfaceReceivesReferences) { + const SurfaceId display_id_first = MakeSurfaceId(kDisplayFrameSink, 1); + const SurfaceId display_id_second = MakeSurfaceId(kDisplayFrameSink, 2); + + // Submit a CompositorFrame for the first display root surface. + display_support().SubmitCompositorFrame( + display_id_first.local_surface_id(), + MakeCompositorFrame({MakeSurfaceId(kParentFrameSink, 1)})); + + // A surface reference from the top-level root is added and there shouldn't be + // a temporary reference. + EXPECT_THAT(GetTempReferences(kDisplayFrameSink), IsEmpty()); + EXPECT_THAT(GetChildReferences(surface_manager().GetRootSurfaceId()), + UnorderedElementsAre(display_id_first)); + + // Submit a CompositorFrame for the second display root surface. + display_support().SubmitCompositorFrame( + display_id_second.local_surface_id(), + MakeCompositorFrame({MakeSurfaceId(kParentFrameSink, 2)})); + + // A surface reference from the top-level root to |display_id_second| should + // be added and the reference to |display_root_first| removed. + EXPECT_THAT(GetTempReferences(kDisplayFrameSink), IsEmpty()); + EXPECT_THAT(GetChildReferences(surface_manager().GetRootSurfaceId()), + UnorderedElementsAre(display_id_second)); + + // Surface |display_id_first| is unreachable and should get deleted. + EXPECT_EQ(nullptr, surface_manager().GetSurfaceForId(display_id_first)); +} + // The parent Surface is blocked on |child_id1| and |child_id2|. TEST_F(CompositorFrameSinkSupportTest, DisplayCompositorLockingBlockedOnTwo) { const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
diff --git a/chrome/android/java/res/layout/new_tab_page_layout.xml b/chrome/android/java/res/layout/new_tab_page_layout.xml index 4cc3b46..050ae19 100644 --- a/chrome/android/java/res/layout/new_tab_page_layout.xml +++ b/chrome/android/java/res/layout/new_tab_page_layout.xml
@@ -104,7 +104,7 @@ android:layout_weight="0" android:visibility="invisible" /> - <!-- Site suggestion tiles --> + <!-- Site suggestion tile grid --> <org.chromium.chrome.browser.suggestions.TileGridLayout android:id="@+id/tile_grid_layout" android:layout_width="wrap_content" @@ -116,7 +116,7 @@ android:paddingTop="@dimen/tile_grid_layout_padding_top" android:paddingBottom="4dp" /> - <!-- Site suggestions tile grid placeholder --> + <!-- Site suggestion tile grid placeholder --> <ViewStub android:id="@+id/tile_grid_placeholder_stub" android:layout_width="match_parent"
diff --git a/chrome/android/java/res/layout/tile_view.xml b/chrome/android/java/res/layout/tile_view.xml index f820e8f..2dbcc11 100644 --- a/chrome/android/java/res/layout/tile_view.xml +++ b/chrome/android/java/res/layout/tile_view.xml
@@ -12,39 +12,42 @@ android:paddingStart="4dp" android:paddingEnd="4dp" > + <!-- The main icon. --> <ImageView android:id="@+id/tile_view_icon" android:layout_width="@dimen/tile_view_icon_size" android:layout_height="@dimen/tile_view_icon_size" - android:layout_marginStart="12dp" - android:layout_marginEnd="12dp" - android:layout_marginTop="12dp" + android:layout_gravity="center_horizontal" + android:layout_marginTop="@dimen/tile_view_icon_margin_top" android:contentDescription="@null" /> + <!-- The offline badge. --> <org.chromium.chrome.browser.widget.TintedImageView android:id="@+id/offline_badge" android:layout_width="@dimen/tile_view_offline_badge_size" android:layout_height="@dimen/tile_view_offline_badge_size" - android:layout_marginStart="48dp" + android:layout_gravity="top|end" android:visibility="gone" android:background="@drawable/offline_badge_background" android:contentDescription="@string/accessibility_ntp_offline_badge" chrome:tint="@color/tile_view_offline_badge_tint" android:src="@drawable/offline_pin_round" /> + <!-- The touch highlight. --> <View + android:id="@+id/tile_view_highlight" android:layout_width="@dimen/tile_view_icon_size" android:layout_height="@dimen/tile_view_icon_size" - android:layout_marginStart="12dp" - android:layout_marginEnd="12dp" - android:layout_marginTop="12dp" + android:layout_gravity="center_horizontal" + android:layout_marginTop="@dimen/tile_view_icon_margin_top" android:background="@drawable/tile_view_highlight" /> + <!-- The title. --> <TextView android:id="@+id/tile_view_title" - android:layout_width="72dp" + android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="66dp" + android:layout_marginTop="@dimen/tile_view_title_margin_top" android:ellipsize="end" android:gravity="center_horizontal" android:lines="2"
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml index 43bb7ce..8eb4862 100644 --- a/chrome/android/java/res/values/dimens.xml +++ b/chrome/android/java/res/values/dimens.xml
@@ -276,8 +276,13 @@ <dimen name="tile_grid_layout_max_horizontal_spacing">16dp</dimen> <dimen name="tile_view_bg_corner_radius">2dp</dimen> <dimen name="tile_view_width">80dp</dimen> + <dimen name="tile_view_width_condensed">64dp</dimen> <dimen name="tile_view_icon_size">48dp</dimen> + <dimen name="tile_view_icon_margin_top">12dp</dimen> + <dimen name="tile_view_icon_margin_top_condensed">8dp</dimen> <dimen name="tile_view_offline_badge_size">24dp</dimen> + <dimen name="tile_view_title_margin_top">66dp</dimen> + <dimen name="tile_view_title_margin_top_condensed">62dp</dimen> <dimen name="ntp_logo_height">116dp</dimen> <dimen name="ntp_search_box_height">62dp</dimen> <dimen name="ntp_search_box_shadow_width">4dp</dimen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java index 3d2ad9a..9f24a05 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -132,6 +132,7 @@ public static final String IMPROVED_A2HS = "ImprovedA2HS"; public static final String NO_CREDIT_CARD_ABORT = "NoCreditCardAbort"; public static final String NTP_CONDENSED_LAYOUT = "NTPCondensedLayout"; + public static final String NTP_CONDENSED_TILE_LAYOUT = "NTPCondensedTileLayout"; public static final String NTP_FAKE_OMNIBOX_TEXT = "NTPFakeOmniboxText"; public static final String NTP_FOREIGN_SESSIONS_SUGGESTIONS = "NTPForeignSessionsSuggestions"; public static final String NTP_OFFLINE_PAGES_FEATURE_NAME = "NTPOfflinePages";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java index 3d124dd..7484e5f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java
@@ -37,7 +37,6 @@ import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.tabmodel.DocumentModeAssassin; import org.chromium.chrome.browser.upgrade.UpgradeActivity; -import org.chromium.content.browser.ChildProcessCreationParams; import org.chromium.ui.base.DeviceFormFactor; import java.lang.reflect.Field; @@ -125,7 +124,6 @@ // Kick off long running IO tasks that can be done in parallel. mNativeInitializationController = new NativeInitializationController(this); - initializeChildProcessCreationParams(); mNativeInitializationController.startBackgroundTasks(shouldAllocateChildConnection()); } @@ -135,11 +133,6 @@ return true; } - /** - * Allow derived classes to initialize their own {@link ChildProcessCreationParams}. - */ - protected void initializeChildProcessCreationParams() {} - @Override public void postInflationStartup() { final View firstDrawView = getViewToBeDrawnBeforeInitializingNative();
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 53d8d2f..57a49d7 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
@@ -76,10 +76,16 @@ private static final String PARAM_NTP_TILE_TITLE_LINES = "ntp_tile_title_lines"; /** - * The maximum number of tiles to try and fit in a row. On smaller screens, there may not be - * enough space to fit all of them. + * Experiment parameter for whether to use the condensed tile layout on small screens. */ - private static final int MAX_TILE_COLUMNS = 4; + private static final String PARAM_CONDENSED_TILE_LAYOUT_FOR_SMALL_SCREENS_ENABLED = + "condensed_tile_layout_for_small_screens_enabled"; + + /** + * Experiment parameter for whether to use the condensed tile layout on large screens. + */ + private static final String PARAM_CONDENSED_TILE_LAYOUT_FOR_LARGE_SCREENS_ENABLED = + "condensed_tile_layout_for_large_screens_enabled"; private NewTabPageRecyclerView mRecyclerView; @@ -234,6 +240,7 @@ mTileGridLayout = (TileGridLayout) mNewTabPageLayout.findViewById(R.id.tile_grid_layout); mTileGridLayout.setMaxRows(getMaxTileRows(searchProviderHasLogo)); + mTileGridLayout.setMaxColumns(getMaxTileColumns()); mTileGroup = new TileGroup(mActivity, mManager, mContextMenuManager, mTileGroupDelegate, /* observer = */ this, offlinePageBridge, getTileTitleLines()); @@ -248,7 +255,7 @@ mNewTabPageLayout.addOnLayoutChangeListener(this); setSearchProviderHasLogo(searchProviderHasLogo); - mTileGroup.startObserving(getMaxTileRows(searchProviderHasLogo) * MAX_TILE_COLUMNS); + mTileGroup.startObserving(getMaxTileRows(searchProviderHasLogo) * getMaxTileColumns()); // Set up snippets NewTabPageAdapter newTabPageAdapter = new NewTabPageAdapter(mManager, mNewTabPageLayout, @@ -805,6 +812,20 @@ ChromeFeatureList.NTP_CONDENSED_LAYOUT, PARAM_NTP_MAX_TILE_ROWS, defaultValue); } + /** + * Determines The maximum number of tiles to try and fit in a row. On smaller screens, there + * may not be enough space to fit all of them. + */ + private int getMaxTileColumns() { + if (!mUiConfig.getCurrentDisplayStyle().isSmall() + && ChromeFeatureList.getFieldTrialParamByFeatureAsBoolean( + ChromeFeatureList.NTP_CONDENSED_TILE_LAYOUT, + PARAM_CONDENSED_TILE_LAYOUT_FOR_LARGE_SCREENS_ENABLED, false)) { + return 5; + } + return 4; + } + private static int getTileTitleLines() { int defaultValue = 2; if (ChromeFeatureList.isEnabled(ChromeFeatureList.NTP_CONDENSED_LAYOUT)) { @@ -814,6 +835,17 @@ ChromeFeatureList.NTP_CONDENSED_LAYOUT, PARAM_NTP_TILE_TITLE_LINES, defaultValue); } + private boolean shouldUseCondensedTileLayout() { + if (mUiConfig.getCurrentDisplayStyle().isSmall()) { + return ChromeFeatureList.getFieldTrialParamByFeatureAsBoolean( + ChromeFeatureList.NTP_CONDENSED_TILE_LAYOUT, + PARAM_CONDENSED_TILE_LAYOUT_FOR_SMALL_SCREENS_ENABLED, false); + } + return ChromeFeatureList.getFieldTrialParamByFeatureAsBoolean( + ChromeFeatureList.NTP_CONDENSED_TILE_LAYOUT, + PARAM_CONDENSED_TILE_LAYOUT_FOR_LARGE_SCREENS_ENABLED, false); + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (mNewTabPageLayout != null) { @@ -855,7 +887,8 @@ @Override public void onTileDataChanged() { - mTileGroup.renderTileViews(mTileGridLayout, !mLoadHasCompleted); + mTileGroup.renderTileViews( + mTileGridLayout, !mLoadHasCompleted, shouldUseCondensedTileLayout()); mSnapshotTileGridChanged = true; // The page contents are initially hidden; otherwise they'll be drawn centered on the page
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGrid.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGrid.java index 11f5d1e..5a2563f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGrid.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGrid.java
@@ -107,11 +107,13 @@ super(LayoutInflater.from(parentView.getContext()) .inflate(R.layout.suggestions_site_tile_grid, parentView, false)); mLayout = (TileGridLayout) itemView; + mLayout.setMaxRows(getMaxTileRows()); + mLayout.setMaxColumns(MAX_TILE_COLUMNS); } public void onBindViewHolder(TileGroup tileGroup) { - mLayout.setMaxRows(getMaxTileRows()); - tileGroup.renderTileViews(mLayout, /* trackLoadTasks = */ false); + tileGroup.renderTileViews(mLayout, /* trackLoadTasks = */ false, + /* condensed = */ false); } public void updateIconView(Tile tile) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGridLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGridLayout.java index 31d13d5..45341c4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGridLayout.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGridLayout.java
@@ -19,16 +19,18 @@ * A layout that arranges tiles in a grid. */ public class TileGridLayout extends FrameLayout { - private static final int MAX_COLUMNS = 4; + private final int mVerticalSpacing; + private final int mMinHorizontalSpacing; + private final int mMaxHorizontalSpacing; + private final int mMaxWidth; - private int mVerticalSpacing; - private int mExtraVerticalSpacing; - private int mMinHorizontalSpacing; - private int mMaxHorizontalSpacing; - private int mMaxWidth; private int mMaxRows; + private int mMaxColumns; + private int mExtraVerticalSpacing; /** + * Constructor for inflating from XML. + * * @param context The view context in which this item will be shown. * @param attrs The attributes of the XML tag that is inflating the view. */ @@ -45,14 +47,20 @@ } /** - * Sets the maximum number of rows to display. Any items that don't fit within these rows will - * be hidden. + * Sets the maximum number of rows to display. Any items that don't fit will be hidden. */ public void setMaxRows(int rows) { mMaxRows = rows; } /** + * Sets the maximum number of columns to display. Any items that don't fit will be hidden. + */ + public void setMaxColumns(int columns) { + mMaxColumns = columns; + } + + /** * Sets the extra vertical spacing that must be used. It will be distributed evenly above each * row. */ @@ -105,7 +113,7 @@ int childWidth = getChildAt(0).getMeasuredWidth(); int numColumns = MathUtils.clamp( (gridWidth + mMinHorizontalSpacing) / (childWidth + mMinHorizontalSpacing), 1, - MAX_COLUMNS); + mMaxColumns); // Ensure column spacing isn't greater than mMaxHorizontalSpacing. int gridWidthMinusColumns = Math.max(0, gridWidth - numColumns * childWidth);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroup.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroup.java index ceaa781..8c8b078 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroup.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroup.java
@@ -242,8 +242,10 @@ * possible because view inflation and icon loading are slow. * @param tileGridLayout The layout to render the tile views into. * @param trackLoadTasks Whether to track load tasks. + * @param condensed Whether to use a condensed layout. */ - public void renderTileViews(TileGridLayout tileGridLayout, boolean trackLoadTasks) { + public void renderTileViews( + TileGridLayout tileGridLayout, boolean trackLoadTasks, boolean condensed) { // Map the old tile views by url so they can be reused later. Map<String, TileView> oldTileViews = new HashMap<>(); int childCount = tileGridLayout.getChildCount(); @@ -259,7 +261,8 @@ for (Tile tile : mTiles) { TileView tileView = oldTileViews.get(tile.getUrl()); if (tileView == null) { - tileView = buildTileView(tile, tileGridLayout, trackLoadTasks, mTitleLinesCount); + tileView = buildTileView( + tile, tileGridLayout, trackLoadTasks, mTitleLinesCount, condensed); } else { tileView.updateIfDataChanged(tile); } @@ -282,13 +285,14 @@ * @param parentView The parent of the new tile view. * @param trackLoadTask Whether to track a load task. * @param titleLines The number of text lines to use for each tile title. + * @param condensed Whether to use a condensed layout. * @return The new tile view. */ - private TileView buildTileView( - Tile tile, ViewGroup parentView, boolean trackLoadTask, int titleLines) { + private TileView buildTileView(Tile tile, ViewGroup parentView, boolean trackLoadTask, + int titleLines, boolean condensed) { TileView tileView = (TileView) LayoutInflater.from(parentView.getContext()) .inflate(R.layout.tile_view, parentView, false); - tileView.initialize(tile, titleLines); + tileView.initialize(tile, titleLines, condensed); // Note: It is important that the callbacks below don't keep a reference to the tile or // modify them as there is no guarantee that the same tile would be used to update the view.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileView.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileView.java index 0c36d8e..316e0a4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileView.java
@@ -5,7 +5,9 @@ package org.chromium.chrome.browser.suggestions; import android.content.Context; +import android.content.res.Resources; import android.util.AttributeSet; +import android.view.View; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.TextView; @@ -46,14 +48,43 @@ * after inflation. * @param tile The tile that holds the data to populate this view. * @param titleLines The number of text lines to use for the tile title. + * @param condensed Whether to use a condensed layout. */ - public void initialize(Tile tile, int titleLines) { + public void initialize(Tile tile, int titleLines, boolean condensed) { mTitleView.setLines(titleLines); mUrl = tile.getUrl(); + + // TODO(mvanouwerkerk): Move this code to xml - https://crbug.com/695817. + if (condensed) { + Resources res = getResources(); + + setPadding(0, 0, 0, 0); + LayoutParams tileParams = (LayoutParams) getLayoutParams(); + tileParams.width = res.getDimensionPixelOffset(R.dimen.tile_view_width_condensed); + setLayoutParams(tileParams); + + LayoutParams iconParams = (LayoutParams) mIconView.getLayoutParams(); + iconParams.setMargins(0, + res.getDimensionPixelOffset(R.dimen.tile_view_icon_margin_top_condensed), 0, 0); + mIconView.setLayoutParams(iconParams); + + View highlightView = findViewById(R.id.tile_view_highlight); + LayoutParams highlightParams = (LayoutParams) highlightView.getLayoutParams(); + highlightParams.setMargins(0, + res.getDimensionPixelOffset(R.dimen.tile_view_icon_margin_top_condensed), 0, 0); + highlightView.setLayoutParams(highlightParams); + + LayoutParams titleParams = (LayoutParams) mTitleView.getLayoutParams(); + titleParams.setMargins(0, + res.getDimensionPixelOffset(R.dimen.tile_view_title_margin_top_condensed), 0, + 0); + mTitleView.setLayoutParams(titleParams); + } + renderTile(tile); } - /** @return The url associated to this view. */ + /** @return The url associated with this view. */ public String getUrl() { return mUrl; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/ChromeWebApkHost.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/ChromeWebApkHost.java index 7abec8c..39ed7ca4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/ChromeWebApkHost.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/ChromeWebApkHost.java
@@ -133,6 +133,12 @@ return sGooglePlayInstallState; } + /* Returns whether launching renderer in WebAPK process is enabled by Chrome. */ + public static boolean canLaunchRendererInWebApkProcess() { + return isEnabled() && LibraryLoader.isInitialized() + && nativeCanLaunchRendererInWebApkProcess(); + } + /** * Check the cached value to figure out if the feature is enabled. We have to use the cached * value because native library may not yet been loaded. @@ -179,5 +185,6 @@ } private static native boolean nativeCanUseGooglePlayToInstallWebApk(); + private static native boolean nativeCanLaunchRendererInWebApkProcess(); private static native boolean nativeCanInstallFromUnknownSources(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java index 360b5262..a5a6521 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java
@@ -31,6 +31,9 @@ /** Manages whether to check update for the WebAPK, and starts update check if needed. */ private WebApkUpdateManager mUpdateManager; + /** Indicates whether launching renderer in WebAPK process is enabled. */ + private boolean mCanLaunchRendererInWebApkProcess; + @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); @@ -124,6 +127,7 @@ super.finishNativeInitialization(); if (!isInitialized()) return; getActivityTab().setWebappManifestScope(mWebappInfo.scopeUri().toString()); + mCanLaunchRendererInWebApkProcess = ChromeWebApkHost.canLaunchRendererInWebApkProcess(); } @Override @@ -149,20 +153,14 @@ } @Override - public void onResume() { - super.onResume(); - // WebAPK hosts Chrome's renderer processes by declaring the Chrome's renderer service in - // its AndroidManifest.xml. We set {@link ChildProcessCreationParams} for WebAPK's renderer - // process so the {@link ChildProcessLauncher} knows which application's renderer - // service to connect. - initializeChildProcessCreationParams(true); - } + public void onResumeWithNative() { + super.onResumeWithNative(); - @Override - protected void initializeChildProcessCreationParams() { - // TODO(hanxi): crbug.com/611842. Investigates whether this function works for multiple - // windows or with --site-per-process enabled. - initializeChildProcessCreationParams(true); + // When launching Chrome renderer in WebAPK process is enabled, WebAPK hosts Chrome's + // renderer processes by declaring the Chrome's renderer service in its AndroidManifest.xml + // and sets {@link ChildProcessCreationParams} for WebAPK's renderer process so the + // {@link ChildProcessLauncher} knows which application's renderer service to connect to. + initializeChildProcessCreationParams(mCanLaunchRendererInWebApkProcess); } @Override
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 4f3c701..39c52c9 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -14463,6 +14463,12 @@ <message name="IDS_FLAGS_NTP_CONDENSED_LAYOUT_DESCRIPTION" desc="Description for the flag to enable the condensed New Tab Page layout." translateable="false"> Show a condensed layout on the New Tab Page. </message> + <message name="IDS_FLAGS_NTP_CONDENSED_TILE_LAYOUT_NAME" desc="Name for the flag to enable the condensed tile layout on the New Tab Page." translateable="false"> + Condensed NTP tile layout + </message> + <message name="IDS_FLAGS_NTP_CONDENSED_TILE_LAYOUT_DESCRIPTION" desc="Description for the flag to enable the condensed tile layout on the New Tab Page." translateable="false"> + Show a condensed tile layout on the New Tab Page. + </message> <message name="IDS_FLAGS_NTP_GOOGLE_G_IN_OMNIBOX_NAME" desc="Name for the flag to show a Google G in the omnibox on the New Tab Page." translateable="false"> Google G in New Tab Page omnibox </message>
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp index 13328e25..e73e74a 100644 --- a/chrome/app/settings_strings.grdp +++ b/chrome/app/settings_strings.grdp
@@ -8,6 +8,11 @@ </message> </if> + <!-- Shared across multiple pages --> + <message name="IDS_SETTINGS_MORE_ACTIONS" desc="Tooltip text (shows on hover or for screenreaders) for a button that shows a menu with more actions when clicked or tapped"> + More actions... + </message> + <!-- About Page --> <message name="IDS_SETTINGS_ABOUT_PAGE_BROWSER_VERSION" desc="The text label describing the version of the browser, example: Version 57.0.2937.0 (Developer Build) unknown (64-bit)"> Version <ph name="PRODUCT_VERSION">$1<ex>15.0.865.0</ex></ph> (<ph name="PRODUCT_CHANNEL">$2<ex>Developer Build</ex></ph>) <ph name="PRODUCT_MODIFIER">$3</ph> <ph name="PRODUCT_VERSION_BITS">$4</ph> @@ -319,9 +324,6 @@ </message> <!-- Passwords and Autofill Page --> - <message name="IDS_SETTINGS_OVERFLOW_MENU" desc="Alt text for the overflow button on a list item. Triggers a context menu when clicked."> - Menu - </message> <message name="IDS_SETTINGS_PASSWORDS_AND_AUTOFILL_PAGE_TITLE" desc="Name of the settings page which allows managing passwords and autofill settings."> Passwords and forms </message>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 560bcaf..8a67168 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -1559,6 +1559,7 @@ "//rlz/features", "//services/image_decoder/public/cpp", "//services/preferences/public/interfaces/", + "//services/resource_coordinator:lib", "//services/service_manager/public/cpp", "//services/shape_detection/public/interfaces", "//skia",
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS index b5c99f9..b532bf1 100644 --- a/chrome/browser/DEPS +++ b/chrome/browser/DEPS
@@ -50,6 +50,7 @@ "+services/image_decoder/public/interfaces", "+services/preferences/public/cpp", "+services/preferences/public/interfaces", + "+services/resource_coordinator", "+services/service_manager", "+services/shape_detection/public/interfaces", "+services/ui/public",
diff --git a/chrome/browser/OWNERS b/chrome/browser/OWNERS index 59a9170f..2fa63d69 100644 --- a/chrome/browser/OWNERS +++ b/chrome/browser/OWNERS
@@ -28,7 +28,7 @@ per-file chrome_content_browser_client_browsertest.cc=* per-file chrome_content_browser_client_unittest.cc=* -# Mojo manfiests +# Mojo manifests per-file *manifest_overlay.json=set noparent per-file *manifest_overlay.json=file://ipc/SECURITY_OWNERS
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index e203935..5dd3eb11 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -585,6 +585,21 @@ #endif // OS_ANDROID #if defined(OS_ANDROID) +const FeatureEntry::FeatureParam kCondensedTileLayoutForSmallScreensEnabled[] = + {{"condensed_tile_layout_for_small_screens_enabled", "true"}}; + +const FeatureEntry::FeatureParam kCondensedTileLayoutForLargeScreensEnabled[] = + {{"condensed_tile_layout_for_large_screens_enabled", "true"}}; + +const FeatureEntry::FeatureVariation + kNTPCondensedTileLayoutFeatureVariations[] = { + {"(small screens)", kCondensedTileLayoutForSmallScreensEnabled, + arraysize(kCondensedTileLayoutForSmallScreensEnabled), nullptr}, + {"(large screens)", kCondensedTileLayoutForLargeScreensEnabled, + arraysize(kCondensedTileLayoutForLargeScreensEnabled), nullptr}}; +#endif // OS_ANDROID + +#if defined(OS_ANDROID) const FeatureEntry::Choice kUpdateMenuItemSummaryChoices[] = { {IDS_FLAGS_UPDATE_MENU_ITEM_NO_SUMMARY, "", ""}, {IDS_FLAGS_UPDATE_MENU_ITEM_DEFAULT_SUMMARY, @@ -1948,6 +1963,12 @@ {"ntp-condensed-layout", IDS_FLAGS_NTP_CONDENSED_LAYOUT_NAME, IDS_FLAGS_NTP_CONDENSED_LAYOUT_DESCRIPTION, kOsAndroid, FEATURE_VALUE_TYPE(chrome::android::kNTPCondensedLayoutFeature)}, + {"ntp-condensed-tile-layout", IDS_FLAGS_NTP_CONDENSED_TILE_LAYOUT_NAME, + IDS_FLAGS_NTP_CONDENSED_TILE_LAYOUT_DESCRIPTION, kOsAndroid, + FEATURE_WITH_VARIATIONS_VALUE_TYPE( + chrome::android::kNTPCondensedTileLayoutFeature, + kNTPCondensedTileLayoutFeatureVariations, + ntp_snippets::kStudyName)}, {"ntp-google-g-in-omnibox", IDS_FLAGS_NTP_GOOGLE_G_IN_OMNIBOX_NAME, IDS_FLAGS_NTP_GOOGLE_G_IN_OMNIBOX_DESCRIPTION, kOsAndroid, FEATURE_VALUE_TYPE(chrome::android::NTPShowGoogleGInOmniboxFeature)},
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc index b8aa537..5e66ec0e 100644 --- a/chrome/browser/android/chrome_feature_list.cc +++ b/chrome/browser/android/chrome_feature_list.cc
@@ -55,6 +55,7 @@ &kImprovedA2HS, &kNoCreditCardAbort, &kNTPCondensedLayoutFeature, + &kNTPCondensedTileLayoutFeature, &kNTPFakeOmniboxTextFeature, &kNTPOfflinePagesFeature, &NTPShowGoogleGInOmniboxFeature, @@ -138,6 +139,9 @@ const base::Feature kNTPCondensedLayoutFeature{ "NTPCondensedLayout", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kNTPCondensedTileLayoutFeature{ + "NTPCondensedTileLayout", base::FEATURE_DISABLED_BY_DEFAULT}; + const base::Feature kNTPOfflinePagesFeature{"NTPOfflinePages", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/chrome/browser/android/chrome_feature_list.h b/chrome/browser/android/chrome_feature_list.h index 31f422f..1951766 100644 --- a/chrome/browser/android/chrome_feature_list.h +++ b/chrome/browser/android/chrome_feature_list.h
@@ -27,6 +27,7 @@ extern const base::Feature kImprovedA2HS; extern const base::Feature kNoCreditCardAbort; extern const base::Feature kNTPCondensedLayoutFeature; +extern const base::Feature kNTPCondensedTileLayoutFeature; extern const base::Feature kNTPFakeOmniboxTextFeature; extern const base::Feature kNTPOfflinePagesFeature; extern const base::Feature NTPShowGoogleGInOmniboxFeature;
diff --git a/chrome/browser/android/webapk/chrome_webapk_host.cc b/chrome/browser/android/webapk/chrome_webapk_host.cc index 0d73490..f7653c4e 100644 --- a/chrome/browser/android/webapk/chrome_webapk_host.cc +++ b/chrome/browser/android/webapk/chrome_webapk_host.cc
@@ -13,6 +13,10 @@ // Variations flag to enable installing WebAPKs using Google Play. const char* kPlayInstall = "play_install"; +// Variations flag to enable launching Chrome renderer in WebAPK process. +const char* kLaunchRendererInWebApkProcess = + "launch_renderer_in_webapk_process"; + } // anonymous namespace // static @@ -42,6 +46,15 @@ } // static +jboolean CanLaunchRendererInWebApkProcess( + JNIEnv* env, + const base::android::JavaParamRef<jclass>& clazz) { + return variations::GetVariationParamValueByFeature( + chrome::android::kImprovedA2HS, kLaunchRendererInWebApkProcess) == + "true"; +} + +// static jboolean CanInstallFromUnknownSources( JNIEnv* env, const base::android::JavaParamRef<jclass>& clazz) {
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 1e20b66c..bf9b94a 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -197,6 +197,7 @@ #include "printing/features/features.h" #include "services/image_decoder/public/interfaces/constants.mojom.h" #include "services/preferences/public/interfaces/preferences.mojom.h" +#include "services/resource_coordinator/memory/coordinator/coordinator_impl.h" #include "services/service_manager/public/cpp/interface_provider.h" #include "services/service_manager/public/cpp/interface_registry.h" #include "services/service_manager/public/cpp/service.h" @@ -3097,6 +3098,13 @@ base::Bind(&metrics::LeakDetectorRemoteController::Create), ui_task_runner); #endif + + registry->AddInterface( + base::Bind( + &memory_instrumentation::CoordinatorImpl::BindCoordinatorRequest, + base::Unretained(memory_instrumentation::CoordinatorImpl::GetInstance( + ui_task_runner))), + ui_task_runner); } void ChromeContentBrowserClient::ExposeInterfacesToMediaService( @@ -3193,6 +3201,15 @@ registry->AddInterface( base::Bind(&metrics::CallStackProfileCollector::Create, metrics::CallStackProfileParams::GPU_PROCESS)); + + auto ui_task_runner = content::BrowserThread::GetTaskRunnerForThread( + content::BrowserThread::UI); + registry->AddInterface( + base::Bind( + &memory_instrumentation::CoordinatorImpl::BindCoordinatorRequest, + base::Unretained(memory_instrumentation::CoordinatorImpl::GetInstance( + ui_task_runner))), + ui_task_runner); } void ChromeContentBrowserClient::RegisterInProcessServices(
diff --git a/chrome/browser/chromeos/login/enrollment/enrollment_screen.h b/chrome/browser/chromeos/login/enrollment/enrollment_screen.h index 7cabf4c8..86b343b5 100644 --- a/chrome/browser/chromeos/login/enrollment/enrollment_screen.h +++ b/chrome/browser/chromeos/login/enrollment/enrollment_screen.h
@@ -98,6 +98,10 @@ TestAttributePromptPageGetsLoaded); FRIEND_TEST_ALL_PREFIXES(EnterpriseEnrollmentTest, TestAuthCodeGetsProperlyReceivedFromGaia); + FRIEND_TEST_ALL_PREFIXES(EnterpriseEnrollmentTest, + TestActiveDirectoryEnrollment_Success); + FRIEND_TEST_ALL_PREFIXES(EnterpriseEnrollmentTest, + TestActiveDirectoryEnrollment_UIErrors); FRIEND_TEST_ALL_PREFIXES(HandsOffNetworkScreenTest, RequiresNoInput); FRIEND_TEST_ALL_PREFIXES(HandsOffNetworkScreenTest, ContinueClickedOnlyOnce); FRIEND_TEST_ALL_PREFIXES(EnrollmentScreenUnitTest, Retries);
diff --git a/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc b/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc index 2a75d861..41f22f90 100644 --- a/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc +++ b/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc
@@ -14,6 +14,8 @@ #include "chrome/browser/chromeos/login/ui/login_display_host.h" #include "chrome/browser/chromeos/login/wizard_controller.h" #include "chrome/browser/chromeos/policy/enrollment_status_chromeos.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/upstart_client.h" #include "content/public/test/test_utils.h" using testing::_; @@ -22,6 +24,20 @@ namespace chromeos { +namespace { + +const char kAdMachineNameInput[] = + "document.querySelector('#oauth-enroll-ad-join-ui /deep/ " + "#machineNameInput')"; +const char kAdUsernameInput[] = + "document.querySelector('#oauth-enroll-ad-join-ui /deep/ #userInput')"; +const char kAdPasswordInput[] = + "document.querySelector('#oauth-enroll-ad-join-ui /deep/ #passwordInput')"; +const char kAdTestRealm[] = "test_realm.com"; +const char kAdTestUser[] = "test_user@test_realm.com"; + +} // namespace + class EnterpriseEnrollmentTest : public LoginManagerTest { public: EnterpriseEnrollmentTest() @@ -41,7 +57,7 @@ } using OnSetupEnrollmentHelper = - void (*)(EnterpriseEnrollmentHelperMock* mock); + std::function<void(EnterpriseEnrollmentHelperMock*)>; // The given function will be executed when the next enrollment helper is // created. @@ -75,6 +91,29 @@ "}));"); } + // Submits Active Directory domain join credentials. + void SubmitActiveDirectoryCredentials(const std::string& machine_name, + const std::string& username, + const std::string& password) { + EXPECT_TRUE(IsStepDisplayed("ad-join")); + js_checker().ExpectFalse(std::string(kAdMachineNameInput) + ".hidden"); + js_checker().ExpectFalse(std::string(kAdUsernameInput) + ".hidden"); + js_checker().ExpectFalse(std::string(kAdPasswordInput) + ".hidden"); + const std::string set_machine_name = + std::string(kAdMachineNameInput) + ".value = '" + machine_name + "'"; + const std::string set_username = + std::string(kAdUsernameInput) + ".value = '" + username + "'"; + const std::string set_password = + std::string(kAdPasswordInput) + ".value = '" + password + "'"; + js_checker().ExecuteAsync(set_machine_name); + js_checker().ExecuteAsync(set_username); + js_checker().ExecuteAsync(set_password); + js_checker().Evaluate( + "document.querySelector('#oauth-enroll-ad-join-ui /deep/ " + "#button').fire('tap')"); + ExecutePendingJavaScript(); + } + void DisableAttributePromptUpdate() { AddEnrollmentSetupFunction( [](EnterpriseEnrollmentHelperMock* enrollment_helper) { @@ -103,6 +142,19 @@ }); } + // Forces the Active Directory domain join flow during enterprise enrollment. + void SetupActiveDirectoryJoin() { + AddEnrollmentSetupFunction([this]( + EnterpriseEnrollmentHelperMock* enrollment_helper) { + // Causes the attribute-prompt flow to activate. + EXPECT_CALL(*enrollment_helper, EnrollUsingAuthCode("test_auth_code", _)) + .WillOnce(InvokeWithoutArgs([this]() { + this->enrollment_screen()->JoinDomain(base::BindOnce([]( + const std::string& realm) { EXPECT_EQ(kAdTestRealm, realm); })); + })); + }); + } + // Fills out the UI with device attribute information and submits it. void SubmitAttributePromptUpdate() { // Fill out the attribute prompt info and submit it. @@ -229,4 +281,73 @@ enrollment_screen()->enrollment_helper_.reset(); } +// Shows the enrollment screen and mocks the enrollment helper to show Active +// Directory domain join screen. Verifies the domain join screen is displayed. +// Submits Active Directory credentials. Verifies that the AuthpolicyClient +// calls us back with the correct realm. +IN_PROC_BROWSER_TEST_F(EnterpriseEnrollmentTest, + TestActiveDirectoryEnrollment_Success) { + ShowEnrollmentScreen(); + DisableAttributePromptUpdate(); + SetupActiveDirectoryJoin(); + SubmitEnrollmentCredentials(); + + chromeos::DBusThreadManager::Get() + ->GetUpstartClient() + ->StartAuthPolicyService(); + + SubmitActiveDirectoryCredentials("machine_name", kAdTestUser, "password"); + EXPECT_FALSE(IsStepDisplayed("ad-join")); + + CompleteEnrollment(); + // Verify that the success page is displayed. + EXPECT_TRUE(IsStepDisplayed("success")); + EXPECT_FALSE(IsStepDisplayed("error")); + + // We have to remove the enrollment_helper before the dtor gets called. + enrollment_screen()->enrollment_helper_.reset(); +} + +// Shows the enrollment screen and mocks the enrollment helper to show Active +// Directory domain join screen. Verifies the domain join screen is displayed. +// Submits Active Directory different incorrect credentials. Verifies that the +// correct error is displayed. +IN_PROC_BROWSER_TEST_F(EnterpriseEnrollmentTest, + TestActiveDirectoryEnrollment_UIErrors) { + ShowEnrollmentScreen(); + SetupActiveDirectoryJoin(); + SubmitEnrollmentCredentials(); + + chromeos::DBusThreadManager::Get() + ->GetUpstartClient() + ->StartAuthPolicyService(); + + // Checking error in case of empty password. Whether password is not empty + // being checked in the UI. Machine name length is checked after that in the + // authpolicyd. + SubmitActiveDirectoryCredentials("too_long_machine_name", kAdTestUser, ""); + EXPECT_TRUE(IsStepDisplayed("ad-join")); + js_checker().ExpectFalse(std::string(kAdMachineNameInput) + ".isInvalid"); + js_checker().ExpectFalse(std::string(kAdUsernameInput) + ".isInvalid"); + js_checker().ExpectTrue(std::string(kAdPasswordInput) + ".isInvalid"); + + // Checking error in case of too long machine name. + SubmitActiveDirectoryCredentials("too_long_machine_name", kAdTestUser, + "password"); + EXPECT_TRUE(IsStepDisplayed("ad-join")); + js_checker().ExpectTrue(std::string(kAdMachineNameInput) + ".isInvalid"); + js_checker().ExpectFalse(std::string(kAdUsernameInput) + ".isInvalid"); + js_checker().ExpectFalse(std::string(kAdPasswordInput) + ".isInvalid"); + + // Checking error in case of bad username (without realm). + SubmitActiveDirectoryCredentials("machine_name", "test_user", "password"); + EXPECT_TRUE(IsStepDisplayed("ad-join")); + js_checker().ExpectFalse(std::string(kAdMachineNameInput) + ".isInvalid"); + js_checker().ExpectTrue(std::string(kAdUsernameInput) + ".isInvalid"); + js_checker().ExpectFalse(std::string(kAdPasswordInput) + ".isInvalid"); + + // We have to remove the enrollment_helper before the dtor gets called. + enrollment_screen()->enrollment_helper_.reset(); +} + } // namespace chromeos
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.html b/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.html index 396b7bcc..079cdc3 100644 --- a/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.html +++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.html
@@ -33,7 +33,7 @@ <span hidden$="[[!device.connecting]]">$i18n{bluetoothConnecting}</span> <div hidden$="[[!device.paired]]"> <paper-icon-button icon="cr:more-vert" on-tap="onMenuButtonTap_" - tabindex$="[[tabindex]]"> + tabindex$="[[tabindex]]" title="$i18n{moreActions}"> </paper-icon-button> <dialog id="dotsMenu" is="cr-action-menu"> <button class="dropdown-item" role="option"
diff --git a/chrome/browser/resources/settings/certificate_manager_page/certificate_subentry.html b/chrome/browser/resources/settings/certificate_manager_page/certificate_subentry.html index 35b41ee..5ad62f5 100644 --- a/chrome/browser/resources/settings/certificate_manager_page/certificate_subentry.html +++ b/chrome/browser/resources/settings/certificate_manager_page/certificate_subentry.html
@@ -31,7 +31,7 @@ </div> <div class="name">[[model.name]]</div> <paper-icon-button id="dots" icon="cr:more-vert" - on-tap="onDotsTap_"></paper-icon-button> + title="$i18n{moreActions}" on-tap="onDotsTap_"></paper-icon-button> <template is="cr-lazy-render" id="menu"> <dialog is="cr-action-menu"> <button class="dropdown-item" role="option" id="view"
diff --git a/chrome/browser/resources/settings/internet_page/internet_known_networks_page.html b/chrome/browser/resources/settings/internet_page/internet_known_networks_page.html index e5482d8..07f09756 100644 --- a/chrome/browser/resources/settings/internet_page/internet_known_networks_page.html +++ b/chrome/browser/resources/settings/internet_page/internet_known_networks_page.html
@@ -22,7 +22,8 @@ <div class="settings-box self-stretch"> <div class="start">[[item.Name]]</div> <paper-icon-button preferred icon="cr:more-vert" - tabindex$="[[tabindex]]" on-tap="onMenuButtonTap_"> + tabindex$="[[tabindex]]" on-tap="onMenuButtonTap_" + title="$i18n{moreActions}"> </paper-icon-button> </div> </template> @@ -35,7 +36,7 @@ <div class="settings-box self-stretch"> <div class="start">[[item.Name]]</div> <paper-icon-button icon="cr:more-vert" tabindex$="[[tabindex]]" - on-tap="onMenuButtonTap_"> + on-tap="onMenuButtonTap_" title="$i18n{moreActions}"> </paper-icon-button> </div> </template>
diff --git a/chrome/browser/resources/settings/languages_page/languages_page.html b/chrome/browser/resources/settings/languages_page/languages_page.html index 078c9a6..2271af5 100644 --- a/chrome/browser/resources/settings/languages_page/languages_page.html +++ b/chrome/browser/resources/settings/languages_page/languages_page.html
@@ -122,7 +122,8 @@ </template> </if> <paper-icon-button id="more-[[item.language.code]]" - icon="cr:more-vert" on-tap="onDotsTap_"> + icon="cr:more-vert" on-tap="onDotsTap_" + title="$i18n{moreActions}"> </paper-icon-button> </div> </template>
diff --git a/chrome/browser/resources/settings/on_startup_page/startup_url_entry.html b/chrome/browser/resources/settings/on_startup_page/startup_url_entry.html index 1a1c0893..1a68b89d 100644 --- a/chrome/browser/resources/settings/on_startup_page/startup_url_entry.html +++ b/chrome/browser/resources/settings/on_startup_page/startup_url_entry.html
@@ -24,7 +24,8 @@ </div> <template is="dom-if" if="[[editable]]"> <paper-icon-button id="dots" icon="cr:more-vert" - tabindex$="[[tabindex]]" on-tap="onDotsTap_"> + tabindex$="[[tabindex]]" on-tap="onDotsTap_" + title="$i18n{moreActions}"> </paper-icon-button> <template is="cr-lazy-render" id="menu"> <dialog is="cr-action-menu">
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.html b/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.html index 8a3fc74c..fd464fc 100644 --- a/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.html +++ b/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.html
@@ -77,7 +77,7 @@ </div> <template is="dom-if" if="[[item.metadata.isLocal]]"> <paper-icon-button id="addressMenu" icon="cr:more-vert" - on-tap="onAddressMenuTap_" alt="$i18n{overflowMenu}"> + on-tap="onAddressMenuTap_" title="$i18n{moreActions}"> </paper-icon-button> </template> <template is="dom-if" if="[[!item.metadata.isLocal]]"> @@ -135,7 +135,7 @@ class="expiration-date">[[expiration_(item)]]</div> <template is="dom-if" if="[[item.metadata.isLocal]]"> <paper-icon-button id="creditCardMenu" icon="cr:more-vert" - on-tap="onCreditCardMenuTap_" alt="$i18n{overflowMenu}"> + on-tap="onCreditCardMenuTap_" title="$i18n{moreActions}"> </paper-icon-button> </template> <template is="dom-if" if="[[!item.metadata.isLocal]]">
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html index b857b200..04806d4 100644 --- a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html +++ b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html
@@ -100,7 +100,7 @@ value="[[getEmptyPassword_(item.numCharactersInPassword)]]"> </input> <paper-icon-button id="passwordMenu" icon="cr:more-vert" - on-tap="onPasswordMenuTap_" alt="$i18n{overflowMenu}" + on-tap="onPasswordMenuTap_" title="$i18n{moreActions}" tabindex$="[[tabIndex]]"> </paper-icon-button> </div> @@ -137,7 +137,7 @@ <paper-icon-button id="removeExceptionButton" icon="cr:close" on-tap="onRemoveExceptionButtonTap_" tabindex$="[[tabIndex]]" - alt="$i18n{deletePasswordException}"> + title="$i18n{deletePasswordException}"> </paper-icon-button> </div> </template>
diff --git a/chrome/browser/resources/settings/printing_page/cups_printers_list.html b/chrome/browser/resources/settings/printing_page/cups_printers_list.html index e3d456fe..8a7f683c 100644 --- a/chrome/browser/resources/settings/printing_page/cups_printers_list.html +++ b/chrome/browser/resources/settings/printing_page/cups_printers_list.html
@@ -39,7 +39,8 @@ <span class="name" id="printer-name">[[item.printerName]]</span> <!--TODO(xdai): Add icon for enterprise CUPS printer. --> </div> - <paper-icon-button icon="cr:more-vert" on-tap="onOpenActionMenuTap_"> + <paper-icon-button icon="cr:more-vert" on-tap="onOpenActionMenuTap_" + title="$i18n{moreActions}"> </paper-icon-button> </div> </template>
diff --git a/chrome/browser/resources/settings/search_engines_page/omnibox_extension_entry.html b/chrome/browser/resources/settings/search_engines_page/omnibox_extension_entry.html index 5496507..68407ef 100644 --- a/chrome/browser/resources/settings/search_engines_page/omnibox_extension_entry.html +++ b/chrome/browser/resources/settings/search_engines_page/omnibox_extension_entry.html
@@ -26,7 +26,7 @@ </div> <div class="keyword-column">[[engine.keyword]]</div> <paper-icon-button icon="cr:more-vert" tabindex$="[[tabindex]]" - on-tap="onDotsTap_"> + on-tap="onDotsTap_" title="$i18n{moreActions}"> </paper-icon-button> <dialog is="cr-action-menu"> <button class="dropdown-item" role="option" on-tap="onManageTap_"
diff --git a/chrome/browser/resources/settings/search_engines_page/search_engine_entry.html b/chrome/browser/resources/settings/search_engines_page/search_engine_entry.html index 600e4c54..033e9fae 100644 --- a/chrome/browser/resources/settings/search_engines_page/search_engine_entry.html +++ b/chrome/browser/resources/settings/search_engines_page/search_engine_entry.html
@@ -59,7 +59,7 @@ <div id="keyword-column">[[engine.keyword]]</div> <div id="url-column" class="text-elide">[[engine.url]]</div> <paper-icon-button icon="cr:more-vert" tabindex$="[[tabindex]]" - on-tap="onDotsTap_"> + on-tap="onDotsTap_" title="$i18n{moreActions}"> </paper-icon-button> <dialog is="cr-action-menu"> <button class="dropdown-item" role="option" on-tap="onMakeDefaultTap_"
diff --git a/chrome/browser/resources/settings/site_settings/protocol_handlers.html b/chrome/browser/resources/settings/site_settings/protocol_handlers.html index 58a391e..33fbfec 100644 --- a/chrome/browser/resources/settings/site_settings/protocol_handlers.html +++ b/chrome/browser/resources/settings/site_settings/protocol_handlers.html
@@ -49,7 +49,7 @@ </div> <paper-icon-button icon="cr:more-vert" on-tap="showMenu_" - class="dropdown-trigger"> + class="dropdown-trigger" title="$i18n{moreActions}"> </paper-icon-button> </div>
diff --git a/chrome/browser/resources/settings/site_settings/site_list.html b/chrome/browser/resources/settings/site_settings/site_list.html index 6f2117f..3fa1a14 100644 --- a/chrome/browser/resources/settings/site_settings/site_list.html +++ b/chrome/browser/resources/settings/site_settings/site_list.html
@@ -85,7 +85,7 @@ <paper-icon-button id="dots" icon="cr:more-vert" hidden="[[isActionMenuHidden_(item.source)]]" - on-tap="onShowActionMenuTap_"> + on-tap="onShowActionMenuTap_" title="$i18n{moreActions}"> </paper-icon-button> <template is="dom-if" if="[[enableSiteSettings_]]"> <div on-tap="onOriginTap_" actionable>
diff --git a/chrome/browser/resources/settings/site_settings/usb_devices.html b/chrome/browser/resources/settings/site_settings/usb_devices.html index 6abb7e3b0..57a312c 100644 --- a/chrome/browser/resources/settings/site_settings/usb_devices.html +++ b/chrome/browser/resources/settings/site_settings/usb_devices.html
@@ -31,7 +31,7 @@ <div class="middle">[[item.origin]]</div> <paper-icon-button icon="cr:more-vert" on-tap="showMenu_" - class="dropdown-trigger"> + class="dropdown-trigger" title="$i18n{moreActions}"> </paper-icon-button> </div> </div>
diff --git a/chrome/browser/ui/app_list/search/app_search_provider.cc b/chrome/browser/ui/app_list/search/app_search_provider.cc index 9f0642c..6e80660 100644 --- a/chrome/browser/ui/app_list/search/app_search_provider.cc +++ b/chrome/browser/ui/app_list/search/app_search_provider.cc
@@ -44,7 +44,11 @@ namespace { // The size of each step unlaunched apps should increase their relevance by. -const double kUnlaunchedAppRelevanceStepSize = 0.0001; +constexpr double kUnlaunchedAppRelevanceStepSize = 0.0001; + +// The minimum capacity we reserve in the Apps container which will be filled +// with extensions and ARC apps, to avoid successive reallocation. +constexpr size_t kMinimumReservedAppsContainerCapacity = 60U; } namespace app_list { @@ -58,21 +62,31 @@ const base::Time& install_time) : data_source_(data_source), id_(id), - indexed_name_(base::UTF8ToUTF16(name)), + name_(base::UTF8ToUTF16(name)), last_launch_time_(last_launch_time), install_time_(install_time) {} ~App() {} + TokenizedString* GetTokenizedIndexedName() { + // Tokenizing a string is expensive. Don't pay the price for it at + // construction of every App, but rather, only when needed (i.e. when the + // query is not empty and cache the result. + if (!tokenized_indexed_name_) + tokenized_indexed_name_ = base::MakeUnique<TokenizedString>(name_); + return tokenized_indexed_name_.get(); + } + AppSearchProvider::DataSource* data_source() { return data_source_; } const std::string& id() const { return id_; } - const TokenizedString& indexed_name() const { return indexed_name_; } + const base::string16& name() const { return name_; } const base::Time& last_launch_time() const { return last_launch_time_; } const base::Time& install_time() const { return install_time_; } private: AppSearchProvider::DataSource* data_source_; + std::unique_ptr<TokenizedString> tokenized_indexed_name_; const std::string id_; - const TokenizedString indexed_name_; + const base::string16 name_; const base::Time last_launch_time_; const base::Time install_time_; @@ -131,8 +145,8 @@ AppListControllerDelegate* list_controller, AppListItemList* top_level_item_list, bool is_recommended) override { - return std::unique_ptr<AppResult>(new ExtensionAppResult( - profile(), app_id, list_controller, is_recommended)); + return base::MakeUnique<ExtensionAppResult>( + profile(), app_id, list_controller, is_recommended); } // extensions::ExtensionRegistryObserver overrides: @@ -165,11 +179,10 @@ continue; } - std::unique_ptr<AppSearchProvider::App> app(new AppSearchProvider::App( + apps->emplace_back(base::MakeUnique<AppSearchProvider::App>( this, extension->id(), extension->short_name(), prefs->GetLastLaunchTime(extension->id()), prefs->GetInstallTime(extension->id()))); - apps->push_back(std::move(app)); } } @@ -210,10 +223,9 @@ if (!app_info->launchable || !app_info->showInLauncher) continue; - std::unique_ptr<AppSearchProvider::App> app(new AppSearchProvider::App( + apps->emplace_back(base::MakeUnique<AppSearchProvider::App>( this, app_id, app_info->name, app_info->last_launch_time, app_info->install_time)); - apps->push_back(std::move(app)); } } @@ -222,8 +234,8 @@ AppListControllerDelegate* list_controller, AppListItemList* top_level_item_list, bool is_recommended) override { - return std::unique_ptr<AppResult>( - new ArcAppResult(profile(), app_id, list_controller, is_recommended)); + return base::MakeUnique<ArcAppResult>(profile(), app_id, list_controller, + is_recommended); } // ArcAppListPrefs::Observer overrides: @@ -256,16 +268,12 @@ top_level_item_list_(top_level_item_list), clock_(std::move(clock)), update_results_factory_(this) { - data_sources_.push_back( - std::unique_ptr<DataSource>(new ExtensionDataSource(profile, this))); + data_sources_.emplace_back( + base::MakeUnique<ExtensionDataSource>(profile, this)); #if defined(OS_CHROMEOS) - if (arc::IsArcAllowedForProfile(profile)) { - data_sources_.push_back( - std::unique_ptr<DataSource>(new ArcDataSource(profile, this))); - } + if (arc::IsArcAllowedForProfile(profile)) + data_sources_.emplace_back(base::MakeUnique<ArcDataSource>(profile, this)); #endif - - RefreshApps(); } AppSearchProvider::~AppSearchProvider() {} @@ -273,12 +281,10 @@ void AppSearchProvider::Start(bool /*is_voice_query*/, const base::string16& query) { query_ = query; - ClearResults(); - - bool show_recommendations = query.empty(); + const bool show_recommendations = query.empty(); // Refresh list of apps to ensure we have the latest launch time information. // This will also cause the results to update. - if (show_recommendations) + if (show_recommendations || apps_.empty()) RefreshApps(); UpdateResults(); @@ -289,27 +295,29 @@ void AppSearchProvider::RefreshApps() { apps_.clear(); - for (auto& data_source : data_sources_) { + apps_.reserve(kMinimumReservedAppsContainerCapacity); + for (auto& data_source : data_sources_) data_source->AddApps(&apps_); - } } void AppSearchProvider::UpdateResults() { - const TokenizedString query_terms(query_); - bool show_recommendations = query_.empty(); - ClearResults(); + const bool show_recommendations = query_.empty(); + // No need to clear the current results as we will swap them with + // |new_results| at the end. + SearchProvider::Results new_results; + const size_t apps_size = apps_.size(); + new_results.reserve(apps_size); if (show_recommendations) { // Build a map of app ids to their position in the app list. std::map<std::string, size_t> id_to_app_list_index; - for (size_t i = 0; i < top_level_item_list_->item_count(); ++i) { + for (size_t i = 0; i < top_level_item_list_->item_count(); ++i) id_to_app_list_index[top_level_item_list_->item_at(i)->id()] = i; - } for (auto& app : apps_) { std::unique_ptr<AppResult> result = app->data_source()->CreateResult( app->id(), list_controller_, top_level_item_list_, true); - result->set_title(app->indexed_name().text()); + result->set_title(app->name()); // Use the app list order to tiebreak apps that have never been launched. // The apps that have been installed or launched recently should be @@ -318,34 +326,37 @@ ? app->install_time() : app->last_launch_time(); if (time.is_null()) { - auto it = id_to_app_list_index.find(app->id()); + const auto& it = id_to_app_list_index.find(app->id()); // If it's in a folder, it won't be in |id_to_app_list_index|. Rank // those as if they are at the end of the list. - size_t app_list_index = - it == id_to_app_list_index.end() ? apps_.size() : (*it).second; - if (app_list_index > apps_.size()) - app_list_index = apps_.size(); + const size_t app_list_index = (it == id_to_app_list_index.end()) + ? apps_size + : std::min(apps_size, it->second); result->set_relevance(kUnlaunchedAppRelevanceStepSize * - (apps_.size() - app_list_index)); + (apps_size - app_list_index)); } else { result->UpdateFromLastLaunchedOrInstalledTime(clock_->Now(), time); } - Add(std::move(result)); + new_results.emplace_back(std::move(result)); } } else { + const TokenizedString query_terms(query_); for (auto& app : apps_) { std::unique_ptr<AppResult> result = app->data_source()->CreateResult( app->id(), list_controller_, top_level_item_list_, false); TokenizedStringMatch match; - if (!match.Calculate(query_terms, app->indexed_name())) + TokenizedString* indexed_name = app->GetTokenizedIndexedName(); + if (!match.Calculate(query_terms, *indexed_name)) continue; - result->UpdateFromMatch(app->indexed_name(), match); - Add(std::move(result)); + result->UpdateFromMatch(*indexed_name, match); + new_results.emplace_back(std::move(result)); } } + SwapResults(&new_results); + update_results_factory_.InvalidateWeakPtrs(); }
diff --git a/chrome/browser/ui/app_list/search/app_search_provider.h b/chrome/browser/ui/app_list/search/app_search_provider.h index 4273c2e..a957ce41a 100644 --- a/chrome/browser/ui/app_list/search/app_search_provider.h +++ b/chrome/browser/ui/app_list/search/app_search_provider.h
@@ -28,7 +28,7 @@ public: class App; class DataSource; - typedef std::vector<std::unique_ptr<App>> Apps; + using Apps = std::vector<std::unique_ptr<App>>; AppSearchProvider(Profile* profile, AppListControllerDelegate* list_controller,
diff --git a/chrome/browser/ui/app_list/search/app_search_provider_unittest.cc b/chrome/browser/ui/app_list/search/app_search_provider_unittest.cc index 5ee16d4..5fe60f5 100644 --- a/chrome/browser/ui/app_list/search/app_search_provider_unittest.cc +++ b/chrome/browser/ui/app_list/search/app_search_provider_unittest.cc
@@ -73,9 +73,8 @@ // Sort results by relevance. std::vector<SearchResult*> sorted_results; - std::copy(app_search_->results().begin(), - app_search_->results().end(), - std::back_inserter(sorted_results)); + for (const auto& result : app_search_->results()) + sorted_results.emplace_back(result.get()); std::sort(sorted_results.begin(), sorted_results.end(), &MoreRelevant); std::string result_str;
diff --git a/chrome/browser/ui/app_list/search/arc_app_result.cc b/chrome/browser/ui/app_list/search/arc_app_result.cc index 5079b99..7467dab7 100644 --- a/chrome/browser/ui/app_list/search/arc_app_result.cc +++ b/chrome/browser/ui/app_list/search/arc_app_result.cc
@@ -56,9 +56,9 @@ } std::unique_ptr<SearchResult> ArcAppResult::Duplicate() const { - std::unique_ptr<SearchResult> copy( - new ArcAppResult(profile(), app_id(), controller(), - display_type() == DISPLAY_RECOMMENDATION)); + std::unique_ptr<SearchResult> copy = + base::MakeUnique<ArcAppResult>(profile(), app_id(), controller(), + display_type() == DISPLAY_RECOMMENDATION); copy->set_title(title()); copy->set_title_tags(title_tags()); copy->set_relevance(relevance());
diff --git a/chrome/browser/ui/app_list/search/extension_app_result.cc b/chrome/browser/ui/app_list/search/extension_app_result.cc index 877fc96..52ff6ab 100644 --- a/chrome/browser/ui/app_list/search/extension_app_result.cc +++ b/chrome/browser/ui/app_list/search/extension_app_result.cc
@@ -90,9 +90,9 @@ } std::unique_ptr<SearchResult> ExtensionAppResult::Duplicate() const { - std::unique_ptr<SearchResult> copy( - new ExtensionAppResult(profile(), app_id(), controller(), - display_type() == DISPLAY_RECOMMENDATION)); + std::unique_ptr<SearchResult> copy = base::MakeUnique<ExtensionAppResult>( + profile(), app_id(), controller(), + display_type() == DISPLAY_RECOMMENDATION); copy->set_title(title()); copy->set_title_tags(title_tags()); copy->set_relevance(relevance());
diff --git a/chrome/browser/ui/app_list/search/launcher_search/launcher_search_provider.cc b/chrome/browser/ui/app_list/search/launcher_search/launcher_search_provider.cc index 8f8871f..cf331fb 100644 --- a/chrome/browser/ui/app_list/search/launcher_search/launcher_search_provider.cc +++ b/chrome/browser/ui/app_list/search/launcher_search/launcher_search_provider.cc
@@ -16,8 +16,8 @@ namespace { -const int kLauncherSearchProviderQueryDelayInMs = 100; -const int kLauncherSearchProviderMaxResults = 6; +constexpr int kLauncherSearchProviderQueryDelayInMs = 100; +constexpr int kLauncherSearchProviderMaxResults = 6; } // namespace @@ -64,11 +64,12 @@ extension_results_[extension_id] = std::move(results); // Update results with other extension results. - ClearResults(); + SearchProvider::Results new_results; for (const auto& item : extension_results_) { for (const auto& result : item.second) - Add(result->Duplicate()); + new_results.emplace_back(result->Duplicate()); } + SwapResults(&new_results); } void LauncherSearchProvider::DelayQuery(const base::Closure& closure) {
diff --git a/chrome/browser/ui/app_list/search/omnibox_provider.cc b/chrome/browser/ui/app_list/search/omnibox_provider.cc index e9f990d..52c8c9a 100644 --- a/chrome/browser/ui/app_list/search/omnibox_provider.cc +++ b/chrome/browser/ui/app_list/search/omnibox_provider.cc
@@ -47,21 +47,20 @@ } void OmniboxProvider::PopulateFromACResult(const AutocompleteResult& result) { - ClearResults(); - for (ACMatches::const_iterator it = result.begin(); - it != result.end(); - ++it) { - if (!it->destination_url.is_valid()) + SearchProvider::Results new_results; + new_results.reserve(result.size()); + for (const AutocompleteMatch& match : result) { + if (!match.destination_url.is_valid()) continue; - Add(std::unique_ptr<SearchResult>(new OmniboxResult( - profile_, list_controller_, controller_.get(), is_voice_query_, *it))); + new_results.emplace_back(base::MakeUnique<OmniboxResult>( + profile_, list_controller_, controller_.get(), is_voice_query_, match)); } + SwapResults(&new_results); } void OmniboxProvider::OnResultChanged(bool default_match_changed) { - const AutocompleteResult& result = controller_->result(); - PopulateFromACResult(result); + PopulateFromACResult(controller_->result()); } } // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/search_controller_factory.cc b/chrome/browser/ui/app_list/search/search_controller_factory.cc index 1239302..3506a1f 100644 --- a/chrome/browser/ui/app_list/search/search_controller_factory.cc +++ b/chrome/browser/ui/app_list/search/search_controller_factory.cc
@@ -33,18 +33,19 @@ namespace { // Maximum number of results to show in each mixer group. -const size_t kMaxAppsGroupResults = 8; -const size_t kMaxOmniboxResults = 4; -const size_t kMaxWebstoreResults = 2; -const size_t kMaxSuggestionsResults = 6; +constexpr size_t kMaxAppsGroupResults = 8; +constexpr size_t kMaxOmniboxResults = 4; +constexpr size_t kMaxWebstoreResults = 2; +constexpr size_t kMaxSuggestionsResults = 6; #if defined(OS_CHROMEOS) -const size_t kMaxLauncherSearchResults = 2; +constexpr size_t kMaxLauncherSearchResults = 2; #endif // Constants related to the SuggestionsService in AppList field trial. -const char kSuggestionsProviderFieldTrialName[] = "SuggestionsAppListProvider"; -const char kSuggestionsProviderFieldTrialEnabledPrefix[] = "Enabled"; +constexpr char kSuggestionsProviderFieldTrialName[] = + "SuggestionsAppListProvider"; +constexpr char kSuggestionsProviderFieldTrialEnabledPrefix[] = "Enabled"; // Returns whether the user is part of a group where the Suggestions provider is // enabled. @@ -61,9 +62,10 @@ Profile* profile, AppListModel* model, AppListControllerDelegate* list_controller) { - std::unique_ptr<SearchController> controller( - new SearchController(model->search_box(), model->results(), - HistoryFactory::GetForBrowserContext(profile))); + std::unique_ptr<SearchController> controller = + base::MakeUnique<SearchController>( + model->search_box(), model->results(), + HistoryFactory::GetForBrowserContext(profile)); // Add mixer groups. There are three main groups: apps, webstore and // omnibox. Each group has a "soft" maximum number of results. However, if @@ -76,22 +78,21 @@ // Add search providers. controller->AddProvider( apps_group_id, - std::unique_ptr<SearchProvider>(new AppSearchProvider( + base::MakeUnique<AppSearchProvider>( profile, list_controller, base::MakeUnique<base::DefaultClock>(), - model->top_level_item_list()))); - controller->AddProvider(omnibox_group_id, - std::unique_ptr<SearchProvider>( - new OmniboxProvider(profile, list_controller))); - controller->AddProvider(webstore_group_id, - std::unique_ptr<SearchProvider>( - new WebstoreProvider(profile, list_controller))); + model->top_level_item_list())); + controller->AddProvider( + omnibox_group_id, + base::MakeUnique<OmniboxProvider>(profile, list_controller)); + controller->AddProvider( + webstore_group_id, + base::MakeUnique<WebstoreProvider>(profile, list_controller)); if (IsSuggestionsSearchProviderEnabled()) { size_t suggestions_group_id = controller->AddGroup(kMaxSuggestionsResults, 1.0); controller->AddProvider( suggestions_group_id, - std::unique_ptr<SearchProvider>( - new SuggestionsSearchProvider(profile, list_controller))); + base::MakeUnique<SuggestionsSearchProvider>(profile, list_controller)); } // LauncherSearchProvider is added only when flag is enabled, not in guest @@ -101,9 +102,8 @@ !profile->IsGuestSession()) { size_t search_api_group_id = controller->AddGroup(kMaxLauncherSearchResults, 1.0); - controller->AddProvider( - search_api_group_id, - std::unique_ptr<SearchProvider>(new LauncherSearchProvider(profile))); + controller->AddProvider(search_api_group_id, + base::MakeUnique<LauncherSearchProvider>(profile)); } #endif
diff --git a/chrome/browser/ui/app_list/search/suggestions/suggestions_search_provider_unittest.cc b/chrome/browser/ui/app_list/search/suggestions/suggestions_search_provider_unittest.cc index 1adf31c..bea13e27b 100644 --- a/chrome/browser/ui/app_list/search/suggestions/suggestions_search_provider_unittest.cc +++ b/chrome/browser/ui/app_list/search/suggestions/suggestions_search_provider_unittest.cc
@@ -76,9 +76,10 @@ suggestions_search_->Start(false, base::UTF8ToUTF16(query)); // Sort results from most to least relevant. - std::vector<SearchResult*> sorted_results( - suggestions_search_->results().begin(), - suggestions_search_->results().end()); + std::vector<SearchResult*> sorted_results; + sorted_results.reserve(suggestions_search_->results().size()); + for (const auto& result : suggestions_search_->results()) + sorted_results.emplace_back(result.get()); std::sort(sorted_results.begin(), sorted_results.end(), &MostRelevant); std::string result_str;
diff --git a/chrome/browser/ui/app_list/search/webstore/webstore_provider.cc b/chrome/browser/ui/app_list/search/webstore/webstore_provider.cc index 044cfac..12b0c575 100644 --- a/chrome/browser/ui/app_list/search/webstore/webstore_provider.cc +++ b/chrome/browser/ui/app_list/search/webstore/webstore_provider.cc
@@ -96,8 +96,7 @@ // Add a placeholder result which when clicked will run the user's query in a // browser. This placeholder is removed when the search results arrive. - Add(std::unique_ptr<SearchResult>( - new SearchWebstoreResult(profile_, controller_, query_))); + Add(base::MakeUnique<SearchWebstoreResult>(profile_, controller_, query_)); } void WebstoreProvider::Stop() { @@ -192,8 +191,8 @@ if (!match.Calculate(query, title)) return std::unique_ptr<SearchResult>(); - std::unique_ptr<SearchResult> result(new WebstoreResult( - profile_, app_id, icon_url, is_paid, item_type, controller_)); + std::unique_ptr<SearchResult> result = base::MakeUnique<WebstoreResult>( + profile_, app_id, icon_url, is_paid, item_type, controller_); result->UpdateFromMatch(title, match); return result; }
diff --git a/chrome/browser/ui/app_list/search/webstore/webstore_provider_browsertest.cc b/chrome/browser/ui/app_list/search/webstore/webstore_provider_browsertest.cc index 6e10205..b316a28 100644 --- a/chrome/browser/ui/app_list/search/webstore/webstore_provider_browsertest.cc +++ b/chrome/browser/ui/app_list/search/webstore/webstore_provider_browsertest.cc
@@ -219,7 +219,7 @@ size_t expected_result_size) { ASSERT_EQ(expected_result_size, webstore_provider_->results().size()); for (size_t i = 0; i < expected_result_size; ++i) { - const SearchResult* result = webstore_provider_->results()[i]; + const SearchResult* result = (webstore_provider_->results()[i]).get(); // A search for an installed app will return a general webstore search // instead of an app in the webstore. if (!strcmp(expected_results[i].id, kWebstoreUrlPlaceholder)) {
diff --git a/chrome/browser/ui/ash/OWNERS b/chrome/browser/ui/ash/OWNERS index 2e0c4bf..8437fb3 100644 --- a/chrome/browser/ui/ash/OWNERS +++ b/chrome/browser/ui/ash/OWNERS
@@ -3,3 +3,5 @@ oshima@chromium.org sky@chromium.org stevenjb@chromium.org + +# COMPONENT: UI>Shell
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc index efd0662..62a45c9d 100644 --- a/chrome/browser/ui/autofill/chrome_autofill_client.cc +++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -331,15 +331,7 @@ ContentAutofillDriverFactory::FromWebContents(web_contents()); DCHECK(factory); - for (content::RenderFrameHost* frame : web_contents()->GetAllFrames()) { - // No need to notify non-live frames. - // And actually they have no corresponding drivers in the factory's map. - if (!frame->IsRenderFrameLive()) - continue; - ContentAutofillDriver* driver = factory->DriverForFrame(frame); - DCHECK(driver); - driver->NotifyFirstUserGestureObservedInTab(); - } + factory->OnFirstUserGestureObserved(); } bool ChromeAutofillClient::IsContextSecure() {
diff --git a/chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.mm b/chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.mm index 16e764eb..be069af5 100644 --- a/chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.mm +++ b/chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.mm
@@ -494,7 +494,7 @@ // Add "?" icon with tooltip. storageTooltip_.reset([[AutofillTooltipController alloc] - initWithArrowLocation:info_bubble::kTopRight]); + initWithArrowLocation:info_bubble::kTopTrailing]); [storageTooltip_ setImage:ui::ResourceBundle::GetSharedInstance() .GetNativeImageNamed(IDR_AUTOFILL_TOOLTIP_ICON) .ToNSImage()];
diff --git a/chrome/browser/ui/cocoa/base_bubble_controller.mm b/chrome/browser/ui/cocoa/base_bubble_controller.mm index ffaae11..2768e53 100644 --- a/chrome/browser/ui/cocoa/base_bubble_controller.mm +++ b/chrome/browser/ui/cocoa/base_bubble_controller.mm
@@ -114,7 +114,7 @@ self)); } - [bubble_ setArrowLocation:info_bubble::kTopRight]; + [bubble_ setArrowLocation:info_bubble::kTopTrailing]; } - (void)dealloc { @@ -411,11 +411,13 @@ info_bubble::kBubbleArrowWidth / 2.0, 0); offsets = [[parentWindow_ contentView] convertSize:offsets toView:nil]; switch ([bubble_ arrowLocation]) { - case info_bubble::kTopRight: - origin.x -= NSWidth([window frame]) - offsets.width; + case info_bubble::kTopTrailing: + origin.x -= + isRTL ? offsets.width : NSWidth([window frame]) - offsets.width; break; - case info_bubble::kTopLeft: - origin.x -= offsets.width; + case info_bubble::kTopLeading: + origin.x -= + isRTL ? NSWidth([window frame]) - offsets.width : offsets.width; break; case info_bubble::kNoArrow: // FALLTHROUGH. @@ -431,7 +433,7 @@ // edge aligns with the anchor. If the arrow is to the left then there's // nothing to do because the left edge is already aligned with the left // edge of the anchor. - if ([bubble_ arrowLocation] == info_bubble::kTopRight) { + if ([bubble_ arrowLocation] == info_bubble::kTopTrailing) { origin.x -= NSWidth([window frame]); } break;
diff --git a/chrome/browser/ui/cocoa/base_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/base_bubble_controller_unittest.mm index 05466b1..c7cc3b1e 100644 --- a/chrome/browser/ui/cocoa/base_bubble_controller_unittest.mm +++ b/chrome/browser/ui/cocoa/base_bubble_controller_unittest.mm
@@ -165,7 +165,7 @@ // Test that kAlignEdgeToAnchorEdge and a left bubble arrow correctly aligns the // left edge of the buble to the anchor point. TEST_F(BaseBubbleControllerTest, LeftAlign) { - [[controller_ bubble] setArrowLocation:info_bubble::kTopLeft]; + [[controller_ bubble] setArrowLocation:info_bubble::kTopLeading]; [[controller_ bubble] setAlignment:info_bubble::kAlignEdgeToAnchorEdge]; [controller_ showWindow:nil]; @@ -181,7 +181,7 @@ // Test that kAlignEdgeToAnchorEdge and a right bubble arrow correctly aligns // the right edge of the buble to the anchor point. TEST_F(BaseBubbleControllerTest, RightAlign) { - [[controller_ bubble] setArrowLocation:info_bubble::kTopRight]; + [[controller_ bubble] setArrowLocation:info_bubble::kTopTrailing]; [[controller_ bubble] setAlignment:info_bubble::kAlignEdgeToAnchorEdge]; [controller_ showWindow:nil]; @@ -197,7 +197,7 @@ // Test that kAlignArrowToAnchor and a left bubble arrow correctly aligns // the bubble arrow to the anchor point. TEST_F(BaseBubbleControllerTest, AnchorAlignLeftArrow) { - [[controller_ bubble] setArrowLocation:info_bubble::kTopLeft]; + [[controller_ bubble] setArrowLocation:info_bubble::kTopLeading]; [[controller_ bubble] setAlignment:info_bubble::kAlignArrowToAnchor]; [controller_ showWindow:nil]; @@ -214,7 +214,7 @@ // Test that kAlignArrowToAnchor and a right bubble arrow correctly aligns // the bubble arrow to the anchor point. TEST_F(BaseBubbleControllerTest, AnchorAlignRightArrow) { - [[controller_ bubble] setArrowLocation:info_bubble::kTopRight]; + [[controller_ bubble] setArrowLocation:info_bubble::kTopTrailing]; [[controller_ bubble] setAlignment:info_bubble::kAlignArrowToAnchor]; [controller_ showWindow:nil]; @@ -248,7 +248,7 @@ // ensures offscreen initialization is done using correct screen metrics. TEST_F(BaseBubbleControllerTest, PositionedBeforeShow) { // Verify default alignment settings, used when initialized in SetUp(). - EXPECT_EQ(info_bubble::kTopRight, [[controller_ bubble] arrowLocation]); + EXPECT_EQ(info_bubble::kTopTrailing, [[controller_ bubble] arrowLocation]); EXPECT_EQ(info_bubble::kAlignArrowToAnchor, [[controller_ bubble] alignment]); // Verify the default frame (positioned relative to the test_window() origin).
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.mm index 2d80a49d..2cd7a5d 100644 --- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.mm +++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.mm
@@ -144,7 +144,7 @@ [BrowserWindowController browserWindowControllerForWindow:parentWindow]; InfoBubbleView* bubble = self.bubble; - [bubble setArrowLocation:info_bubble::kTopRight]; + [bubble setArrowLocation:info_bubble::kTopTrailing]; // Insure decent positioning even in the absence of a browser controller, // which will occur for some unit tests.
diff --git a/chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa.mm b/chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa.mm index 47166727..e8d55a7 100644 --- a/chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa.mm +++ b/chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa.mm
@@ -791,7 +791,7 @@ ContentSettingSimpleBubbleModel* simple_bubble = contentSettingBubbleModel_->AsSimpleBubbleModel(); - [[self bubble] setArrowLocation:info_bubble::kTopRight]; + [[self bubble] setArrowLocation:info_bubble::kTopTrailing]; // Adapt window size to bottom buttons. Do this before all other layouting. if (simple_bubble && !simple_bubble->bubble_content().manage_text.empty())
diff --git a/chrome/browser/ui/cocoa/extensions/extension_action_platform_delegate_cocoa.mm b/chrome/browser/ui/cocoa/extensions/extension_action_platform_delegate_cocoa.mm index 9050f5d..e3abc4c 100644 --- a/chrome/browser/ui/cocoa/extensions/extension_action_platform_delegate_cocoa.mm +++ b/chrome/browser/ui/cocoa/extensions/extension_action_platform_delegate_cocoa.mm
@@ -77,7 +77,7 @@ [ExtensionPopupController host:std::move(host) inBrowser:controller_->browser() anchoredAt:GetPopupPoint() - arrowLocation:info_bubble::kTopRight + arrowLocation:info_bubble::kTopTrailing devMode:devMode]; }
diff --git a/chrome/browser/ui/cocoa/extensions/extension_installed_bubble_controller.mm b/chrome/browser/ui/cocoa/extensions/extension_installed_bubble_controller.mm index deed5a8c..a4d65986 100644 --- a/chrome/browser/ui/cocoa/extensions/extension_installed_bubble_controller.mm +++ b/chrome/browser/ui/cocoa/extensions/extension_installed_bubble_controller.mm
@@ -285,9 +285,9 @@ if (installedBubble_ && installedBubble_->anchor_position() == ExtensionInstalledBubble::ANCHOR_OMNIBOX) { - [self.bubble setArrowLocation:info_bubble::kTopLeft]; + [self.bubble setArrowLocation:info_bubble::kTopLeading]; } else { - [self.bubble setArrowLocation:info_bubble::kTopRight]; + [self.bubble setArrowLocation:info_bubble::kTopTrailing]; } // Set appropriate icon, resizing if necessary.
diff --git a/chrome/browser/ui/cocoa/extensions/toolbar_actions_bar_bubble_mac.mm b/chrome/browser/ui/cocoa/extensions/toolbar_actions_bar_bubble_mac.mm index 4099c11..75177f2f 100644 --- a/chrome/browser/ui/cocoa/extensions/toolbar_actions_bar_bubble_mac.mm +++ b/chrome/browser/ui/cocoa/extensions/toolbar_actions_bar_bubble_mac.mm
@@ -87,7 +87,7 @@ ui::NativeTheme* nativeTheme = ui::NativeTheme::GetInstanceForNativeUi(); [[self bubble] setAlignment:info_bubble::kAlignArrowToAnchor]; - [[self bubble] setArrowLocation:info_bubble::kTopRight]; + [[self bubble] setArrowLocation:info_bubble::kTopTrailing]; [[self bubble] setBackgroundColor: skia::SkColorToCalibratedNSColor(nativeTheme->GetSystemColor( ui::NativeTheme::kColorId_DialogBackground))];
diff --git a/chrome/browser/ui/cocoa/info_bubble_view.h b/chrome/browser/ui/cocoa/info_bubble_view.h index 09fa4745..3787f29 100644 --- a/chrome/browser/ui/cocoa/info_bubble_view.h +++ b/chrome/browser/ui/cocoa/info_bubble_view.h
@@ -25,9 +25,9 @@ }; enum BubbleArrowLocation { - kTopLeft, + kTopLeading, kTopCenter, - kTopRight, + kTopTrailing, kNoArrow, };
diff --git a/chrome/browser/ui/cocoa/info_bubble_view.mm b/chrome/browser/ui/cocoa/info_bubble_view.mm index 103db6b5..0d3f23d2 100644 --- a/chrome/browser/ui/cocoa/info_bubble_view.mm +++ b/chrome/browser/ui/cocoa/info_bubble_view.mm
@@ -7,6 +7,7 @@ #include "base/logging.h" #include "base/mac/foundation_util.h" #import "chrome/browser/ui/cocoa/info_bubble_window.h" +#import "chrome/browser/ui/cocoa/l10n_util.h" #import "third_party/google_toolbox_for_mac/src/AppKit/GTMNSBezierPath+RoundRect.h" @implementation InfoBubbleView @@ -17,7 +18,7 @@ - (id)initWithFrame:(NSRect)frameRect { if ((self = [super initWithFrame:frameRect])) { - arrowLocation_ = info_bubble::kTopLeft; + arrowLocation_ = info_bubble::kTopLeading; alignment_ = info_bubble::kAlignArrowToAnchor; cornerFlags_ = info_bubble::kRoundedAllCorners; backgroundColor_.reset([[NSColor whiteColor] retain]); @@ -64,14 +65,17 @@ bottomRightCornerRadius:bottomRadius]; // Add the bubble arrow. + BOOL isRTL = cocoa_l10n_util::ShouldDoExperimentalRTLLayout(); CGFloat dX = 0; + CGFloat leftOffset = info_bubble::kBubbleArrowXOffset; + CGFloat rightOffset = NSWidth(bounds) - info_bubble::kBubbleArrowXOffset - + info_bubble::kBubbleArrowWidth; switch (arrowLocation_) { - case info_bubble::kTopLeft: - dX = info_bubble::kBubbleArrowXOffset; + case info_bubble::kTopLeading: + dX = isRTL ? rightOffset : leftOffset; break; - case info_bubble::kTopRight: - dX = NSWidth(bounds) - info_bubble::kBubbleArrowXOffset - - info_bubble::kBubbleArrowWidth; + case info_bubble::kTopTrailing: + dX = isRTL ? leftOffset : rightOffset; break; case info_bubble::kTopCenter: dX = NSMidX(bounds) - info_bubble::kBubbleArrowWidth / 2.0; @@ -103,12 +107,15 @@ CGFloat tipXOffset = info_bubble::kBubbleArrowXOffset + info_bubble::kBubbleArrowWidth / 2.0; CGFloat xOffset = 0.0; + BOOL isRTL = cocoa_l10n_util::ShouldDoExperimentalRTLLayout(); + CGFloat leftOffset = NSMaxX(bounds) - tipXOffset; + CGFloat rightOffset = NSMinX(bounds) + tipXOffset; switch(arrowLocation_) { - case info_bubble::kTopRight: - xOffset = NSMaxX(bounds) - tipXOffset; + case info_bubble::kTopTrailing: + xOffset = isRTL ? rightOffset : leftOffset; break; - case info_bubble::kTopLeft: - xOffset = NSMinX(bounds) + tipXOffset; + case info_bubble::kTopLeading: + xOffset = isRTL ? leftOffset : rightOffset; break; case info_bubble::kTopCenter: xOffset = NSMidX(bounds);
diff --git a/chrome/browser/ui/cocoa/passwords/passwords_bubble_controller.mm b/chrome/browser/ui/cocoa/passwords/passwords_bubble_controller.mm index 54fa903..68c237a 100644 --- a/chrome/browser/ui/cocoa/passwords/passwords_bubble_controller.mm +++ b/chrome/browser/ui/cocoa/passwords/passwords_bubble_controller.mm
@@ -118,7 +118,7 @@ browserWindowControllerForWindow:[self parentWindow]]; anchorPoint = [controller locationBarBridge]->GetBubblePointForDecoration( [self decorationForBubble]); - arrow = info_bubble::kTopRight; + arrow = info_bubble::kTopTrailing; } else { // Center the bubble if there's no location bar. NSRect contentFrame = [[[self parentWindow] contentView] frame];
diff --git a/chrome/browser/ui/cocoa/validation_message_bubble_cocoa.mm b/chrome/browser/ui/cocoa/validation_message_bubble_cocoa.mm index 63e41ba..2fc70ee 100644 --- a/chrome/browser/ui/cocoa/validation_message_bubble_cocoa.mm +++ b/chrome/browser/ui/cocoa/validation_message_bubble_cocoa.mm
@@ -47,7 +47,7 @@ if ((self = [super initWithWindow:window.get() parentWindow:parentWindow anchoredAt:anchorPoint])) { - [[self bubble] setArrowLocation:info_bubble::kTopLeft]; + [[self bubble] setArrowLocation:info_bubble::kTopLeading]; self.shouldOpenAsKeyWindow = NO; NSView* contentView = [ValidationMessageBubbleController
diff --git a/chrome/browser/ui/cocoa/website_settings/chooser_bubble_ui_cocoa.mm b/chrome/browser/ui/cocoa/website_settings/chooser_bubble_ui_cocoa.mm index f8baba4..f7e8f1ee5 100644 --- a/chrome/browser/ui/cocoa/website_settings/chooser_bubble_ui_cocoa.mm +++ b/chrome/browser/ui/cocoa/website_settings/chooser_bubble_ui_cocoa.mm
@@ -246,7 +246,8 @@ } - (info_bubble::BubbleArrowLocation)getExpectedArrowLocation { - return [self hasLocationBar] ? info_bubble::kTopLeft : info_bubble::kNoArrow; + return [self hasLocationBar] ? info_bubble::kTopLeading + : info_bubble::kNoArrow; } - (NSWindow*)getExpectedParentWindow {
diff --git a/chrome/browser/ui/cocoa/website_settings/permission_bubble_controller.mm b/chrome/browser/ui/cocoa/website_settings/permission_bubble_controller.mm index 3d0dc43..f100a71 100644 --- a/chrome/browser/ui/cocoa/website_settings/permission_bubble_controller.mm +++ b/chrome/browser/ui/cocoa/website_settings/permission_bubble_controller.mm
@@ -479,7 +479,7 @@ } - (info_bubble::BubbleArrowLocation)getExpectedArrowLocation { - return info_bubble::kTopLeft; + return info_bubble::kTopLeading; } - (NSWindow*)getExpectedParentWindow {
diff --git a/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller.mm b/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller.mm index 31b9d3c..dbbb273 100644 --- a/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller.mm +++ b/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller.mm
@@ -213,7 +213,7 @@ if ((self = [super initWithWindow:window.get() parentWindow:parentWindow anchoredAt:NSZeroPoint])) { - [[self bubble] setArrowLocation:info_bubble::kTopLeft]; + [[self bubble] setArrowLocation:info_bubble::kTopLeading]; // Create the container view that uses flipped coordinates. NSRect contentFrame = NSMakeRect(0, 0, [self defaultWindowWidth], 300);
diff --git a/chrome/browser/ui/views/ash/OWNERS b/chrome/browser/ui/views/ash/OWNERS index 6c1a33b..28ae752 100644 --- a/chrome/browser/ui/views/ash/OWNERS +++ b/chrome/browser/ui/views/ash/OWNERS
@@ -2,3 +2,5 @@ sky@chromium.org jamescook@chromium.org erg@chromium.org + +# COMPONENT: UI>Shell
diff --git a/chrome/browser/ui/views/payments/payment_method_view_controller.cc b/chrome/browser/ui/views/payments/payment_method_view_controller.cc index 1983e899..88bb7db 100644 --- a/chrome/browser/ui/views/payments/payment_method_view_controller.cc +++ b/chrome/browser/ui/views/payments/payment_method_view_controller.cc
@@ -44,8 +44,14 @@ public views::ButtonListener { public: // Does not take ownership of |card|, which should not be null and should - // outlive this object. - explicit PaymentMethodListItem(autofill::CreditCard* card) : card_(card) {} + // outlive this object. |list| is the PaymentRequestItemList object that will + // own this. + PaymentMethodListItem(autofill::CreditCard* card, + PaymentRequest* request, + PaymentRequestItemList* list, + bool selected) + : payments::PaymentRequestItemList::Item(request, list, selected), + card_(card) {} ~PaymentMethodListItem() override {} private: @@ -72,6 +78,8 @@ columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0); + columns->AddPaddingColumn(0, kPaymentRequestButtonSpacing); + // A column for the card icon columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::CENTER, 0, views::GridLayout::USE_PREF, 0, 0); @@ -97,14 +105,20 @@ card_info_container->AddChildView(new views::Label( card_->GetInfo(autofill::AutofillType(autofill::CREDIT_CARD_NAME_FULL), g_browser_process->GetApplicationLocale()))); + // TODO(anthonyvd): Add the "card is incomplete" label once the + // completedness logic is implemented. layout->AddView(card_info_container.release()); - std::unique_ptr<views::ImageView> checkmark = - base::MakeUnique<views::ImageView>(); - checkmark->set_can_process_events_within_subtree(false); - checkmark->SetImage( + checkmark_ = base::MakeUnique<views::ImageView>(); + checkmark_->set_id( + static_cast<int>(DialogViewID::PAYMENT_METHOD_ITEM_CHECKMARK_VIEW)); + checkmark_->set_owned_by_client(); + checkmark_->set_can_process_events_within_subtree(false); + checkmark_->SetImage( gfx::CreateVectorIcon(views::kMenuCheckIcon, 0xFF609265)); - layout->AddView(checkmark.release()); + layout->AddView(checkmark_.get()); + if (!selected()) + checkmark_->SetVisible(false); std::unique_ptr<views::ImageView> card_icon_view = CreateCardIconView(card_->type()); @@ -114,10 +128,33 @@ return std::move(row); } + void SelectedStateChanged() override { + // This could be called before CreateItemView, so before |checkmark_| is + // instantiated. + if (checkmark_) + checkmark_->SetVisible(selected()); + + request()->set_selected_credit_card(card_); + } + // views::ButtonListener: - void ButtonPressed(views::Button* sender, const ui::Event& event) override {} + void ButtonPressed(views::Button* sender, const ui::Event& event) override { + if (IsComplete()) { + list()->SelectItem(this); + } else { + // TODO(anthonyvd): Display the editor, pre-populated with the data that + // already exists in |card|. + } + } + + bool IsComplete() const { + // TODO(anthonyvd): Hook this up to the card completedness logic when it's + // implemented in PaymentRequest. + return true; + } autofill::CreditCard* card_; + std::unique_ptr<views::ImageView> checkmark_; DISALLOW_COPY_AND_ASSIGN(PaymentMethodListItem); }; @@ -132,19 +169,28 @@ request->credit_cards(); for (autofill::CreditCard* card : available_cards) { - payment_method_list_.AddItem(base::MakeUnique<PaymentMethodListItem>(card)); + std::unique_ptr<PaymentMethodListItem> item = + base::MakeUnique<PaymentMethodListItem>( + card, request, &payment_method_list_, + card == request->selected_credit_card()); + payment_method_list_.AddItem(std::move(item)); } } PaymentMethodViewController::~PaymentMethodViewController() {} std::unique_ptr<views::View> PaymentMethodViewController::CreateView() { + std::unique_ptr<views::View> list_view = + payment_method_list_.CreateListView(); + list_view->set_id( + static_cast<int>(DialogViewID::PAYMENT_METHOD_SHEET_LIST_VIEW)); return CreatePaymentView( CreateSheetHeaderView( - true, l10n_util::GetStringUTF16( - IDS_PAYMENT_REQUEST_PAYMENT_METHOD_SECTION_NAME), + true, + l10n_util::GetStringUTF16( + IDS_PAYMENT_REQUEST_PAYMENT_METHOD_SECTION_NAME), this), - payment_method_list_.CreateListView()); + std::move(list_view)); } std::unique_ptr<views::View>
diff --git a/chrome/browser/ui/views/payments/payment_method_view_controller_interactive_uitest.cc b/chrome/browser/ui/views/payments/payment_method_view_controller_interactive_uitest.cc new file mode 100644 index 0000000..b8d3dea --- /dev/null +++ b/chrome/browser/ui/views/payments/payment_method_view_controller_interactive_uitest.cc
@@ -0,0 +1,129 @@ +// 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 "chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h" +#include "chrome/browser/ui/views/payments/payment_request_interactive_uitest_base.h" +#include "components/autofill/core/browser/autofill_test_utils.h" +#include "components/autofill/core/browser/personal_data_manager.h" +#include "components/payments/payment_request.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace payments { + +class PaymentMethodViewControllerTest + : public PaymentRequestInteractiveTestBase { + protected: + PaymentMethodViewControllerTest() + : PaymentRequestInteractiveTestBase( + "/payment_request_no_shipping_test.html") {} + + private: + DISALLOW_COPY_AND_ASSIGN(PaymentMethodViewControllerTest); +}; + +IN_PROC_BROWSER_TEST_F(PaymentMethodViewControllerTest, EmptyList) { + InvokePaymentRequestUI(); + OpenPaymentMethodScreen(); + + views::View* list_view = dialog_view()->GetViewByID( + static_cast<int>(DialogViewID::PAYMENT_METHOD_SHEET_LIST_VIEW)); + EXPECT_TRUE(list_view); + EXPECT_FALSE(list_view->has_children()); +} + +IN_PROC_BROWSER_TEST_F(PaymentMethodViewControllerTest, OneCardSelected) { + autofill::PersonalDataManager* personal_data_manager = GetDataManager(); + + PersonalDataLoadedObserverMock personal_data_observer; + personal_data_manager->AddObserver(&personal_data_observer); + base::RunLoop data_loop; + EXPECT_CALL(personal_data_observer, OnPersonalDataChanged()) + .WillOnce(QuitMessageLoop(&data_loop)); + autofill::CreditCard card = autofill::test::GetCreditCard(); + personal_data_manager->AddCreditCard(card); + data_loop.Run(); + + InvokePaymentRequestUI(); + OpenPaymentMethodScreen(); + + PaymentRequest* request = GetPaymentRequests(GetActiveWebContents())[0]; + EXPECT_EQ(1U, request->credit_cards().size()); + + views::View* list_view = dialog_view()->GetViewByID( + static_cast<int>(DialogViewID::PAYMENT_METHOD_SHEET_LIST_VIEW)); + EXPECT_TRUE(list_view); + EXPECT_EQ(1, list_view->child_count()); + + EXPECT_EQ(card, *request->selected_credit_card()); + views::View* checkmark_view = list_view->child_at(0)->GetViewByID( + static_cast<int>(DialogViewID::PAYMENT_METHOD_ITEM_CHECKMARK_VIEW)); + EXPECT_TRUE(checkmark_view->visible()); +} + +IN_PROC_BROWSER_TEST_F(PaymentMethodViewControllerTest, + OneCardSelectedOutOfMany) { + autofill::PersonalDataManager* personal_data_manager = GetDataManager(); + + PersonalDataLoadedObserverMock personal_data_observer1; + personal_data_manager->AddObserver(&personal_data_observer1); + base::RunLoop card1_loop; + EXPECT_CALL(personal_data_observer1, OnPersonalDataChanged()) + .WillOnce(QuitMessageLoop(&card1_loop)); + autofill::CreditCard card1 = autofill::test::GetCreditCard(); + // Ensure that this card is the first suggestion. + card1.set_use_count(5U); + personal_data_manager->AddCreditCard(card1); + card1_loop.Run(); + personal_data_manager->RemoveObserver(&personal_data_observer1); + + EXPECT_EQ(1U, personal_data_manager->GetCreditCardsToSuggest().size()); + + PersonalDataLoadedObserverMock personal_data_observer2; + personal_data_manager->AddObserver(&personal_data_observer2); + base::RunLoop card2_loop; + EXPECT_CALL(personal_data_observer2, OnPersonalDataChanged()) + .WillOnce(QuitMessageLoop(&card2_loop)); + autofill::CreditCard card2 = autofill::test::GetCreditCard2(); + card2.set_use_count(1U); + personal_data_manager->AddCreditCard(card2); + card2_loop.Run(); + personal_data_manager->RemoveObserver(&personal_data_observer2); + + InvokePaymentRequestUI(); + OpenPaymentMethodScreen(); + + PaymentRequest* request = GetPaymentRequests(GetActiveWebContents())[0]; + EXPECT_EQ(2U, request->credit_cards().size()); + EXPECT_EQ(card1, *request->selected_credit_card()); + + views::View* list_view = dialog_view()->GetViewByID( + static_cast<int>(DialogViewID::PAYMENT_METHOD_SHEET_LIST_VIEW)); + EXPECT_TRUE(list_view); + EXPECT_EQ(2, list_view->child_count()); + + EXPECT_EQ(card1, *request->selected_credit_card()); + views::View* checkmark_view = list_view->child_at(0)->GetViewByID( + static_cast<int>(DialogViewID::PAYMENT_METHOD_ITEM_CHECKMARK_VIEW)); + EXPECT_TRUE(checkmark_view->visible()); + + views::View* checkmark_view2 = list_view->child_at(1)->GetViewByID( + static_cast<int>(DialogViewID::PAYMENT_METHOD_ITEM_CHECKMARK_VIEW)); + EXPECT_FALSE(checkmark_view2->visible()); + + // Simulate selecting the second card. + ClickOnDialogViewAndWait(list_view->child_at(1)); + + EXPECT_EQ(card2, *request->selected_credit_card()); + EXPECT_FALSE(checkmark_view->visible()); + EXPECT_TRUE(checkmark_view2->visible()); + + // Clicking on the second card again should not modify any state. + ClickOnDialogViewAndWait(list_view->child_at(1)); + + EXPECT_EQ(card2, *request->selected_credit_card()); + EXPECT_FALSE(checkmark_view->visible()); + EXPECT_TRUE(checkmark_view2->visible()); +} + +} // namespace payments
diff --git a/chrome/browser/ui/views/payments/payment_request_credit_card_editor_interactive_uitest.cc b/chrome/browser/ui/views/payments/payment_request_credit_card_editor_interactive_uitest.cc index e408da8..3b49bd6 100644 --- a/chrome/browser/ui/views/payments/payment_request_credit_card_editor_interactive_uitest.cc +++ b/chrome/browser/ui/views/payments/payment_request_credit_card_editor_interactive_uitest.cc
@@ -12,12 +12,10 @@ #include "chrome/browser/ui/views/payments/validating_textfield.h" #include "components/autofill/core/browser/field_types.h" #include "components/autofill/core/browser/personal_data_manager.h" -#include "components/autofill/core/browser/personal_data_manager_observer.h" #include "components/autofill/core/browser/test_autofill_clock.h" #include "components/payments/payment_request.h" #include "components/strings/grit/components_strings.h" #include "content/public/test/browser_test_utils.h" -#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/l10n/l10n_util.h" @@ -27,19 +25,6 @@ const base::Time kJune2017 = base::Time::FromDoubleT(1497552271); -ACTION_P(QuitMessageLoop, loop) { - loop->Quit(); -} - -class PersonalDataLoadedObserverMock - : public autofill::PersonalDataManagerObserver { - public: - PersonalDataLoadedObserverMock() {} - virtual ~PersonalDataLoadedObserverMock() {} - - MOCK_METHOD0(OnPersonalDataChanged, void()); -}; - } // namespace class PaymentRequestCreditCardEditorTest @@ -74,8 +59,7 @@ autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR); // Verifying the data is in the DB. - autofill::PersonalDataManager* personal_data_manager = - GetPaymentRequests(GetActiveWebContents())[0]->personal_data_manager(); + autofill::PersonalDataManager* personal_data_manager = GetDataManager(); personal_data_manager->AddObserver(&personal_data_observer_); ResetEventObserver(DialogEvent::BACK_NAVIGATION); @@ -126,8 +110,7 @@ EXPECT_FALSE(IsEditorComboboxInvalid(autofill::CREDIT_CARD_EXP_MONTH)); EXPECT_FALSE(IsEditorComboboxInvalid(autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR)); - autofill::PersonalDataManager* personal_data_manager = - GetPaymentRequests(GetActiveWebContents())[0]->personal_data_manager(); + autofill::PersonalDataManager* personal_data_manager = GetDataManager(); EXPECT_EQ(0u, personal_data_manager->GetCreditCards().size()); } @@ -196,8 +179,7 @@ EXPECT_FALSE(IsEditorComboboxInvalid(autofill::CREDIT_CARD_EXP_MONTH)); EXPECT_FALSE(IsEditorComboboxInvalid(autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR)); - autofill::PersonalDataManager* personal_data_manager = - GetPaymentRequests(GetActiveWebContents())[0]->personal_data_manager(); + autofill::PersonalDataManager* personal_data_manager = GetDataManager(); EXPECT_EQ(0u, personal_data_manager->GetCreditCards().size()); } @@ -232,8 +214,7 @@ EXPECT_FALSE(IsEditorComboboxInvalid(autofill::CREDIT_CARD_EXP_MONTH)); EXPECT_FALSE(IsEditorComboboxInvalid(autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR)); - autofill::PersonalDataManager* personal_data_manager = - GetPaymentRequests(GetActiveWebContents())[0]->personal_data_manager(); + autofill::PersonalDataManager* personal_data_manager = GetDataManager(); EXPECT_EQ(0u, personal_data_manager->GetCreditCards().size()); } @@ -274,8 +255,7 @@ GetErrorLabelForType(autofill::CREDIT_CARD_NUMBER)); // Verifying the data is in the DB. - autofill::PersonalDataManager* personal_data_manager = - GetPaymentRequests(GetActiveWebContents())[0]->personal_data_manager(); + autofill::PersonalDataManager* personal_data_manager = GetDataManager(); personal_data_manager->AddObserver(&personal_data_observer_); ResetEventObserver(DialogEvent::BACK_NAVIGATION);
diff --git a/chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h b/chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h index e3de7b51..df302b0f 100644 --- a/chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h +++ b/chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h
@@ -29,6 +29,10 @@ ORDER_SUMMARY_LINE_ITEM_2, ORDER_SUMMARY_LINE_ITEM_3, + // The following are views contained within the Payment Method Sheet. + PAYMENT_METHOD_SHEET_LIST_VIEW, + PAYMENT_METHOD_ITEM_CHECKMARK_VIEW, + // Used to label the error labels with an offset, which gets added to // the Autofill type value they represent (for tests). ERROR_LABEL_OFFSET,
diff --git a/chrome/browser/ui/views/payments/payment_request_interactive_uitest_base.cc b/chrome/browser/ui/views/payments/payment_request_interactive_uitest_base.cc index 991adf4..6e14875 100644 --- a/chrome/browser/ui/views/payments/payment_request_interactive_uitest_base.cc +++ b/chrome/browser/ui/views/payments/payment_request_interactive_uitest_base.cc
@@ -11,6 +11,8 @@ #include "base/memory/ptr_util.h" #include "base/run_loop.h" #include "base/strings/string16.h" +#include "chrome/browser/autofill/personal_data_manager_factory.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h" @@ -35,6 +37,9 @@ namespace payments { +PersonalDataLoadedObserverMock::PersonalDataLoadedObserverMock() {} +PersonalDataLoadedObserverMock::~PersonalDataLoadedObserverMock() {} + PaymentRequestInteractiveTestBase::PaymentRequestInteractiveTestBase( const std::string& test_file_path) : test_file_path_(test_file_path), @@ -153,6 +158,12 @@ return payment_requests_ptrs; } +autofill::PersonalDataManager* +PaymentRequestInteractiveTestBase::GetDataManager() { + return autofill::PersonalDataManagerFactory::GetForProfile( + Profile::FromBrowserContext(GetActiveWebContents()->GetBrowserContext())); +} + void PaymentRequestInteractiveTestBase::CreatePaymentRequestForTest( content::WebContents* web_contents, mojo::InterfaceRequest<payments::mojom::PaymentRequest> request) { @@ -171,6 +182,12 @@ views::View* view = delegate_->dialog_view()->GetViewByID(static_cast<int>(view_id)); DCHECK(view); + ClickOnDialogViewAndWait(view); +} + +void PaymentRequestInteractiveTestBase::ClickOnDialogViewAndWait( + views::View* view) { + DCHECK(view); base::RunLoop run_loop; ui_test_utils::MoveMouseToCenterAndPress( view, ui_controls::LEFT, ui_controls::DOWN | ui_controls::UP,
diff --git a/chrome/browser/ui/views/payments/payment_request_interactive_uitest_base.h b/chrome/browser/ui/views/payments/payment_request_interactive_uitest_base.h index 3b718a8..663dd91 100644 --- a/chrome/browser/ui/views/payments/payment_request_interactive_uitest_base.h +++ b/chrome/browser/ui/views/payments/payment_request_interactive_uitest_base.h
@@ -15,8 +15,10 @@ #include "chrome/browser/ui/views/payments/test_chrome_payment_request_delegate.h" #include "chrome/test/base/in_process_browser_test.h" #include "components/autofill/core/browser/field_types.h" +#include "components/autofill/core/browser/personal_data_manager_observer.h" #include "components/payments/payment_request.mojom.h" #include "net/test/embedded_test_server/embedded_test_server.h" +#include "testing/gmock/include/gmock/gmock.h" #include "ui/views/widget/widget_observer.h" namespace content { @@ -32,6 +34,23 @@ enum class DialogViewID; class PaymentRequest; +namespace { + +ACTION_P(QuitMessageLoop, loop) { + loop->Quit(); +} + +} // namespace + +class PersonalDataLoadedObserverMock + : public autofill::PersonalDataManagerObserver { + public: + PersonalDataLoadedObserverMock(); + ~PersonalDataLoadedObserverMock() override; + + MOCK_METHOD0(OnPersonalDataChanged, void()); +}; + // Base class for any interactive PaymentRequest test that will need to open // the UI and interact with it. class PaymentRequestInteractiveTestBase @@ -68,12 +87,14 @@ void OpenPaymentMethodScreen(); void OpenCreditCardEditorScreen(); + content::WebContents* GetActiveWebContents(); + // Convenience method to get a list of PaymentRequest associated with // |web_contents|. const std::vector<PaymentRequest*> GetPaymentRequests( content::WebContents* web_contents); - content::WebContents* GetActiveWebContents(); + autofill::PersonalDataManager* GetDataManager(); void CreatePaymentRequestForTest( content::WebContents* web_contents, @@ -82,6 +103,7 @@ // Click on a view from within the dialog and waits for an observed event // to be observed. void ClickOnDialogViewAndWait(DialogViewID view_id); + void ClickOnDialogViewAndWait(views::View* view); // Setting the |value| in the textfield of a given |type|. void SetEditorTextfieldValue(const base::string16& value,
diff --git a/chrome/browser/ui/views/payments/payment_request_item_list.cc b/chrome/browser/ui/views/payments/payment_request_item_list.cc index 0cb3ce87..dde7ff9 100644 --- a/chrome/browser/ui/views/payments/payment_request_item_list.cc +++ b/chrome/browser/ui/views/payments/payment_request_item_list.cc
@@ -10,7 +10,10 @@ namespace payments { -PaymentRequestItemList::Item::Item() {} +PaymentRequestItemList::Item::Item(PaymentRequest* request, + PaymentRequestItemList* list, + bool selected) + : request_(request), list_(list), selected_(selected) {} PaymentRequestItemList::Item::~Item() {} @@ -23,13 +26,21 @@ return item_view_.get(); } -PaymentRequestItemList::PaymentRequestItemList() {} +void PaymentRequestItemList::Item::SetSelected(bool selected) { + selected_ = selected; + SelectedStateChanged(); +} + +PaymentRequestItemList::PaymentRequestItemList() : selected_item_(nullptr) {} PaymentRequestItemList::~PaymentRequestItemList() {} void PaymentRequestItemList::AddItem( std::unique_ptr<PaymentRequestItemList::Item> item) { + DCHECK_EQ(this, item->list()); items_.push_back(std::move(item)); + if (items_.back()->selected()) + SelectItem(items_.back().get()); } std::unique_ptr<views::View> PaymentRequestItemList::CreateListView() { @@ -46,4 +57,25 @@ return content_view; } +void PaymentRequestItemList::SelectItem(PaymentRequestItemList::Item* item) { + DCHECK_EQ(this, item->list()); + if (selected_item_ == item) + return; + + UnselectSelectedItem(); + + selected_item_ = item; + item->SetSelected(true); +} + +void PaymentRequestItemList::UnselectSelectedItem() { + // It's possible that no item is currently selected, either during list + // creation or in the middle of the selection operation when the previously + // selected item has been deselected but the new one isn't selected yet. + if (selected_item_) + selected_item_->SetSelected(false); + + selected_item_ = nullptr; +} + } // namespace payments
diff --git a/chrome/browser/ui/views/payments/payment_request_item_list.h b/chrome/browser/ui/views/payments/payment_request_item_list.h index 71f4c04..09aafea0 100644 --- a/chrome/browser/ui/views/payments/payment_request_item_list.h +++ b/chrome/browser/ui/views/payments/payment_request_item_list.h
@@ -16,17 +16,21 @@ namespace payments { +class PaymentRequest; + // A control representing a list of selectable items in the PaymentRequest // dialog. These lists enforce that only one of their elements be selectable at // a time and that "incomplete" items (for example, a credit card with no known -// expriration date) behave differently when selected. Most of the time, this +// expiration date) behave differently when selected. Most of the time, this // behavior is to show an editor screen. class PaymentRequestItemList { public: // Represents an item in the item list. class Item { public: - Item(); + // Creates an item that will be owned by |list| with the initial state set + // to |selected|. + Item(PaymentRequest* request, PaymentRequestItemList* list, bool selected); virtual ~Item(); // Gets the view associated with this item. It's owned by this object so @@ -34,12 +38,33 @@ // view. views::View* GetItemView(); + bool selected() const { return selected_; } + // Changes the selected state of this item to |selected| and calls + // SelectedStateChanged. + void SetSelected(bool selected); + + // Returns a pointer to the PaymentRequestItemList that owns this object. + PaymentRequestItemList* list() { return list_; } + + // Returns a pointer to the PaymentRequest object associated with this + // instance of the UI. + PaymentRequest* request() { return request_; } + protected: // Creates and returns the view associated with this list item. virtual std::unique_ptr<views::View> CreateItemView() = 0; + // Called when the selected state of this item changes. Subclasses may + // assume that they are the only selected item in |list| when this is + // called. This could be called before CreateItemView so subclasses should + // be aware that their views might not exist yet. + virtual void SelectedStateChanged() = 0; + private: std::unique_ptr<views::View> item_view_; + PaymentRequest* request_; + PaymentRequestItemList* list_; + bool selected_; DISALLOW_COPY_AND_ASSIGN(Item); }; @@ -47,7 +72,7 @@ PaymentRequestItemList(); ~PaymentRequestItemList(); - // Adds an item to this list. + // Adds an item to this list. |item->list()| should return this object. void AddItem(std::unique_ptr<Item> item); // Creates and returns the UI representation of this list. It iterates over @@ -55,8 +80,17 @@ // hierarchy. std::unique_ptr<views::View> CreateListView(); + // Deselects the currently selected item and selects |item| instead. + void SelectItem(Item* item); + private: + // Unselects the currently selected item. This is private so that the list can + // use it when selecting a new item while avoiding consumers of this class + // putting the list in a state where no item is selected. + void UnselectSelectedItem(); + std::vector<std::unique_ptr<Item>> items_; + Item* selected_item_; DISALLOW_COPY_AND_ASSIGN(PaymentRequestItemList); };
diff --git a/chrome/browser/ui/views/payments/payment_request_item_list_unittest.cc b/chrome/browser/ui/views/payments/payment_request_item_list_unittest.cc new file mode 100644 index 0000000..8f1f86d --- /dev/null +++ b/chrome/browser/ui/views/payments/payment_request_item_list_unittest.cc
@@ -0,0 +1,124 @@ +// 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 "chrome/browser/ui/views/payments/payment_request_item_list.h" + +#include <algorithm> + +#include "base/memory/ptr_util.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/views/view.h" + +namespace payments { + +namespace { + +class TestListItem : public PaymentRequestItemList::Item { + public: + TestListItem(PaymentRequestItemList* list, bool selected) + : PaymentRequestItemList::Item(nullptr, list, selected), + selected_state_changed_calls_count_(0) {} + + int selected_state_changed_calls_count() { + return selected_state_changed_calls_count_; + } + + private: + std::unique_ptr<views::View> CreateItemView() override { + return base::MakeUnique<views::View>(); + } + + void SelectedStateChanged() override { + ++selected_state_changed_calls_count_; + } + + int selected_state_changed_calls_count_; + + DISALLOW_COPY_AND_ASSIGN(TestListItem); +}; + +} // namespace + +TEST(PaymentRequestItemListTest, TestAddItem) { + PaymentRequestItemList list; + + std::unique_ptr<views::View> list_view = list.CreateListView(); + EXPECT_FALSE(list_view->has_children()); + + std::vector<std::unique_ptr<TestListItem>> items; + items.push_back(base::MakeUnique<TestListItem>(&list, false)); + items.push_back(base::MakeUnique<TestListItem>(&list, true)); + items.push_back(base::MakeUnique<TestListItem>(&list, false)); + items.push_back(base::MakeUnique<TestListItem>(&list, true)); + + // The unique_ptr objects will become owned by |list|, but the underlying + // pointers will be needed for assertions after the unique_ptr is moved. + std::vector<TestListItem*> item_pointers; + for (auto& item : items) { + item_pointers.push_back(item.get()); + list.AddItem(std::move(item)); + } + + EXPECT_FALSE(item_pointers[0]->selected()); + // Only one item should be selected at a time, so adding item at index 3 with + // |selected| set to true should have deselected item at index 1. + EXPECT_FALSE(item_pointers[1]->selected()); + EXPECT_FALSE(item_pointers[2]->selected()); + EXPECT_TRUE(item_pointers[3]->selected()); + + list_view = list.CreateListView(); + EXPECT_EQ(4, list_view->child_count()); +} + +TEST(PaymentRequestItemListTest, TestSelectItemResultsInSingleItemSelected) { + PaymentRequestItemList list; + + std::vector<std::unique_ptr<TestListItem>> items; + items.push_back(base::MakeUnique<TestListItem>(&list, false)); + items.push_back(base::MakeUnique<TestListItem>(&list, false)); + items.push_back(base::MakeUnique<TestListItem>(&list, false)); + + // The unique_ptr objects will become owned by |list|, but the underlying + // pointers will be needed for assertions after the unique_ptr is moved. + std::vector<TestListItem*> item_pointers; + for (auto& item : items) { + item_pointers.push_back(item.get()); + list.AddItem(std::move(item)); + } + + // Only one item should be selected at once and items should have their + // SelectedStateChanged() function called when they are selected and when + // they are unselected. + list.SelectItem(item_pointers[0]); + EXPECT_TRUE(item_pointers[0]->selected()); + EXPECT_EQ(1, item_pointers[0]->selected_state_changed_calls_count()); + + EXPECT_FALSE(item_pointers[1]->selected()); + EXPECT_EQ(0, item_pointers[1]->selected_state_changed_calls_count()); + + EXPECT_FALSE(item_pointers[2]->selected()); + EXPECT_EQ(0, item_pointers[2]->selected_state_changed_calls_count()); + + list.SelectItem(item_pointers[2]); + EXPECT_FALSE(item_pointers[0]->selected()); + EXPECT_EQ(2, item_pointers[0]->selected_state_changed_calls_count()); + + EXPECT_FALSE(item_pointers[1]->selected()); + EXPECT_EQ(0, item_pointers[1]->selected_state_changed_calls_count()); + + EXPECT_TRUE(item_pointers[2]->selected()); + EXPECT_EQ(1, item_pointers[2]->selected_state_changed_calls_count()); + + list.SelectItem(item_pointers[1]); + EXPECT_FALSE(item_pointers[0]->selected()); + EXPECT_EQ(2, item_pointers[0]->selected_state_changed_calls_count()); + + EXPECT_TRUE(item_pointers[1]->selected()); + EXPECT_EQ(1, item_pointers[1]->selected_state_changed_calls_count()); + + EXPECT_FALSE(item_pointers[2]->selected()); + EXPECT_EQ(2, item_pointers[2]->selected_state_changed_calls_count()); +} + +} // namespace payments
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc index 88caad3..886fab62 100644 --- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -82,6 +82,7 @@ {"edit", IDS_SETTINGS_EDIT}, {"learnMore", IDS_LEARN_MORE}, {"menuButtonLabel", IDS_SETTINGS_MENU_BUTTON_LABEL}, + {"moreActions", IDS_SETTINGS_MORE_ACTIONS}, {"ok", IDS_OK}, {"restart", IDS_SETTINGS_RESTART}, {"save", IDS_SAVE}, @@ -1042,7 +1043,6 @@ void AddPasswordsAndFormsStrings(content::WebUIDataSource* html_source) { LocalizedString localized_strings[] = { - {"overflowMenu", IDS_SETTINGS_OVERFLOW_MENU}, {"passwordsAndAutofillPageTitle", IDS_SETTINGS_PASSWORDS_AND_AUTOFILL_PAGE_TITLE}, {"autofill", IDS_SETTINGS_AUTOFILL},
diff --git a/chrome/renderer/app_categorizer.cc b/chrome/renderer/app_categorizer.cc index 4251977..3d7a180 100644 --- a/chrome/renderer/app_categorizer.cc +++ b/chrome/renderer/app_categorizer.cc
@@ -20,11 +20,6 @@ "plus.sandbox.google.com" }; -const char* const kPredefinedPlusDomains[] = { - "plus.google.com", - "plus.sandbox.google.com" -}; - bool IsInWhitelistedDomain( const GURL& url, const char* const domains[], size_t number_of_domains) { for (size_t i = 0; i < number_of_domains; ++i) { @@ -55,19 +50,6 @@ if (!app_url.SchemeIsCryptographic()) return false; - std::string manifest_url_path = manifest_url.path(); - bool is_photo_app = - manifest_url.SchemeIsCryptographic() && - manifest_url.DomainIs("ssl.gstatic.com") && - (base::StartsWith(manifest_url_path, "/s2/oz/nacl/", - base::CompareCase::SENSITIVE) || - base::StartsWith(manifest_url_path, "/photos/nacl/", - base::CompareCase::SENSITIVE)) && - IsInWhitelistedDomain( - app_url, - kPredefinedPlusDomains, - arraysize(kPredefinedPlusDomains)); - bool is_hangouts_app = manifest_url.SchemeIsFileSystem() && manifest_url.inner_url() != NULL && @@ -76,5 +58,5 @@ (manifest_url.inner_url()->host() == app_url.host()) && IsHangoutsUrl(app_url); - return is_photo_app || is_hangouts_app; + return is_hangouts_app; }
diff --git a/chrome/renderer/app_categorizer_unittest.cc b/chrome/renderer/app_categorizer_unittest.cc index 8a882aa..69b5f0b 100644 --- a/chrome/renderer/app_categorizer_unittest.cc +++ b/chrome/renderer/app_categorizer_unittest.cc
@@ -34,32 +34,6 @@ "https://talkgadget.evil.com/hangouts/foo" // domain not whitelisted }; -const char* kPhotosAppURLs[] = { - "https://foo.plus.google.com", - "https://foo.plus.sandbox.google.com" -}; - -const char* kPhotosManifestURLs[] = { - "https://ssl.gstatic.com/photos/nacl/foo", - "https://ssl.gstatic.com/s2/oz/nacl/foo" -}; - -const char* kBadPhotosAppURLs[] = { - "https://plus.google.com/foo", - "https://plus.google.com/foo", - "https://plus.google.com/foo", - "http://plus.google.com/foo", // http scheme - "https://plus.evil.com/foo", // domain not whitelisted -}; - -const char* kBadPhotosManifestURLs[] = { - "http://ssl.gstatic.com/photos/nacl/foo", // http scheme - "https://lss.gstatic.com/photos/nacl/foo", // bad hostname - "https://ssl.gstatic.com/wrong/photos/nacl/foo", // bad path - "https://ssl.gstatic.com/photos/nacl/foo", - "https://ssl.gstatic.com/photos/nacl/foo", -}; - } // namespace TEST(AppCategorizerTest, IsHangoutsUrl) { @@ -101,25 +75,4 @@ GURL("filesystem:https://meet.google.com/foo"), GURL("https://hangouts.google.com/hangouts/foo"))); } - - // Photos app - { - EXPECT_EQ(arraysize(kPhotosAppURLs), arraysize(kPhotosManifestURLs)); - for (size_t i = 0; i < arraysize(kPhotosAppURLs); ++i) { - EXPECT_TRUE(AppCategorizer::IsWhitelistedApp( - GURL(kPhotosManifestURLs[i]), GURL(kPhotosAppURLs[i]))); - } - // The app/manifest two sides do not have any coorelation for the Photos app - for (size_t i = 0; i < arraysize(kPhotosAppURLs); ++i) { - EXPECT_TRUE(AppCategorizer::IsWhitelistedApp( - GURL(kPhotosManifestURLs[(i + 1) % arraysize(kPhotosAppURLs)]), - GURL(kPhotosAppURLs[i]))); - } - - EXPECT_EQ(arraysize(kBadPhotosAppURLs), arraysize(kBadPhotosManifestURLs)); - for (size_t i = 0; i < arraysize(kBadPhotosAppURLs); ++i) { - EXPECT_FALSE(AppCategorizer::IsWhitelistedApp( - GURL(kBadPhotosManifestURLs[i]), GURL(kBadPhotosAppURLs[i]))); - } - } }
diff --git a/chrome/renderer/chrome_content_renderer_client_unittest.cc b/chrome/renderer/chrome_content_renderer_client_unittest.cc index ce3ad61..25e9c33 100644 --- a/chrome/renderer/chrome_content_renderer_client_unittest.cc +++ b/chrome/renderer/chrome_content_renderer_client_unittest.cc
@@ -61,9 +61,6 @@ #if !defined(DISABLE_NACL) const char kExtensionUrl[] = "chrome-extension://extension_id/background.html"; -const char kPhotosAppURL[] = "https://foo.plus.google.com"; -const char kPhotosManifestURL[] = "https://ssl.gstatic.com/photos/nacl/foo"; - const char kChatManifestFS[] = "filesystem:https://talkgadget.google.com/foo"; #endif @@ -277,15 +274,6 @@ // interfaces. There is a whitelist for the app URL and the manifest URL. { WebPluginParams params; - // Whitelisted Photos app is allowed (two app URLs, two manifest URLs) - EXPECT_TRUE(ChromeContentRendererClient::IsNaClAllowed( - GURL(kPhotosManifestURL), - GURL(kPhotosAppURL), - kNaClRestricted, - nullptr, - ¶ms)); - EXPECT_FALSE(AllowsDevInterfaces(params)); - // Whitelisted Chat app is allowed. EXPECT_TRUE(ChromeContentRendererClient::IsNaClAllowed( GURL(kChatManifestFS), @@ -296,51 +284,33 @@ // Whitelisted manifest URL, bad app URLs, NOT allowed. EXPECT_FALSE(ChromeContentRendererClient::IsNaClAllowed( - GURL(kPhotosManifestURL), + GURL(kChatManifestFS), GURL("http://plus.google.com/foo"), // http scheme - kNaClRestricted, - nullptr, - ¶ms)); + kNaClRestricted, nullptr, ¶ms)); EXPECT_FALSE(ChromeContentRendererClient::IsNaClAllowed( - GURL(kPhotosManifestURL), + GURL(kChatManifestFS), GURL("http://plus.sandbox.google.com/foo"), // http scheme - kNaClRestricted, - nullptr, - ¶ms)); + kNaClRestricted, nullptr, ¶ms)); EXPECT_FALSE(ChromeContentRendererClient::IsNaClAllowed( - GURL(kPhotosManifestURL), + GURL(kChatManifestFS), GURL("https://plus.google.evil.com/foo"), // bad host - kNaClRestricted, - nullptr, - ¶ms)); + kNaClRestricted, nullptr, ¶ms)); // Whitelisted app URL, bad manifest URL, NOT allowed. EXPECT_FALSE(ChromeContentRendererClient::IsNaClAllowed( GURL("http://ssl.gstatic.com/s2/oz/nacl/foo"), // http scheme - GURL(kPhotosAppURL), - kNaClRestricted, - nullptr, - ¶ms)); + GURL(kChatAppURL), kNaClRestricted, nullptr, ¶ms)); EXPECT_FALSE(ChromeContentRendererClient::IsNaClAllowed( GURL("https://ssl.gstatic.evil.com/s2/oz/nacl/foo"), // bad host - GURL(kPhotosAppURL), - kNaClRestricted, - nullptr, - ¶ms)); + GURL(kChatAppURL), kNaClRestricted, nullptr, ¶ms)); EXPECT_FALSE(ChromeContentRendererClient::IsNaClAllowed( GURL("https://ssl.gstatic.com/wrong/s2/oz/nacl/foo"), // bad path - GURL(kPhotosAppURL), - kNaClRestricted, - nullptr, - ¶ms)); + GURL(kChatAppURL), kNaClRestricted, nullptr, ¶ms)); } // Whitelisted URLs can't get 'dev' interfaces with --enable-nacl. { WebPluginParams params; EXPECT_TRUE(ChromeContentRendererClient::IsNaClAllowed( - GURL(kPhotosManifestURL), - GURL(kPhotosAppURL), - kNaClUnrestricted, - nullptr, + GURL(kChatManifestFS), GURL(kChatAppURL), kNaClUnrestricted, nullptr, ¶ms)); EXPECT_FALSE(AllowsDevInterfaces(params)); } @@ -350,10 +320,7 @@ WebPluginParams params; AddFakeDevAttribute(¶ms); EXPECT_TRUE(ChromeContentRendererClient::IsNaClAllowed( - GURL(kPhotosManifestURL), - GURL(kPhotosAppURL), - kNaClRestricted, - nullptr, + GURL(kChatManifestFS), GURL(kChatAppURL), kNaClRestricted, nullptr, ¶ms)); EXPECT_FALSE(AllowsDevInterfaces(params)); }
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 49a64ef..f4601a9 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -580,6 +580,7 @@ # TODO(crbug.com/679127): Investigate why these tests currently break # on Mac, and enable them. sources += [ + "../browser/ui/views/payments/payment_method_view_controller_interactive_uitest.cc", "../browser/ui/views/payments/payment_request_credit_card_editor_interactive_uitest.cc", "../browser/ui/views/payments/payment_request_interactive_uitest.cc", "../browser/ui/views/payments/payment_request_interactive_uitest_base.cc", @@ -4813,6 +4814,7 @@ "../browser/ui/views/confirm_bubble_views_unittest.cc", "../browser/ui/views/global_error_bubble_view_unittest.cc", "../browser/ui/views/payments/credit_card_editor_view_controller_unittest.cc", + "../browser/ui/views/payments/payment_request_item_list_unittest.cc", "../browser/ui/views/payments/validating_textfield_unittest.cc", "../browser/ui/views/payments/view_stack_unittest.cc", "../browser/ui/views/website_settings/website_settings_popup_view_unittest.cc",
diff --git a/components/BUILD.gn b/components/BUILD.gn index 9dfe6ff5..5b3a0231 100644 --- a/components/BUILD.gn +++ b/components/BUILD.gn
@@ -395,7 +395,6 @@ "dom_distiller/content/browser/test/dom_distiller_js_browsertest.cc", "password_manager/content/renderer/credential_manager_client_browsertest.cc", "security_state/content/content_utils_browsertest.cc", - "tracing/child/child_trace_message_filter_browsertest.cc", ] data = [
diff --git a/components/autofill/content/browser/content_autofill_driver.h b/components/autofill/content/browser/content_autofill_driver.h index 4223737..0f6fb08 100644 --- a/components/autofill/content/browser/content_autofill_driver.h +++ b/components/autofill/content/browser/content_autofill_driver.h
@@ -67,6 +67,7 @@ gfx::RectF TransformBoundingBoxToViewportCoordinates( const gfx::RectF& bounding_box) override; void DidInteractWithCreditCardForm() override; + void NotifyFirstUserGestureObservedInTab() override; // mojom::AutofillDriver: void FirstUserGestureObserved() override; @@ -93,10 +94,6 @@ // Called when the frame has navigated. void DidNavigateFrame(content::NavigationHandle* navigation_handle); - // Tells the render frame that a user gesture was observed - // somewhere in the tab (including in a different frame). - void NotifyFirstUserGestureObservedInTab(); - AutofillExternalDelegate* autofill_external_delegate() { return &autofill_external_delegate_; }
diff --git a/components/autofill/core/browser/autofill_driver.h b/components/autofill/core/browser/autofill_driver.h index a702eb26..e8b95d8 100644 --- a/components/autofill/core/browser/autofill_driver.h +++ b/components/autofill/core/browser/autofill_driver.h
@@ -103,6 +103,10 @@ // Called when the user interacted with a credit card form, so that // the current page's security state can be updated appropriately. virtual void DidInteractWithCreditCardForm() = 0; + + // Tells the associated frame that a user gesture was observed somewhere in + // the tab (including in a different frame). + virtual void NotifyFirstUserGestureObservedInTab() {} }; } // namespace autofill
diff --git a/components/autofill/core/browser/autofill_driver_factory.cc b/components/autofill/core/browser/autofill_driver_factory.cc index 19d369bb1..224c1efd 100644 --- a/components/autofill/core/browser/autofill_driver_factory.cc +++ b/components/autofill/core/browser/autofill_driver_factory.cc
@@ -20,20 +20,8 @@ return mapping == driver_map_.end() ? nullptr : mapping->second.get(); } -void AutofillDriverFactory::AddForKey( - void* key, - base::Callback<std::unique_ptr<AutofillDriver>()> factory_method) { - auto insertion_result = driver_map_.insert(std::make_pair(key, nullptr)); - // This can be called twice for the key representing the main frame. - if (insertion_result.second) - insertion_result.first->second = factory_method.Run(); -} - -void AutofillDriverFactory::DeleteForKey(void* key) { - driver_map_.erase(key); -} - void AutofillDriverFactory::NavigationFinished() { + user_gesture_seen_ = false; client_->HideAutofillPopup(); } @@ -41,4 +29,30 @@ client_->HideAutofillPopup(); } +void AutofillDriverFactory::OnFirstUserGestureObserved() { + if (user_gesture_seen_) + return; + + for (auto& driver : driver_map_) + driver.second->NotifyFirstUserGestureObservedInTab(); + + user_gesture_seen_ = true; +} + +void AutofillDriverFactory::AddForKey( + void* key, + base::Callback<std::unique_ptr<AutofillDriver>()> factory_method) { + auto insertion_result = driver_map_.insert(std::make_pair(key, nullptr)); + // This can be called twice for the key representing the main frame. + if (insertion_result.second) { + insertion_result.first->second = factory_method.Run(); + if (user_gesture_seen_) + insertion_result.first->second->NotifyFirstUserGestureObservedInTab(); + } +} + +void AutofillDriverFactory::DeleteForKey(void* key) { + driver_map_.erase(key); +} + } // namespace autofill
diff --git a/components/autofill/core/browser/autofill_driver_factory.h b/components/autofill/core/browser/autofill_driver_factory.h index 8446d7a..ff48bb6 100644 --- a/components/autofill/core/browser/autofill_driver_factory.h +++ b/components/autofill/core/browser/autofill_driver_factory.h
@@ -17,11 +17,9 @@ class AutofillDriver; // Manages the lifetime of AutofillDrivers for a particular AutofillClient by -// creating, retrieveing and deleting on demand. +// creating, notifying, retrieving and deleting on demand. class AutofillDriverFactory { - // The API is protected to guarantee subclasses that nothing else can - // interfere with the map of drivers. - protected: + public: explicit AutofillDriverFactory(AutofillClient* client); ~AutofillDriverFactory(); @@ -30,8 +28,27 @@ // null if there is none. AutofillDriver* DriverForKey(void* key); + // Handles finished navigation in any of the frames. + void NavigationFinished(); + + // Handles hiding of the corresponding tab. + void TabHidden(); + + // Call this to notify the factory that one of the frames saw a user gesture. + // The factory will distribute this information to all drivers when it comes + // for the first time since the last main frame navigation to a different + // page. It will also notify drivers added later (see AddForKey). + void OnFirstUserGestureObserved(); + + AutofillClient* client() { return client_; }; + + protected: + // The API manipulating the drivers map is protected to guarantee subclasses + // that nothing else can interfere with the map of drivers. + // Adds a driver, constructed by calling |factory_method|, for |key|. If there - // already is a driver for |key|, |factory_method| is not called. + // already is a driver for |key|, |factory_method| is not called. This might + // end up notifying the driver that a user gesture has been observed. void AddForKey( void* key, base::Callback<std::unique_ptr<AutofillDriver>()> factory_method); @@ -39,19 +56,13 @@ // Deletes the AutofillDriver for |key|. void DeleteForKey(void* key); - // Handles finished navigation in any of the frames. - void NavigationFinished(); - - // Handles hiding of the corresponding tab. - void TabHidden(); - - AutofillClient* client() { return client_; }; - private: AutofillClient* const client_; std::unordered_map<void*, std::unique_ptr<AutofillDriver>> driver_map_; + bool user_gesture_seen_ = false; // The state for OnFirstUserGestureObserved. + DISALLOW_COPY_AND_ASSIGN(AutofillDriverFactory); };
diff --git a/components/autofill/core/browser/autofill_driver_factory_unittest.cc b/components/autofill/core/browser/autofill_driver_factory_unittest.cc index e79c4716..8355161 100644 --- a/components/autofill/core/browser/autofill_driver_factory_unittest.cc +++ b/components/autofill/core/browser/autofill_driver_factory_unittest.cc
@@ -25,7 +25,8 @@ }; // Just a stub AutofillDriver implementation which announces its construction -// and desctruction by updating the passed |instance_counter|. +// and desctruction by updating the passed |instance_counter|. It also records +// when "user gesture observed" was signalled to it. class CountingAutofillDriver : public TestAutofillDriver { public: CountingAutofillDriver(int* instance_counter) @@ -35,8 +36,19 @@ ~CountingAutofillDriver() override { --*instance_counter_; } + // Note that EXPECT_CALL cannot be used here, because creation and + // notification of the same driver might be done by a single AddForKey call + // from the test. Therefore tracking the "gesture_observed" flag is done + // explicitly here. + void NotifyFirstUserGestureObservedInTab() override { + gesture_observed_ = true; + } + + bool gesture_observed() { return gesture_observed_; } + private: int* const instance_counter_; + bool gesture_observed_ = false; DISALLOW_COPY_AND_ASSIGN(CountingAutofillDriver); }; @@ -51,11 +63,8 @@ ~PublicAutofillDriverFactory() {} - using AutofillDriverFactory::DriverForKey; using AutofillDriverFactory::AddForKey; using AutofillDriverFactory::DeleteForKey; - using AutofillDriverFactory::NavigationFinished; - using AutofillDriverFactory::TabHidden; }; // Wrapper around an integer, checking that the integer is 0 on desctruction. @@ -85,6 +94,11 @@ // constants. void* KeyFrom(int x) { return reinterpret_cast<void*>(x); } + // Convenience accessor with a cast to CountingAutofillDriver. + CountingAutofillDriver* GetDriver(void* key) { + return static_cast<CountingAutofillDriver*>(factory_.DriverForKey(key)); + } + std::unique_ptr<AutofillDriver> CreateDriver() { ++drivers_created_; return base::MakeUnique<CountingAutofillDriver>(instance_counter_.val()); @@ -173,4 +187,54 @@ factory_.TabHidden(); } +// Without calling OnFirstUserGestureObserved on the factory, the factory will +// not call NotifyFirstUserGestureObservedInTab on a driver. +TEST_F(AutofillDriverFactoryTest, OnFirstUserGestureObserved_NotCalled) { + factory_.AddForKey(KeyFrom(1), CreateDriverCallback()); + EXPECT_FALSE(GetDriver(KeyFrom(1))->gesture_observed()); +} + +// Call OnFirstUserGestureObserved on the factory with one driver. The factory +// will call NotifyFirstUserGestureObservedInTab on that driver. +TEST_F(AutofillDriverFactoryTest, OnFirstUserGestureObserved_CalledOld) { + factory_.AddForKey(KeyFrom(1), CreateDriverCallback()); + factory_.OnFirstUserGestureObserved(); + EXPECT_TRUE(GetDriver(KeyFrom(1))->gesture_observed()); +} + +// Call OnFirstUserGestureObserved on the factory without drivers. Add a +// driver. The factory will call NotifyFirstUserGestureObservedInTab on that +// driver. +TEST_F(AutofillDriverFactoryTest, OnFirstUserGestureObserved_CalledNew) { + factory_.OnFirstUserGestureObserved(); + factory_.AddForKey(KeyFrom(1), CreateDriverCallback()); + EXPECT_TRUE(GetDriver(KeyFrom(1))->gesture_observed()); +} + +// Combining the CalledOld and CalledNew test cases into one. +TEST_F(AutofillDriverFactoryTest, OnFirstUserGestureObserved_MultipleDrivers) { + factory_.AddForKey(KeyFrom(1), CreateDriverCallback()); + factory_.OnFirstUserGestureObserved(); + EXPECT_TRUE(GetDriver(KeyFrom(1))->gesture_observed()); + + factory_.AddForKey(KeyFrom(7), CreateDriverCallback()); + EXPECT_TRUE(GetDriver(KeyFrom(7))->gesture_observed()); +} + +// Call OnFirstUserGestureObserved on the factory with one driver. Simulate +// navigation to a different page. Add a driver. The factory will not call +// NotifyFirstUserGestureObservedInTab on that driver. +TEST_F(AutofillDriverFactoryTest, OnFirstUserGestureObserved_CalledNavigation) { + factory_.AddForKey(KeyFrom(1), CreateDriverCallback()); + factory_.OnFirstUserGestureObserved(); + EXPECT_TRUE(GetDriver(KeyFrom(1))->gesture_observed()); + + EXPECT_CALL(client_, HideAutofillPopup()); + factory_.NavigationFinished(); + + // Adding a sub-frame + factory_.AddForKey(KeyFrom(2), CreateDriverCallback()); + EXPECT_FALSE(GetDriver(KeyFrom(2))->gesture_observed()); +} + } // namespace autofill
diff --git a/components/nacl/browser/pnacl_translation_cache.cc b/components/nacl/browser/pnacl_translation_cache.cc index a183d59..1f71fe39 100644 --- a/components/nacl/browser/pnacl_translation_cache.cc +++ b/components/nacl/browser/pnacl_translation_cache.cc
@@ -42,7 +42,7 @@ // operations. It also tracks the open disk_cache::Entry // and ensures that the entry is closed. class PnaclTranslationCacheEntry - : public base::RefCounted<PnaclTranslationCacheEntry> { + : public base::RefCountedThreadSafe<PnaclTranslationCacheEntry> { public: static PnaclTranslationCacheEntry* GetReadEntry( base::WeakPtr<PnaclTranslationCache> cache, @@ -76,7 +76,7 @@ }; private: - friend class base::RefCounted<PnaclTranslationCacheEntry>; + friend class base::RefCountedThreadSafe<PnaclTranslationCacheEntry>; PnaclTranslationCacheEntry(base::WeakPtr<PnaclTranslationCache> cache, const std::string& key, bool is_read);
diff --git a/components/omnibox/browser/in_memory_url_index_types.cc b/components/omnibox/browser/in_memory_url_index_types.cc index 9718068..69798d1 100644 --- a/components/omnibox/browser/in_memory_url_index_types.cc +++ b/components/omnibox/browser/in_memory_url_index_types.cc
@@ -62,10 +62,9 @@ std::vector<size_t> OffsetsFromTermMatches(const TermMatches& matches) { std::vector<size_t> offsets; - for (TermMatches::const_iterator i = matches.begin(); i != matches.end(); - ++i) { - offsets.push_back(i->offset); - offsets.push_back(i->offset + i->length); + for (const auto& match : matches) { + offsets.push_back(match.offset); + offsets.push_back(match.offset + match.length); } return offsets; } @@ -98,11 +97,10 @@ WordStarts* word_starts) { String16Vector words = String16VectorFromString16(cleaned_uni_string, false, word_starts); - String16Set word_set; - for (String16Vector::const_iterator iter = words.begin(); iter != words.end(); - ++iter) - word_set.insert(base::i18n::ToLower(*iter).substr(0, kMaxSignificantChars)); - return word_set; + for (auto& word : words) + word = base::i18n::ToLower(word).substr(0, kMaxSignificantChars); + return String16Set(std::make_move_iterator(words.begin()), + std::make_move_iterator(words.end())); } String16Vector String16VectorFromString16( @@ -141,25 +139,29 @@ } Char16Set Char16SetFromString16(const base::string16& term) { - Char16Set characters; - for (base::string16::const_iterator iter = term.begin(); iter != term.end(); - ++iter) - characters.insert(*iter); - return characters; + return Char16Set(term.begin(), term.end()); } // HistoryInfoMapValue --------------------------------------------------------- -HistoryInfoMapValue::HistoryInfoMapValue() {} +HistoryInfoMapValue::HistoryInfoMapValue() = default; HistoryInfoMapValue::HistoryInfoMapValue(const HistoryInfoMapValue& other) = default; -HistoryInfoMapValue::~HistoryInfoMapValue() {} +HistoryInfoMapValue::HistoryInfoMapValue(HistoryInfoMapValue&& other) = default; +HistoryInfoMapValue& HistoryInfoMapValue::operator=( + const HistoryInfoMapValue& other) = default; +HistoryInfoMapValue& HistoryInfoMapValue::operator=( + HistoryInfoMapValue&& other) = default; +HistoryInfoMapValue::~HistoryInfoMapValue() = default; // RowWordStarts --------------------------------------------------------------- -RowWordStarts::RowWordStarts() {} +RowWordStarts::RowWordStarts() = default; RowWordStarts::RowWordStarts(const RowWordStarts& other) = default; -RowWordStarts::~RowWordStarts() {} +RowWordStarts::RowWordStarts(RowWordStarts&& other) = default; +RowWordStarts& RowWordStarts::operator=(const RowWordStarts& other) = default; +RowWordStarts& RowWordStarts::operator=(RowWordStarts&& other) = default; +RowWordStarts::~RowWordStarts() = default; void RowWordStarts::Clear() { url_word_starts_.clear();
diff --git a/components/omnibox/browser/in_memory_url_index_types.h b/components/omnibox/browser/in_memory_url_index_types.h index 070ba43..6d38a79f 100644 --- a/components/omnibox/browser/in_memory_url_index_types.h +++ b/components/omnibox/browser/in_memory_url_index_types.h
@@ -147,6 +147,9 @@ struct HistoryInfoMapValue { HistoryInfoMapValue(); HistoryInfoMapValue(const HistoryInfoMapValue& other); + HistoryInfoMapValue(HistoryInfoMapValue&& other); + HistoryInfoMapValue& operator=(const HistoryInfoMapValue& other); + HistoryInfoMapValue& operator=(HistoryInfoMapValue&& other); ~HistoryInfoMapValue(); // This field is always populated. @@ -166,6 +169,9 @@ struct RowWordStarts { RowWordStarts(); RowWordStarts(const RowWordStarts& other); + RowWordStarts(RowWordStarts&& other); + RowWordStarts& operator=(const RowWordStarts& other); + RowWordStarts& operator=(RowWordStarts&& other); ~RowWordStarts(); // Clears both url_word_starts_ and title_word_starts_.
diff --git a/components/omnibox/browser/in_memory_url_index_unittest.cc b/components/omnibox/browser/in_memory_url_index_unittest.cc index 1e08dce..14996f64d 100644 --- a/components/omnibox/browser/in_memory_url_index_unittest.cc +++ b/components/omnibox/browser/in_memory_url_index_unittest.cc
@@ -7,6 +7,7 @@ #include <algorithm> #include <fstream> +#include <numeric> #include "base/auto_reset.h" #include "base/files/file_path.h" @@ -738,15 +739,13 @@ }; auto GetHistoryIdsUpTo = [&](HistoryID max) { - HistoryIDSet res; - // All ids are inserted in the end so the implicit hint would work. - for (HistoryID id = kMinRowId; id < max; ++id) - res.insert(id); + HistoryIDVector res(max - kMinRowId); + std::iota(res.begin(), res.end(), kMinRowId); return res; }; auto CountGroupElementsInIds = [](const ItemGroup& group, - const HistoryIDSet& ids) { + const HistoryIDVector& ids) { return std::count_if(ids.begin(), ids.end(), [&](history::URLID id) { return group.min_id <= id && id < group.max_id; });
diff --git a/components/omnibox/browser/scored_history_match.cc b/components/omnibox/browser/scored_history_match.cc index 5dddb3f..f0424978 100644 --- a/components/omnibox/browser/scored_history_match.cc +++ b/components/omnibox/browser/scored_history_match.cc
@@ -320,9 +320,12 @@ ScoredHistoryMatch::ScoredHistoryMatch(const ScoredHistoryMatch& other) = default; - -ScoredHistoryMatch::~ScoredHistoryMatch() { -} +ScoredHistoryMatch::ScoredHistoryMatch(ScoredHistoryMatch&& other) = default; +ScoredHistoryMatch& ScoredHistoryMatch::operator=( + const ScoredHistoryMatch& other) = default; +ScoredHistoryMatch& ScoredHistoryMatch::operator=(ScoredHistoryMatch&& other) = + default; +ScoredHistoryMatch::~ScoredHistoryMatch() = default; // Comparison function for sorting ScoredMatches by their scores with // intelligent tie-breaking.
diff --git a/components/omnibox/browser/scored_history_match.h b/components/omnibox/browser/scored_history_match.h index 51d18835..f9c432a 100644 --- a/components/omnibox/browser/scored_history_match.h +++ b/components/omnibox/browser/scored_history_match.h
@@ -37,6 +37,9 @@ // Required for STL, we don't use this directly. ScoredHistoryMatch(); ScoredHistoryMatch(const ScoredHistoryMatch& other); + ScoredHistoryMatch(ScoredHistoryMatch&& other); + ScoredHistoryMatch& operator=(const ScoredHistoryMatch& other); + ScoredHistoryMatch& operator=(ScoredHistoryMatch&& other); // Initializes the ScoredHistoryMatch with a raw score calculated for the // history item given in |row| with recent visits as indicated in |visits|. It
diff --git a/components/omnibox/browser/url_index_private_data.cc b/components/omnibox/browser/url_index_private_data.cc index 6556116c..e410239 100644 --- a/components/omnibox/browser/url_index_private_data.cc +++ b/components/omnibox/browser/url_index_private_data.cc
@@ -37,6 +37,8 @@ #include "third_party/protobuf/src/google/protobuf/repeated_field.h" #endif +namespace { + using google::protobuf::RepeatedField; using google::protobuf::RepeatedPtrField; using in_memory_url_index::InMemoryURLIndexCacheItem; @@ -77,6 +79,7 @@ return string_a.length() > string_b.length(); } +} // namespace // UpdateRecentVisitsFromHistoryDBTask ----------------------------------------- @@ -187,22 +190,20 @@ net::UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS); // Extract individual 'words' (as opposed to 'terms'; see comment in - // HistoryIdSetToScoredMatches()) from the search string. When the user - // types "colspec=ID%20Mstone Release" we get four 'words': "colspec", "id", + // HistoryIdsToScoredMatches()) from the search string. When the user types + // "colspec=ID%20Mstone Release" we get four 'words': "colspec", "id", // "mstone" and "release". String16Vector lower_words( String16VectorFromString16(lower_unescaped_string, false, nullptr)); if (lower_words.empty()) continue; - HistoryIDSet history_id_set = HistoryIDSetFromWords(lower_words); - history_ids_were_trimmed |= TrimHistoryIdsPool(&history_id_set); - ScoredHistoryMatches temp_scored_items; - HistoryIdSetToScoredMatches(history_id_set, lower_raw_string, - template_url_service, bookmark_model, - &temp_scored_items); - scored_items.insert(scored_items.end(), temp_scored_items.begin(), - temp_scored_items.end()); + HistoryIDVector history_ids = HistoryIDsFromWords(lower_words); + history_ids_were_trimmed |= TrimHistoryIdsPool(&history_ids); + + HistoryIdsToScoredMatches(std::move(history_ids), lower_raw_string, + template_url_service, bookmark_model, + &scored_items); } // Select and sort only the top |max_matches| results. if (scored_items.size() > max_matches) { @@ -452,7 +453,7 @@ void URLIndexPrivateData::Clear() { last_time_rebuilt_from_history_ = base::Time(); word_list_.clear(); - available_words_.clear(); + available_words_ = std::stack<WordID>(); word_map_.clear(); char_word_map_.clear(); word_id_history_map_.clear(); @@ -463,57 +464,56 @@ URLIndexPrivateData::~URLIndexPrivateData() {} -HistoryIDSet URLIndexPrivateData::HistoryIDSetFromWords( +HistoryIDVector URLIndexPrivateData::HistoryIDsFromWords( const String16Vector& unsorted_words) { + // This histogram name reflects the historic name of this function. SCOPED_UMA_HISTOGRAM_TIMER("Omnibox.HistoryQuickHistoryIDSetFromWords"); // Break the terms down into individual terms (words), get the candidate // set for each term, and intersect each to get a final candidate list. // Note that a single 'term' from the user's perspective might be // a string like "http://www.somewebsite.com" which, from our perspective, // is four words: 'http', 'www', 'somewebsite', and 'com'. - HistoryIDSet history_id_set; + HistoryIDVector history_ids; String16Vector words(unsorted_words); // Sort the words into the longest first as such are likely to narrow down // the results quicker. Also, single character words are the most expensive // to process so save them for last. std::sort(words.begin(), words.end(), LengthGreater); + + // TODO(dyaroshev): write a generic algorithm(crbug.com/696167). for (String16Vector::iterator iter = words.begin(); iter != words.end(); ++iter) { base::string16 uni_word = *iter; HistoryIDSet term_history_set = HistoryIDsForTerm(uni_word); if (term_history_set.empty()) { - history_id_set.clear(); + history_ids.clear(); break; } if (iter == words.begin()) { - history_id_set.swap(term_history_set); + history_ids = {term_history_set.begin(), term_history_set.end()}; } else { - HistoryIDSet new_history_id_set = base::STLSetIntersection<HistoryIDSet>( - history_id_set, term_history_set); - history_id_set.swap(new_history_id_set); + history_ids = base::STLSetIntersection<HistoryIDVector>(history_ids, + term_history_set); } } - return history_id_set; + return history_ids; } bool URLIndexPrivateData::TrimHistoryIdsPool( - HistoryIDSet* history_id_set) const { + HistoryIDVector* history_ids) const { constexpr size_t kItemsToScoreLimit = 500; - if (history_id_set->size() <= kItemsToScoreLimit) + if (history_ids->size() <= kItemsToScoreLimit) return false; - HistoryIDVector history_ids(history_id_set->begin(), history_id_set->end()); - // Trim down the set by sorting by typed-count, visit-count, and last // visit. - auto new_end = history_ids.begin() + kItemsToScoreLimit; + auto new_end = history_ids->begin() + kItemsToScoreLimit; HistoryItemFactorGreater item_factor_functor(history_info_map_); - std::nth_element(history_ids.begin(), new_end, history_ids.end(), + std::nth_element(history_ids->begin(), new_end, history_ids->end(), item_factor_functor); - history_ids.erase(new_end, history_ids.end()); + history_ids->erase(new_end, history_ids->end()); - *history_id_set = {history_ids.begin(), history_ids.end()}; return true; } @@ -581,13 +581,9 @@ return HistoryIDSet(); } // Or there may not have been a prefix from which to start. - if (prefix_chars.empty()) { - word_id_set.swap(leftover_set); - } else { - WordIDSet new_word_id_set = base::STLSetIntersection<WordIDSet>( - word_id_set, leftover_set); - word_id_set.swap(new_word_id_set); - } + word_id_set = prefix_chars.empty() ? std::move(leftover_set) + : base::STLSetIntersection<WordIDSet>( + word_id_set, leftover_set); } // We must filter the word list because the resulting word set surely @@ -606,16 +602,12 @@ // If any words resulted then we can compose a set of history IDs by unioning // the sets from each word. HistoryIDSet history_id_set; - if (!word_id_set.empty()) { - for (WordIDSet::iterator word_id_iter = word_id_set.begin(); - word_id_iter != word_id_set.end(); ++word_id_iter) { - WordID word_id = *word_id_iter; - WordIDHistoryMap::iterator word_iter = word_id_history_map_.find(word_id); - if (word_iter != word_id_history_map_.end()) { - HistoryIDSet& word_history_id_set(word_iter->second); - history_id_set.insert(word_history_id_set.begin(), - word_history_id_set.end()); - } + for (WordID word_id : word_id_set) { + WordIDHistoryMap::iterator word_iter = word_id_history_map_.find(word_id); + if (word_iter != word_id_history_map_.end()) { + HistoryIDSet& word_history_id_set(word_iter->second); + history_id_set.insert(word_history_id_set.begin(), + word_history_id_set.end()); } } @@ -629,6 +621,8 @@ WordIDSet URLIndexPrivateData::WordIDSetForTermChars( const Char16Set& term_chars) { + // TODO(dyaroshev): write a generic algorithm(crbug.com/696167). + WordIDSet word_id_set; for (Char16Set::const_iterator c_iter = term_chars.begin(); c_iter != term_chars.end(); ++c_iter) { @@ -651,21 +645,20 @@ word_id_set = char_word_id_set; } else { // Subsequent character results get intersected in. - WordIDSet new_word_id_set = base::STLSetIntersection<WordIDSet>( - word_id_set, char_word_id_set); - word_id_set.swap(new_word_id_set); + word_id_set = + base::STLSetIntersection<WordIDSet>(word_id_set, char_word_id_set); } } return word_id_set; } -void URLIndexPrivateData::HistoryIdSetToScoredMatches( - HistoryIDSet history_id_set, +void URLIndexPrivateData::HistoryIdsToScoredMatches( + HistoryIDVector history_ids, const base::string16& lower_raw_string, const TemplateURLService* template_url_service, bookmarks::BookmarkModel* bookmark_model, ScoredHistoryMatches* scored_items) const { - if (history_id_set.empty()) + if (history_ids.empty()) return; // Break up the raw search string (complete with escaped URL elements) into @@ -693,41 +686,32 @@ &lower_terms_to_word_starts_offsets); // Filter bad matches and other matches we don't want to display. - for (auto it = history_id_set.begin();;) { - it = std::find_if(it, history_id_set.end(), - [this, template_url_service](const HistoryID history_id) { - return ShouldFilter(history_id, template_url_service); - }); - if (it == history_id_set.end()) - break; - it = history_id_set.erase(it); - } + auto filter = [this, template_url_service](const HistoryID history_id) { + return ShouldFilter(history_id, template_url_service); + }; + history_ids.erase( + std::remove_if(history_ids.begin(), history_ids.end(), filter), + history_ids.end()); // Score the matches. - const size_t num_matches = history_id_set.size(); + const size_t num_matches = history_ids.size(); const base::Time now = base::Time::Now(); - std::transform( - history_id_set.begin(), history_id_set.end(), - std::back_inserter(*scored_items), [&](const HistoryID history_id) { - auto hist_pos = history_info_map_.find(history_id); - const history::URLRow& hist_item = hist_pos->second.url_row; - auto starts_pos = word_starts_map_.find(history_id); - DCHECK(starts_pos != word_starts_map_.end()); - return ScoredHistoryMatch( - hist_item, hist_pos->second.visits, lower_raw_string, - lower_raw_terms, lower_terms_to_word_starts_offsets, - starts_pos->second, - bookmark_model && bookmark_model->IsBookmarked(hist_item.url()), - num_matches, now); - }); - // Filter all matches that ended up scoring 0. (These are usually matches - // which didn't match the user's raw terms.) - scored_items->erase(std::remove_if(scored_items->begin(), scored_items->end(), - [](const ScoredHistoryMatch& match) { - return match.raw_score == 0; - }), - scored_items->end()); + for (HistoryID history_id : history_ids) { + auto hist_pos = history_info_map_.find(history_id); + const history::URLRow& hist_item = hist_pos->second.url_row; + auto starts_pos = word_starts_map_.find(history_id); + DCHECK(starts_pos != word_starts_map_.end()); + ScoredHistoryMatch new_scored_match( + hist_item, hist_pos->second.visits, lower_raw_string, lower_raw_terms, + lower_terms_to_word_starts_offsets, starts_pos->second, + bookmark_model && bookmark_model->IsBookmarked(hist_item.url()), + num_matches, now); + // Filter new matches that ended up scoring 0. (These are usually matches + // which didn't match the user's raw terms.) + if (new_scored_match.raw_score != 0) + scored_items->push_back(std::move(new_scored_match)); + } } // static @@ -819,80 +803,44 @@ const base::string16& title = bookmarks::CleanUpTitleForMatching(row.title()); String16Set title_words = String16SetFromString16(title, word_starts ? &word_starts->title_word_starts_ : nullptr); - String16Set words = base::STLSetUnion<String16Set>(url_words, title_words); - for (String16Set::iterator word_iter = words.begin(); - word_iter != words.end(); ++word_iter) - AddWordToIndex(*word_iter, history_id); + for (const auto& word : + base::STLSetUnion<String16Set>(url_words, title_words)) + AddWordToIndex(word, history_id); search_term_cache_.clear(); // Invalidate the term cache. } void URLIndexPrivateData::AddWordToIndex(const base::string16& term, HistoryID history_id) { - WordMap::iterator word_pos = word_map_.find(term); - if (word_pos != word_map_.end()) - UpdateWordHistory(word_pos->second, history_id); - else - AddWordHistory(term, history_id); + WordMap::iterator word_pos; + bool is_new; + std::tie(word_pos, is_new) = word_map_.insert(std::make_pair(term, WordID())); + + // Adding a new word (i.e. a word that is not already in the word index). + if (is_new) { + word_pos->second = AddNewWordToWordList(term); + + // For each character in the newly added word add the word to the character + // index. + for (base::char16 uni_char : Char16SetFromString16(term)) + char_word_map_[uni_char].insert(word_pos->second); + } + + word_id_history_map_[word_pos->second].insert(history_id); + history_id_word_map_[history_id].insert(word_pos->second); } -void URLIndexPrivateData::AddWordHistory(const base::string16& term, - HistoryID history_id) { +WordID URLIndexPrivateData::AddNewWordToWordList(const base::string16& term) { WordID word_id = word_list_.size(); if (available_words_.empty()) { word_list_.push_back(term); - } else { - word_id = *(available_words_.begin()); - word_list_[word_id] = term; - available_words_.erase(word_id); + return word_id; } - word_map_[term] = word_id; - HistoryIDSet history_id_set; - history_id_set.insert(history_id); - word_id_history_map_[word_id] = history_id_set; - AddToHistoryIDWordMap(history_id, word_id); - - // For each character in the newly added word (i.e. a word that is not - // already in the word index), add the word to the character index. - Char16Set characters = Char16SetFromString16(term); - for (Char16Set::iterator uni_char_iter = characters.begin(); - uni_char_iter != characters.end(); ++uni_char_iter) { - base::char16 uni_char = *uni_char_iter; - CharWordIDMap::iterator char_iter = char_word_map_.find(uni_char); - if (char_iter != char_word_map_.end()) { - // Update existing entry in the char/word index. - WordIDSet& word_id_set(char_iter->second); - word_id_set.insert(word_id); - } else { - // Create a new entry in the char/word index. - WordIDSet word_id_set; - word_id_set.insert(word_id); - char_word_map_[uni_char] = word_id_set; - } - } -} - -void URLIndexPrivateData::UpdateWordHistory(WordID word_id, - HistoryID history_id) { - WordIDHistoryMap::iterator history_pos = word_id_history_map_.find(word_id); - DCHECK(history_pos != word_id_history_map_.end()); - HistoryIDSet& history_id_set(history_pos->second); - history_id_set.insert(history_id); - AddToHistoryIDWordMap(history_id, word_id); -} - -void URLIndexPrivateData::AddToHistoryIDWordMap(HistoryID history_id, - WordID word_id) { - HistoryIDWordMap::iterator iter = history_id_word_map_.find(history_id); - if (iter != history_id_word_map_.end()) { - WordIDSet& word_id_set(iter->second); - word_id_set.insert(word_id); - } else { - WordIDSet word_id_set; - word_id_set.insert(word_id); - history_id_word_map_[history_id] = word_id_set; - } + word_id = available_words_.top(); + available_words_.pop(); + word_list_[word_id] = term; + return word_id; } void URLIndexPrivateData::RemoveRowFromIndex(const history::URLRow& row) { @@ -910,36 +858,34 @@ history_id_word_map_.erase(history_id); // Reconcile any changes to word usage. - for (WordIDSet::iterator word_id_iter = word_id_set.begin(); - word_id_iter != word_id_set.end(); ++word_id_iter) { - WordID word_id = *word_id_iter; - word_id_history_map_[word_id].erase(history_id); - if (!word_id_history_map_[word_id].empty()) - continue; // The word is still in use. + for (WordID word_id : word_id_set) { + auto word_id_history_map_iter = word_id_history_map_.find(word_id); + DCHECK(word_id_history_map_iter != word_id_history_map_.end()); + + word_id_history_map_iter->second.erase(history_id); + if (!word_id_history_map_iter->second.empty()) + continue; // The word is no longer in use. Reconcile any changes to character usage. base::string16 word = word_list_[word_id]; - Char16Set characters = Char16SetFromString16(word); - for (Char16Set::iterator uni_char_iter = characters.begin(); - uni_char_iter != characters.end(); ++uni_char_iter) { - base::char16 uni_char = *uni_char_iter; - char_word_map_[uni_char].erase(word_id); - if (char_word_map_[uni_char].empty()) - char_word_map_.erase(uni_char); // No longer in use. + for (base::char16 uni_char : Char16SetFromString16(word)) { + auto char_word_map_iter = char_word_map_.find(uni_char); + char_word_map_iter->second.erase(word_id); + if (char_word_map_iter->second.empty()) + char_word_map_.erase(char_word_map_iter); } // Complete the removal of references to the word. - word_id_history_map_.erase(word_id); + word_id_history_map_.erase(word_id_history_map_iter); word_map_.erase(word); word_list_[word_id] = base::string16(); - available_words_.insert(word_id); + available_words_.push(word_id); } } void URLIndexPrivateData::ResetSearchTermCache() { - for (SearchTermCacheMap::iterator iter = search_term_cache_.begin(); - iter != search_term_cache_.end(); ++iter) - iter->second.used_ = false; + for (auto& item : search_term_cache_) + item.second.used_ = false; } bool URLIndexPrivateData::SaveToFile(const base::FilePath& file_path) { @@ -984,9 +930,8 @@ return; WordListItem* list_item = cache->mutable_word_list(); list_item->set_word_count(word_list_.size()); - for (String16Vector::const_iterator iter = word_list_.begin(); - iter != word_list_.end(); ++iter) - list_item->add_word(base::UTF16ToUTF8(*iter)); + for (const base::string16& word : word_list_) + list_item->add_word(base::UTF16ToUTF8(word)); } void URLIndexPrivateData::SaveWordMap(InMemoryURLIndexCacheItem* cache) const { @@ -994,11 +939,10 @@ return; WordMapItem* map_item = cache->mutable_word_map(); map_item->set_item_count(word_map_.size()); - for (WordMap::const_iterator iter = word_map_.begin(); - iter != word_map_.end(); ++iter) { + for (const auto& elem : word_map_) { WordMapEntry* map_entry = map_item->add_word_map_entry(); - map_entry->set_word(base::UTF16ToUTF8(iter->first)); - map_entry->set_word_id(iter->second); + map_entry->set_word(base::UTF16ToUTF8(elem.first)); + map_entry->set_word_id(elem.second); } } @@ -1008,15 +952,13 @@ return; CharWordMapItem* map_item = cache->mutable_char_word_map(); map_item->set_item_count(char_word_map_.size()); - for (CharWordIDMap::const_iterator iter = char_word_map_.begin(); - iter != char_word_map_.end(); ++iter) { + for (const auto& entry : char_word_map_) { CharWordMapEntry* map_entry = map_item->add_char_word_map_entry(); - map_entry->set_char_16(iter->first); - const WordIDSet& word_id_set(iter->second); + map_entry->set_char_16(entry.first); + const WordIDSet& word_id_set = entry.second; map_entry->set_item_count(word_id_set.size()); - for (WordIDSet::const_iterator set_iter = word_id_set.begin(); - set_iter != word_id_set.end(); ++set_iter) - map_entry->add_word_id(*set_iter); + for (WordID word_id : word_id_set) + map_entry->add_word_id(word_id); } } @@ -1026,16 +968,14 @@ return; WordIDHistoryMapItem* map_item = cache->mutable_word_id_history_map(); map_item->set_item_count(word_id_history_map_.size()); - for (WordIDHistoryMap::const_iterator iter = word_id_history_map_.begin(); - iter != word_id_history_map_.end(); ++iter) { + for (const auto& entry : word_id_history_map_) { WordIDHistoryMapEntry* map_entry = map_item->add_word_id_history_map_entry(); - map_entry->set_word_id(iter->first); - const HistoryIDSet& history_id_set(iter->second); + map_entry->set_word_id(entry.first); + const HistoryIDSet& history_id_set = entry.second; map_entry->set_item_count(history_id_set.size()); - for (HistoryIDSet::const_iterator set_iter = history_id_set.begin(); - set_iter != history_id_set.end(); ++set_iter) - map_entry->add_history_id(*set_iter); + for (HistoryID history_id : history_id_set) + map_entry->add_history_id(history_id); } } @@ -1045,11 +985,10 @@ return; HistoryInfoMapItem* map_item = cache->mutable_history_info_map(); map_item->set_item_count(history_info_map_.size()); - for (HistoryInfoMap::const_iterator iter = history_info_map_.begin(); - iter != history_info_map_.end(); ++iter) { + for (const auto& entry : history_info_map_) { HistoryInfoMapEntry* map_entry = map_item->add_history_info_map_entry(); - map_entry->set_history_id(iter->first); - const history::URLRow& url_row(iter->second.url_row); + map_entry->set_history_id(entry.first); + const history::URLRow& url_row = entry.second.url_row; // Note: We only save information that contributes to the index so there // is no need to save search_term_cache_ (not persistent). map_entry->set_visit_count(url_row.visit_count()); @@ -1057,12 +996,10 @@ map_entry->set_last_visit(url_row.last_visit().ToInternalValue()); map_entry->set_url(url_row.url().spec()); map_entry->set_title(base::UTF16ToUTF8(url_row.title())); - const VisitInfoVector& visits(iter->second.visits); - for (VisitInfoVector::const_iterator visit_iter = visits.begin(); - visit_iter != visits.end(); ++visit_iter) { + for (const auto& visit : entry.second.visits) { HistoryInfoMapEntry_VisitInfo* visit_info = map_entry->add_visits(); - visit_info->set_visit_time(visit_iter->first.ToInternalValue()); - visit_info->set_transition_type(visit_iter->second); + visit_info->set_visit_time(visit.first.ToInternalValue()); + visit_info->set_transition_type(visit.second); } } } @@ -1081,17 +1018,14 @@ WordStartsMapItem* map_item = cache->mutable_word_starts_map(); map_item->set_item_count(word_starts_map_.size()); - for (WordStartsMap::const_iterator iter = word_starts_map_.begin(); - iter != word_starts_map_.end(); ++iter) { + for (const auto& entry : word_starts_map_) { WordStartsMapEntry* map_entry = map_item->add_word_starts_map_entry(); - map_entry->set_history_id(iter->first); - const RowWordStarts& word_starts(iter->second); - for (WordStarts::const_iterator i = word_starts.url_word_starts_.begin(); - i != word_starts.url_word_starts_.end(); ++i) - map_entry->add_url_word_starts(*i); - for (WordStarts::const_iterator i = word_starts.title_word_starts_.begin(); - i != word_starts.title_word_starts_.end(); ++i) - map_entry->add_title_word_starts(*i); + map_entry->set_history_id(entry.first); + const RowWordStarts& word_starts = entry.second; + for (auto url_word_start : word_starts.url_word_starts_) + map_entry->add_url_word_starts(url_word_start); + for (auto title_word_start : word_starts.title_word_starts_) + map_entry->add_title_word_starts(title_word_start); } } @@ -1133,10 +1067,11 @@ uint32_t actual_item_count = list_item.word_size(); if (actual_item_count == 0 || actual_item_count != expected_item_count) return false; - const RepeatedPtrField<std::string>& words(list_item.word()); - for (RepeatedPtrField<std::string>::const_iterator iter = words.begin(); - iter != words.end(); ++iter) - word_list_.push_back(base::UTF8ToUTF16(*iter)); + const RepeatedPtrField<std::string>& words = list_item.word(); + word_list_.reserve(words.size()); + std::transform( + words.begin(), words.end(), std::back_inserter(word_list_), + [](const std::string& word) { return base::UTF8ToUTF16(word); }); return true; } @@ -1144,15 +1079,14 @@ const InMemoryURLIndexCacheItem& cache) { if (!cache.has_word_map()) return false; - const WordMapItem& list_item(cache.word_map()); + const WordMapItem& list_item = cache.word_map(); uint32_t expected_item_count = list_item.item_count(); uint32_t actual_item_count = list_item.word_map_entry_size(); if (actual_item_count == 0 || actual_item_count != expected_item_count) return false; - const RepeatedPtrField<WordMapEntry>& entries(list_item.word_map_entry()); - for (RepeatedPtrField<WordMapEntry>::const_iterator iter = entries.begin(); - iter != entries.end(); ++iter) - word_map_[base::UTF8ToUTF16(iter->word())] = iter->word_id(); + for (const auto& entry : list_item.word_map_entry()) + word_map_[base::UTF8ToUTF16(entry.word())] = entry.word_id(); + return true; } @@ -1165,21 +1099,15 @@ uint32_t actual_item_count = list_item.char_word_map_entry_size(); if (actual_item_count == 0 || actual_item_count != expected_item_count) return false; - const RepeatedPtrField<CharWordMapEntry>& - entries(list_item.char_word_map_entry()); - for (RepeatedPtrField<CharWordMapEntry>::const_iterator iter = - entries.begin(); iter != entries.end(); ++iter) { - expected_item_count = iter->item_count(); - actual_item_count = iter->word_id_size(); + + for (const auto& entry : list_item.char_word_map_entry()) { + expected_item_count = entry.item_count(); + actual_item_count = entry.word_id_size(); if (actual_item_count == 0 || actual_item_count != expected_item_count) return false; - base::char16 uni_char = static_cast<base::char16>(iter->char_16()); - WordIDSet word_id_set; - const RepeatedField<int32_t>& word_ids(iter->word_id()); - for (RepeatedField<int32_t>::const_iterator jiter = word_ids.begin(); - jiter != word_ids.end(); ++jiter) - word_id_set.insert(*jiter); - char_word_map_[uni_char] = word_id_set; + base::char16 uni_char = static_cast<base::char16>(entry.char_16()); + const RepeatedField<int32_t>& word_ids = entry.word_id(); + char_word_map_[uni_char] = {word_ids.begin(), word_ids.end()}; } return true; } @@ -1193,23 +1121,16 @@ uint32_t actual_item_count = list_item.word_id_history_map_entry_size(); if (actual_item_count == 0 || actual_item_count != expected_item_count) return false; - const RepeatedPtrField<WordIDHistoryMapEntry>& - entries(list_item.word_id_history_map_entry()); - for (RepeatedPtrField<WordIDHistoryMapEntry>::const_iterator iter = - entries.begin(); iter != entries.end(); ++iter) { - expected_item_count = iter->item_count(); - actual_item_count = iter->history_id_size(); + for (const auto& entry : list_item.word_id_history_map_entry()) { + expected_item_count = entry.item_count(); + actual_item_count = entry.history_id_size(); if (actual_item_count == 0 || actual_item_count != expected_item_count) return false; - WordID word_id = iter->word_id(); - HistoryIDSet history_id_set; - const RepeatedField<int64_t>& history_ids(iter->history_id()); - for (RepeatedField<int64_t>::const_iterator jiter = history_ids.begin(); - jiter != history_ids.end(); ++jiter) { - history_id_set.insert(*jiter); - AddToHistoryIDWordMap(*jiter, word_id); - } - word_id_history_map_[word_id] = history_id_set; + WordID word_id = entry.word_id(); + const RepeatedField<int64_t>& history_ids = entry.history_id(); + word_id_history_map_[word_id] = {history_ids.begin(), history_ids.end()}; + for (HistoryID history_id : history_ids) + history_id_word_map_[history_id].insert(word_id); } return true; } @@ -1223,31 +1144,26 @@ uint32_t actual_item_count = list_item.history_info_map_entry_size(); if (actual_item_count == 0 || actual_item_count != expected_item_count) return false; - const RepeatedPtrField<HistoryInfoMapEntry>& - entries(list_item.history_info_map_entry()); - for (RepeatedPtrField<HistoryInfoMapEntry>::const_iterator iter = - entries.begin(); iter != entries.end(); ++iter) { - HistoryID history_id = iter->history_id(); - GURL url(iter->url()); - history::URLRow url_row(url, history_id); - url_row.set_visit_count(iter->visit_count()); - url_row.set_typed_count(iter->typed_count()); - url_row.set_last_visit(base::Time::FromInternalValue(iter->last_visit())); - if (iter->has_title()) { - base::string16 title(base::UTF8ToUTF16(iter->title())); - url_row.set_title(title); - } - history_info_map_[history_id].url_row = url_row; + + for (const auto& entry : list_item.history_info_map_entry()) { + HistoryID history_id = entry.history_id(); + history::URLRow url_row(GURL(entry.url()), history_id); + url_row.set_visit_count(entry.visit_count()); + url_row.set_typed_count(entry.typed_count()); + url_row.set_last_visit(base::Time::FromInternalValue(entry.last_visit())); + if (entry.has_title()) + url_row.set_title(base::UTF8ToUTF16(entry.title())); + history_info_map_[history_id].url_row = std::move(url_row); // Restore visits list. VisitInfoVector visits; - visits.reserve(iter->visits_size()); - for (int i = 0; i < iter->visits_size(); ++i) { - visits.push_back(std::make_pair( - base::Time::FromInternalValue(iter->visits(i).visit_time()), - ui::PageTransitionFromInt(iter->visits(i).transition_type()))); + visits.reserve(entry.visits_size()); + for (const auto& entry_visit : entry.visits()) { + visits.emplace_back( + base::Time::FromInternalValue(entry_visit.visit_time()), + ui::PageTransitionFromInt(entry_visit.transition_type())); } - history_info_map_[history_id].visits = visits; + history_info_map_[history_id].visits = std::move(visits); } return true; } @@ -1263,38 +1179,33 @@ uint32_t actual_item_count = list_item.word_starts_map_entry_size(); if (actual_item_count == 0 || actual_item_count != expected_item_count) return false; - const RepeatedPtrField<WordStartsMapEntry>& - entries(list_item.word_starts_map_entry()); - for (RepeatedPtrField<WordStartsMapEntry>::const_iterator iter = - entries.begin(); iter != entries.end(); ++iter) { - HistoryID history_id = iter->history_id(); + for (const auto& entry : list_item.word_starts_map_entry()) { + HistoryID history_id = entry.history_id(); RowWordStarts word_starts; // Restore the URL word starts. - const RepeatedField<int32_t>& url_starts(iter->url_word_starts()); - for (RepeatedField<int32_t>::const_iterator jiter = url_starts.begin(); - jiter != url_starts.end(); ++jiter) - word_starts.url_word_starts_.push_back(*jiter); + const RepeatedField<int32_t>& url_starts = entry.url_word_starts(); + word_starts.url_word_starts_ = {url_starts.begin(), url_starts.end()}; + // Restore the page title word starts. - const RepeatedField<int32_t>& title_starts(iter->title_word_starts()); - for (RepeatedField<int32_t>::const_iterator jiter = title_starts.begin(); - jiter != title_starts.end(); ++jiter) - word_starts.title_word_starts_.push_back(*jiter); - word_starts_map_[history_id] = word_starts; + const RepeatedField<int32_t>& title_starts = entry.title_word_starts(); + word_starts.title_word_starts_ = {title_starts.begin(), + title_starts.end()}; + + word_starts_map_[history_id] = std::move(word_starts); } } else { // Since the cache did not contain any word starts we must rebuild then from // the URL and page titles. - for (HistoryInfoMap::const_iterator iter = history_info_map_.begin(); - iter != history_info_map_.end(); ++iter) { + for (const auto& entry : history_info_map_) { RowWordStarts word_starts; - const history::URLRow& row(iter->second.url_row); + const history::URLRow& row = entry.second.url_row; const base::string16& url = bookmarks::CleanUpUrlForMatching(row.url(), nullptr); String16VectorFromString16(url, false, &word_starts.url_word_starts_); const base::string16& title = bookmarks::CleanUpTitleForMatching(row.title()); String16VectorFromString16(title, false, &word_starts.title_word_starts_); - word_starts_map_[iter->first] = word_starts; + word_starts_map_[entry.first] = std::move(word_starts); } } return true;
diff --git a/components/omnibox/browser/url_index_private_data.h b/components/omnibox/browser/url_index_private_data.h index 4eb77e5..9054ba7 100644 --- a/components/omnibox/browser/url_index_private_data.h +++ b/components/omnibox/browser/url_index_private_data.h
@@ -8,6 +8,7 @@ #include <stddef.h> #include <set> +#include <stack> #include <string> #include "base/files/file_path.h" @@ -205,9 +206,9 @@ // URL History indexing support functions. - // Composes a set of history item IDs by intersecting the set for each word + // Composes a vector of history item IDs by intersecting the set for each word // in |unsorted_words|. - HistoryIDSet HistoryIDSetFromWords(const String16Vector& unsorted_words); + HistoryIDVector HistoryIDsFromWords(const String16Vector& unsorted_words); // Trims the candidate pool in advance of doing proper substring searching, to // cap the cost of such searching. Discards the least-relevant items (based on @@ -215,7 +216,7 @@ // minimize the risk of discarding a valuable URL, the candidate pool is still // left two orders of magnitude larger than the final number of results // returned from the HQP. Returns whether anything was trimmed. - bool TrimHistoryIdsPool(HistoryIDSet* history_id_set) const; + bool TrimHistoryIdsPool(HistoryIDVector* history_ids) const; // Helper function to HistoryIDSetFromWords which composes a set of history // ids for the given term given in |term|. @@ -225,13 +226,12 @@ WordIDSet WordIDSetForTermChars(const Char16Set& term_chars); // Helper function for HistoryItemsForTerms(). Fills in |scored_items| from - // the matches listed in |history_id_set|. - void HistoryIdSetToScoredMatches( - HistoryIDSet history_id_set, - const base::string16& lower_raw_string, - const TemplateURLService* template_url_service, - bookmarks::BookmarkModel* bookmark_model, - ScoredHistoryMatches* scored_items) const; + // the matches listed in |history_ids|. + void HistoryIdsToScoredMatches(HistoryIDVector history_ids, + const base::string16& lower_raw_string, + const TemplateURLService* template_url_service, + bookmarks::BookmarkModel* bookmark_model, + ScoredHistoryMatches* scored_items) const; // Fills in |terms_to_word_starts_offsets| according to where the word starts // in each term. For example, in the term "-foo" the word starts at offset 1. @@ -262,17 +262,9 @@ // history item identified by |history_id| to the index. void AddWordToIndex(const base::string16& uni_word, HistoryID history_id); - // Creates a new entry in the word/history map for |word_id| and add - // |history_id| as the initial element of the word's set. - void AddWordHistory(const base::string16& uni_word, HistoryID history_id); - - // Updates an existing entry in the word/history index by adding the - // |history_id| to set for |word_id| in the word_id_history_map_. - void UpdateWordHistory(WordID word_id, HistoryID history_id); - - // Adds |word_id| to |history_id|'s entry in the history/word map, - // creating a new entry if one does not already exist. - void AddToHistoryIDWordMap(HistoryID history_id, WordID word_id); + // Adds a new entry to |word_list_|. Uses previously freed positions if + // available. + WordID AddNewWordToWordList(const base::string16& term); // Removes |row| and all associated words and characters from the index. void RemoveRowFromIndex(const history::URLRow& row); @@ -353,9 +345,9 @@ // the index, in which case any available words are used, if any, and then // words are added to the end of the word_list_. When URL visits are // modified or deleted old words may be removed from the index, in which - // case the slots for those words are added to available_words_ for resuse + // case the slots for those words are added to available_words_ for reuse // by future URL updates. - WordIDSet available_words_; + std::stack<WordID> available_words_; // A one-to-one mapping from the a word string to its slot number (i.e. // WordID) in the |word_list_|.
diff --git a/components/payments/payment_request.h b/components/payments/payment_request.h index 0207c6b1..551d8ffe 100644 --- a/components/payments/payment_request.h +++ b/components/payments/payment_request.h
@@ -100,6 +100,10 @@ // card. autofill::CreditCard* selected_credit_card() { return selected_credit_card_; } + void set_selected_credit_card(autofill::CreditCard* credit_card) { + selected_credit_card_ = credit_card; + } + autofill::PersonalDataManager* personal_data_manager() { return delegate_->GetPersonalDataManager(); }
diff --git a/components/tracing/BUILD.gn b/components/tracing/BUILD.gn index deab4a6..6608413 100644 --- a/components/tracing/BUILD.gn +++ b/components/tracing/BUILD.gn
@@ -7,8 +7,6 @@ component("tracing") { sources = [ - "child/child_memory_dump_manager_delegate_impl.cc", - "child/child_memory_dump_manager_delegate_impl.h", "child/child_trace_message_filter.cc", "child/child_trace_message_filter.h", "common/graphics_memory_dump_provider_android.cc",
diff --git a/components/tracing/child/child_memory_dump_manager_delegate_impl.cc b/components/tracing/child/child_memory_dump_manager_delegate_impl.cc deleted file mode 100644 index f0c4517b..0000000 --- a/components/tracing/child/child_memory_dump_manager_delegate_impl.cc +++ /dev/null
@@ -1,114 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/tracing/child/child_memory_dump_manager_delegate_impl.h" - -#include "base/single_thread_task_runner.h" -#include "build/build_config.h" -#include "components/tracing/child/child_trace_message_filter.h" -#include "components/tracing/common/process_metrics_memory_dump_provider.h" - -namespace tracing { - -namespace { -void AbortDumpRequest(const base::trace_event::MemoryDumpRequestArgs& args, - const base::trace_event::MemoryDumpCallback& callback) { - if (!callback.is_null()) - callback.Run(args.dump_guid, false /* success */); -} -} // namespace - -// static -ChildMemoryDumpManagerDelegateImpl* -ChildMemoryDumpManagerDelegateImpl::GetInstance() { - return base::Singleton< - ChildMemoryDumpManagerDelegateImpl, - base::LeakySingletonTraits<ChildMemoryDumpManagerDelegateImpl>>::get(); -} - -ChildMemoryDumpManagerDelegateImpl::ChildMemoryDumpManagerDelegateImpl() - : ctmf_(nullptr), - tracing_process_id_( - base::trace_event::MemoryDumpManager::kInvalidTracingProcessId) { -} - -ChildMemoryDumpManagerDelegateImpl::~ChildMemoryDumpManagerDelegateImpl() {} - -void ChildMemoryDumpManagerDelegateImpl::SetChildTraceMessageFilter( - ChildTraceMessageFilter* ctmf) { - auto* task_runner = ctmf ? (ctmf->ipc_task_runner()) : nullptr; - // Check that we are either registering the CTMF or tearing it down, but not - // replacing a valid instance with another one (should never happen). - DCHECK(!ctmf_ || (!ctmf && ctmf_task_runner_)); - ctmf_ = ctmf; - - { - base::AutoLock lock(lock_); - ctmf_task_runner_ = task_runner; - } - - if (ctmf) { - base::trace_event::MemoryDumpManager::GetInstance()->Initialize( - this /* delegate */, false /* is_coordinator */); - -#if !defined(OS_LINUX) && !defined(OS_NACL) - // On linux the browser process takes care of dumping process metrics. - // The child process is not allowed to do so due to BPF sandbox. - tracing::ProcessMetricsMemoryDumpProvider::RegisterForProcess( - base::kNullProcessId); -#endif - } -} - -// Invoked in child processes by the MemoryDumpManager. -void ChildMemoryDumpManagerDelegateImpl::RequestGlobalMemoryDump( - const base::trace_event::MemoryDumpRequestArgs& args, - const base::trace_event::MemoryDumpCallback& callback) { - // RequestGlobalMemoryDump can be called on any thread, cannot access - // ctmf_task_runner_ as it could be racy. - scoped_refptr<base::SingleThreadTaskRunner> ctmf_task_runner; - { - base::AutoLock lock(lock_); - ctmf_task_runner = ctmf_task_runner_; - } - - // Bail out if we receive a dump request from the manager before the - // ChildTraceMessageFilter has been initialized. - if (!ctmf_task_runner) { - VLOG(1) << base::trace_event::MemoryDumpManager::kLogPrefix - << " failed because child trace message filter hasn't been" - << " initialized"; - return AbortDumpRequest(args, callback); - } - - // Make sure we access |ctmf_| only on the thread where it lives to avoid - // races on shutdown. - if (!ctmf_task_runner->BelongsToCurrentThread()) { - const bool did_post_task = ctmf_task_runner->PostTask( - FROM_HERE, - base::Bind(&ChildMemoryDumpManagerDelegateImpl::RequestGlobalMemoryDump, - base::Unretained(this), args, callback)); - if (!did_post_task) - return AbortDumpRequest(args, callback); - return; - } - - // The ChildTraceMessageFilter could have been destroyed while hopping on the - // right thread. If this is the case, bail out. - if (!ctmf_) { - VLOG(1) << base::trace_event::MemoryDumpManager::kLogPrefix - << " failed because child trace message filter was" - << " destroyed while switching threads"; - return AbortDumpRequest(args, callback); - } - - // Send the request up to the browser process' MessageDumpmanager. - ctmf_->SendGlobalMemoryDumpRequest(args, callback); -} - -uint64_t ChildMemoryDumpManagerDelegateImpl::GetTracingProcessId() const { - return tracing_process_id_; -} - -} // namespace tracing
diff --git a/components/tracing/child/child_memory_dump_manager_delegate_impl.h b/components/tracing/child/child_memory_dump_manager_delegate_impl.h deleted file mode 100644 index fc27d96..0000000 --- a/components/tracing/child/child_memory_dump_manager_delegate_impl.h +++ /dev/null
@@ -1,85 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_TRACING_CHILD_CHILD_MEMORY_DUMP_MANAGER_DELEGATE_IMPL_H_ -#define COMPONENTS_TRACING_CHILD_CHILD_MEMORY_DUMP_MANAGER_DELEGATE_IMPL_H_ - -#include "base/trace_event/memory_dump_manager.h" - -#include <stdint.h> - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/singleton.h" -#include "base/synchronization/lock.h" -#include "components/tracing/tracing_export.h" - -namespace base { -class SingleThreadTaskRunner; -} // namespace base - -namespace tracing { - -class ChildTraceMessageFilter; - -// This class is a simple proxy class between the MemoryDumpManager and the -// ChildTraceMessageFilter. It's only purpose is to adapt the lifetime of -// CTMF to the demands of MDM, which expects the delegate to be thread-safe -// and long lived. CTMF, instead, can be torn down during browser shutdown. -// This class is registered as MDM delegate in child processes and handles -// gracefully (and thread-safely) failures in the case of a lack of the CTMF. -class TRACING_EXPORT ChildMemoryDumpManagerDelegateImpl - : public base::trace_event::MemoryDumpManagerDelegate { - public: - static ChildMemoryDumpManagerDelegateImpl* GetInstance(); - - // base::trace_event::MemoryDumpManagerDelegate implementation. - void RequestGlobalMemoryDump( - const base::trace_event::MemoryDumpRequestArgs& args, - const base::trace_event::MemoryDumpCallback& callback) override; - uint64_t GetTracingProcessId() const override; - - void SetChildTraceMessageFilter(ChildTraceMessageFilter* ctmf); - - // Pass kInvalidTracingProcessId to invalidate the id. - void set_tracing_process_id(uint64_t id) { - DCHECK(tracing_process_id_ == - base::trace_event::MemoryDumpManager::kInvalidTracingProcessId || - id == - base::trace_event::MemoryDumpManager::kInvalidTracingProcessId || - id == tracing_process_id_); - tracing_process_id_ = id; - } - - protected: - // Make CreateProcessDump() visible to ChildTraceMessageFilter. - friend class ChildTraceMessageFilter; - - private: - friend struct base::DefaultSingletonTraits< - ChildMemoryDumpManagerDelegateImpl>; - - ChildMemoryDumpManagerDelegateImpl(); - ~ChildMemoryDumpManagerDelegateImpl() override; - - ChildTraceMessageFilter* ctmf_; // Not owned. - - // The SingleThreadTaskRunner where the |ctmf_| lives. - // It is NULL iff |cmtf_| is NULL. - scoped_refptr<base::SingleThreadTaskRunner> ctmf_task_runner_; - - // Protects from concurrent access to |ctmf_task_runner_| to allow - // RequestGlobalMemoryDump to be called from arbitrary threads. - base::Lock lock_; - - // The unique id of the child process, created for tracing and is expected to - // be valid only when tracing is enabled. - uint64_t tracing_process_id_; - - DISALLOW_COPY_AND_ASSIGN(ChildMemoryDumpManagerDelegateImpl); -}; - -} // namespace tracing - -#endif // COMPONENTS_TRACING_CHILD_CHILD_MEMORY_DUMP_MANAGER_DELEGATE_IMPL_H_
diff --git a/components/tracing/child/child_trace_message_filter.cc b/components/tracing/child/child_trace_message_filter.cc index ed2be875..6012a96a 100644 --- a/components/tracing/child/child_trace_message_filter.cc +++ b/components/tracing/child/child_trace_message_filter.cc
@@ -8,11 +8,13 @@ #include "base/memory/ref_counted_memory.h" #include "base/metrics/statistics_recorder.h" +#include "base/trace_event/memory_dump_manager.h" #include "base/trace_event/trace_event.h" -#include "components/tracing/child/child_memory_dump_manager_delegate_impl.h" +#include "components/tracing/common/process_metrics_memory_dump_provider.h" #include "components/tracing/common/tracing_messages.h" #include "ipc/ipc_channel.h" +using base::trace_event::MemoryDumpManager; using base::trace_event::TraceLog; namespace tracing { @@ -25,16 +27,18 @@ ChildTraceMessageFilter::ChildTraceMessageFilter( base::SingleThreadTaskRunner* ipc_task_runner) - : sender_(NULL), - ipc_task_runner_(ipc_task_runner), - pending_memory_dump_guid_(0) { -} + : sender_(NULL), ipc_task_runner_(ipc_task_runner) {} void ChildTraceMessageFilter::OnFilterAdded(IPC::Channel* channel) { sender_ = channel; sender_->Send(new TracingHostMsg_ChildSupportsTracing()); - ChildMemoryDumpManagerDelegateImpl::GetInstance()->SetChildTraceMessageFilter( - this); + +#if !defined(OS_LINUX) && !defined(OS_NACL) + // On linux the browser process takes care of dumping process metrics. + // The child process is not allowed to do so due to BPF sandbox. + tracing::ProcessMetricsMemoryDumpProvider::RegisterForProcess( + base::kNullProcessId); +#endif } void ChildTraceMessageFilter::SetSenderForTesting(IPC::Sender* sender) { @@ -42,8 +46,6 @@ } void ChildTraceMessageFilter::OnFilterRemoved() { - ChildMemoryDumpManagerDelegateImpl::GetInstance()->SetChildTraceMessageFilter( - nullptr); sender_ = NULL; } @@ -54,10 +56,6 @@ IPC_MESSAGE_HANDLER(TracingMsg_EndTracing, OnEndTracing) IPC_MESSAGE_HANDLER(TracingMsg_CancelTracing, OnCancelTracing) IPC_MESSAGE_HANDLER(TracingMsg_GetTraceLogStatus, OnGetTraceLogStatus) - IPC_MESSAGE_HANDLER(TracingMsg_ProcessMemoryDumpRequest, - OnProcessMemoryDumpRequest) - IPC_MESSAGE_HANDLER(TracingMsg_GlobalMemoryDumpResponse, - OnGlobalMemoryDumpResponse) IPC_MESSAGE_HANDLER(TracingMsg_SetUMACallback, OnSetUMACallback) IPC_MESSAGE_HANDLER(TracingMsg_ClearUMACallback, OnClearUMACallback) IPC_MESSAGE_UNHANDLED(handled = false) @@ -78,8 +76,7 @@ base::TimeDelta time_offset = base::TimeTicks::Now() - browser_time; TraceLog::GetInstance()->SetTimeOffset(time_offset); #endif - ChildMemoryDumpManagerDelegateImpl::GetInstance()->set_tracing_process_id( - tracing_process_id); + MemoryDumpManager::GetInstance()->set_tracing_process_id(tracing_process_id); TraceLog::GetInstance()->SetEnabled( base::trace_event::TraceConfig(trace_config_str), base::trace_event::TraceLog::RECORDING_MODE); @@ -95,8 +92,8 @@ TraceLog::GetInstance()->Flush( base::Bind(&ChildTraceMessageFilter::OnTraceDataCollected, this)); - ChildMemoryDumpManagerDelegateImpl::GetInstance()->set_tracing_process_id( - base::trace_event::MemoryDumpManager::kInvalidTracingProcessId); + MemoryDumpManager::GetInstance()->set_tracing_process_id( + MemoryDumpManager::kInvalidTracingProcessId); } void ChildTraceMessageFilter::OnCancelTracing() { @@ -129,52 +126,6 @@ } } -// Sent by the Browser's MemoryDumpManager when coordinating a global dump. -void ChildTraceMessageFilter::OnProcessMemoryDumpRequest( - const base::trace_event::MemoryDumpRequestArgs& args) { - ChildMemoryDumpManagerDelegateImpl::GetInstance()->CreateProcessDump( - args, - base::Bind(&ChildTraceMessageFilter::OnProcessMemoryDumpDone, this)); -} - -void ChildTraceMessageFilter::OnProcessMemoryDumpDone(uint64_t dump_guid, - bool success) { - sender_->Send( - new TracingHostMsg_ProcessMemoryDumpResponse(dump_guid, success)); -} - -// Initiates a dump request, asking the Browser's MemoryDumpManager to -// coordinate a global memory dump. The Browser's MDM will answer back with a -// MemoryDumpResponse when all the child processes (including this one) have -// dumped, or with a NACK (|success| == false) if the dump failed (e.g., due to -// a collision with a concurrent request from another child process). -void ChildTraceMessageFilter::SendGlobalMemoryDumpRequest( - const base::trace_event::MemoryDumpRequestArgs& args, - const base::trace_event::MemoryDumpCallback& callback) { - // If there is already another dump request pending from this child process, - // there is no point bothering the Browser's MemoryDumpManager. - if (pending_memory_dump_guid_) { - if (!callback.is_null()) - callback.Run(args.dump_guid, false); - return; - } - - pending_memory_dump_guid_ = args.dump_guid; - pending_memory_dump_callback_ = callback; - sender_->Send(new TracingHostMsg_GlobalMemoryDumpRequest(args)); -} - -// Sent by the Browser's MemoryDumpManager in response of a dump request -// initiated by this child process. -void ChildTraceMessageFilter::OnGlobalMemoryDumpResponse(uint64_t dump_guid, - bool success) { - DCHECK_NE(0U, pending_memory_dump_guid_); - pending_memory_dump_guid_ = 0; - if (pending_memory_dump_callback_.is_null()) - return; - pending_memory_dump_callback_.Run(dump_guid, success); -} - void ChildTraceMessageFilter::OnHistogramChanged( const std::string& histogram_name, base::Histogram::Sample reference_lower_value,
diff --git a/components/tracing/child/child_trace_message_filter.h b/components/tracing/child/child_trace_message_filter.h index 287abd35..619de78 100644 --- a/components/tracing/child/child_trace_message_filter.h +++ b/components/tracing/child/child_trace_message_filter.h
@@ -12,7 +12,6 @@ #include "base/memory/ref_counted_memory.h" #include "base/metrics/histogram.h" #include "base/time/time.h" -#include "base/trace_event/memory_dump_request_args.h" #include "components/tracing/tracing_export.h" #include "ipc/message_filter.h" @@ -33,10 +32,6 @@ void OnFilterRemoved() override; bool OnMessageReceived(const IPC::Message& message) override; - void SendGlobalMemoryDumpRequest( - const base::trace_event::MemoryDumpRequestArgs& args, - const base::trace_event::MemoryDumpCallback& callback); - base::SingleThreadTaskRunner* ipc_task_runner() const { return ipc_task_runner_; } @@ -58,9 +53,6 @@ const std::string& event_name); void OnCancelWatchEvent(); void OnWatchEventMatched(); - void OnProcessMemoryDumpRequest( - const base::trace_event::MemoryDumpRequestArgs& args); - void OnGlobalMemoryDumpResponse(uint64_t dump_guid, bool success); void OnSetUMACallback(const std::string& histogram_name, int histogram_lower_value, int histogram_upper_value, @@ -79,20 +71,11 @@ const scoped_refptr<base::RefCountedString>& events_str_ptr, bool has_more_events); - void OnProcessMemoryDumpDone(uint64_t dump_guid, bool success); - void SetSenderForTesting(IPC::Sender* sender); IPC::Sender* sender_; base::SingleThreadTaskRunner* ipc_task_runner_; - // guid of the outstanding request (to the Browser's MemoryDumpManager), if - // any. 0 if there is no request pending. - uint64_t pending_memory_dump_guid_; - - // callback of the outstanding memory dump request, if any. - base::trace_event::MemoryDumpCallback pending_memory_dump_callback_; - base::Time histogram_last_changed_; DISALLOW_COPY_AND_ASSIGN(ChildTraceMessageFilter);
diff --git a/components/tracing/child/child_trace_message_filter_browsertest.cc b/components/tracing/child/child_trace_message_filter_browsertest.cc deleted file mode 100644 index d0d2d020..0000000 --- a/components/tracing/child/child_trace_message_filter_browsertest.cc +++ /dev/null
@@ -1,326 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <stdint.h> - -#include <memory> -#include <tuple> - -#include "base/callback.h" -#include "base/run_loop.h" -#include "base/threading/thread_task_runner_handle.h" -#include "base/trace_event/memory_dump_manager.h" -#include "base/trace_event/memory_dump_provider.h" -#include "base/trace_event/trace_event.h" -#include "components/tracing/child/child_memory_dump_manager_delegate_impl.h" -#include "components/tracing/child/child_trace_message_filter.h" -#include "components/tracing/common/tracing_messages.h" -#include "content/public/test/render_view_test.h" -#include "testing/gmock/include/gmock/gmock.h" - -using base::trace_event::MemoryDumpManager; -using base::trace_event::MemoryDumpRequestArgs; -using base::trace_event::MemoryDumpArgs; -using base::trace_event::MemoryDumpLevelOfDetail; -using base::trace_event::MemoryDumpType; -using testing::_; -using testing::Return; - -namespace tracing { - -// A mock dump provider, used to check that dump requests actually end up -// creating memory dumps. -class MockDumpProvider : public base::trace_event::MemoryDumpProvider { - public: - MOCK_METHOD2(OnMemoryDump, - bool(const MemoryDumpArgs& args, - base::trace_event::ProcessMemoryDump* pmd)); -}; - -class ChildTracingTest : public content::RenderViewTest, public IPC::Listener { - public: - // Used as callback argument for MemoryDumpManager::RequestGlobalDump(): - void OnMemoryDumpCallback(uint64_t dump_guid, bool status) { - last_callback_dump_guid_ = dump_guid; - last_callback_status_ = status; - ++callback_call_count_; - } - - protected: - void SetUp() override { - // RenderViewTest::SetUp causes additional registrations, so we first - // register the mock dump provider and ignore registrations from then on. - // In addition to the mock dump provider, the TraceLog has already - // registered itself by now; this cannot be prevented easily. - mock_dump_provider_.reset(new MockDumpProvider()); - MemoryDumpManager::GetInstance()->RegisterDumpProvider( - mock_dump_provider_.get(), "MockDumpProvider", - base::ThreadTaskRunnerHandle::Get()); - MemoryDumpManager::GetInstance() - ->set_dumper_registrations_ignored_for_testing(true); - - RenderViewTest::SetUp(); - - callback_call_count_ = 0; - last_callback_dump_guid_ = 0; - last_callback_status_ = false; - wait_for_ipc_message_type_ = 0; - callback_ = base::Bind(&ChildTracingTest::OnMemoryDumpCallback, - base::Unretained(this)); - task_runner_ = base::ThreadTaskRunnerHandle::Get(); - ctmf_ = make_scoped_refptr(new ChildTraceMessageFilter(task_runner_.get())); - render_thread_->AddFilter(ctmf_.get()); - - // Add a filter to the TestSink which allows to WaitForIPCMessage() by - // posting a nested RunLoop closure when a given IPC Message is seen. - render_thread_->sink().AddFilter(this); - - // Getting an instance of |ChildMemoryDumpManagerDelegateImpl| calls - // |MemoryDumpManager::Initialize| with the correct delegate. - ChildMemoryDumpManagerDelegateImpl::GetInstance(); - } - - void TearDown() override { - render_thread_->sink().RemoveFilter(this); - RenderViewTest::TearDown(); - MemoryDumpManager::GetInstance()->UnregisterDumpProvider( - mock_dump_provider_.get()); - mock_dump_provider_.reset(); - ctmf_ = nullptr; - task_runner_ = nullptr; - } - - // IPC::Filter implementation. - bool OnMessageReceived(const IPC::Message& message) override { - if (message.type() == wait_for_ipc_message_type_) { - DCHECK(!wait_for_ipc_closure_.is_null()); - task_runner_->PostTask(FROM_HERE, wait_for_ipc_closure_); - } - // Always propagate messages to the sink, never consume them here. - return false; - } - - const IPC::Message* WaitForIPCMessage(uint32_t message_type) { - base::RunLoop run_loop; - wait_for_ipc_message_type_ = message_type; - wait_for_ipc_closure_ = run_loop.QuitClosure(); - run_loop.Run(); - wait_for_ipc_message_type_ = 0; - wait_for_ipc_closure_.Reset(); - return render_thread_->sink().GetUniqueMessageMatching(message_type); - } - - // Simulates a synthetic browser -> child (this process) IPC message. - void SimulateSyntheticMessageFromBrowser(const IPC::Message& msg) { - ctmf_->OnMessageReceived(msg); - } - - void EnableTracingWithMemoryDumps() { - // Re-enabling tracing could crash these tests https://crbug.com/656729 . - if (base::trace_event::TraceLog::GetInstance()->IsEnabled()) { - FAIL() << "Tracing seems to be already enabled. " - "Very likely this is because the startup tracing file " - "has been leaked from a previous test."; - } - - std::string category_filter = "-*,"; // Disable all other trace categories. - category_filter += MemoryDumpManager::kTraceCategory; - base::trace_event::TraceConfig trace_config(category_filter, ""); - TracingMsg_BeginTracing msg(trace_config.ToString(), base::TimeTicks(), 0); - SimulateSyntheticMessageFromBrowser(msg); - } - - void DisableTracing() { - SimulateSyntheticMessageFromBrowser(TracingMsg_EndTracing()); - } - - // Simulates a synthetic browser -> child process memory dump request and - // checks that the child actually sends a response to that. - void RequestProcessMemoryDumpAndCheckResponse(uint64_t dump_guid) { - SimulateSyntheticMessageFromBrowser(TracingMsg_ProcessMemoryDumpRequest( - {dump_guid, MemoryDumpType::EXPLICITLY_TRIGGERED, - MemoryDumpLevelOfDetail::DETAILED})); - - // Check that a child -> browser response to the local dump request is sent. - const IPC::Message* msg = - WaitForIPCMessage(TracingHostMsg_ProcessMemoryDumpResponse::ID); - EXPECT_NE(nullptr, msg); - - // Check that the |dump_guid| and the |success| fields are properly set. - TracingHostMsg_ProcessMemoryDumpResponse::Param params; - TracingHostMsg_ProcessMemoryDumpResponse::Read(msg, ¶ms); - const uint64_t resp_guid = std::get<0>(params); - const bool resp_success = std::get<1>(params); - EXPECT_EQ(dump_guid, resp_guid); - EXPECT_TRUE(resp_success); - } - - // Retrieves the MemoryDumpRequestArgs of the global memory dump request that - // this child process tried to send to the browser. Fails if either none or - // multiple requests were sent. - MemoryDumpRequestArgs GetInterceptedGlobalMemoryDumpRequest() { - const IPC::Message* msg = render_thread_->sink().GetUniqueMessageMatching( - TracingHostMsg_GlobalMemoryDumpRequest::ID); - EXPECT_NE(nullptr, msg); - TracingHostMsg_GlobalMemoryDumpRequest::Param params; - TracingHostMsg_GlobalMemoryDumpRequest::Read(msg, ¶ms); - MemoryDumpRequestArgs args = std::get<0>(params); - EXPECT_NE(0U, args.dump_guid); - return args; - } - - scoped_refptr<ChildTraceMessageFilter> ctmf_; - std::unique_ptr<MockDumpProvider> mock_dump_provider_; - scoped_refptr<base::SingleThreadTaskRunner> task_runner_; - base::trace_event::MemoryDumpCallback callback_; - uint32_t wait_for_ipc_message_type_; - base::Closure wait_for_ipc_closure_; - uint32_t callback_call_count_; - uint64_t last_callback_dump_guid_; - bool last_callback_status_; -}; - -// Covers the case of some browser-initiated memory dumps. -#if defined(OS_ANDROID) -// Flaky on Android. http://crbug.com/620734. -#define MAYBE_BrowserInitiatedMemoryDumps DISABLED_BrowserInitiatedMemoryDumps -#else -#define MAYBE_BrowserInitiatedMemoryDumps BrowserInitiatedMemoryDumps -#endif -TEST_F(ChildTracingTest, MAYBE_BrowserInitiatedMemoryDumps) { - const uint32_t kNumDumps = 3; - - EnableTracingWithMemoryDumps(); - EXPECT_CALL(*mock_dump_provider_, OnMemoryDump(_, _)) - .Times(kNumDumps) - .WillRepeatedly(Return(true)); - - for (uint32_t i = 0; i < kNumDumps; ++i) { - render_thread_->sink().ClearMessages(); - RequestProcessMemoryDumpAndCheckResponse(i + 1); - } - - DisableTracing(); -} - -// Covers the case of one simple child-initiated memory dump without callback, -// simulating a global memory dump request to the browser (+ response). -TEST_F(ChildTracingTest, SingleChildInitiatedMemoryDump) { - EnableTracingWithMemoryDumps(); - - // Expect that our mock dump provider is called when the emulated memory dump - // request (browser -> child) is sent. - EXPECT_CALL(*mock_dump_provider_, OnMemoryDump(_, _)) - .Times(1) - .WillRepeatedly(Return(true)); - - // Send the global memory dump request to the browser. - render_thread_->sink().ClearMessages(); - MemoryDumpManager::GetInstance()->RequestGlobalDump( - MemoryDumpType::EXPLICITLY_TRIGGERED, MemoryDumpLevelOfDetail::DETAILED); - base::RunLoop().RunUntilIdle(); - - // Check that the child -> browser global dump request IPC is actually sent. - MemoryDumpRequestArgs args = GetInterceptedGlobalMemoryDumpRequest(); - EXPECT_EQ(MemoryDumpType::EXPLICITLY_TRIGGERED, args.dump_type); - - // Emulate a browser -> child process dump request and corresponding response. - RequestProcessMemoryDumpAndCheckResponse(args.dump_guid); - - // Send a synthetic browser -> child global memory dump response. - SimulateSyntheticMessageFromBrowser( - TracingMsg_GlobalMemoryDumpResponse(args.dump_guid, true)); - - DisableTracing(); -} - -// Covers the case of a global memory dump being requested while another one is -// in progress and has not been acknowledged by the browser. The second request -// is expected to fail immediately, while the first one is expected to suceed. -TEST_F(ChildTracingTest, OverlappingChildInitiatedMemoryDumps) { - EnableTracingWithMemoryDumps(); - - // Expect that our mock dump provider is called only once. - EXPECT_CALL(*mock_dump_provider_, OnMemoryDump(_, _)) - .Times(1) - .WillRepeatedly(Return(true)); - - // Send the global memory dump request to the browser. - render_thread_->sink().ClearMessages(); - MemoryDumpManager::GetInstance()->RequestGlobalDump( - MemoryDumpType::EXPLICITLY_TRIGGERED, MemoryDumpLevelOfDetail::DETAILED, - callback_); - base::RunLoop().RunUntilIdle(); - - // Check that the child -> browser global dump request IPC is actually sent. - MemoryDumpRequestArgs args = GetInterceptedGlobalMemoryDumpRequest(); - EXPECT_EQ(MemoryDumpType::EXPLICITLY_TRIGGERED, args.dump_type); - - // Emulate a browser -> child process dump request and corresponding response. - RequestProcessMemoryDumpAndCheckResponse(args.dump_guid); - - // Before the response for the first global dump is sent, send another one, - // and expect that to fail. - render_thread_->sink().ClearMessages(); - MemoryDumpManager::GetInstance()->RequestGlobalDump( - MemoryDumpType::EXPLICITLY_TRIGGERED, MemoryDumpLevelOfDetail::DETAILED, - callback_); - base::RunLoop().RunUntilIdle(); - - EXPECT_EQ(1u, callback_call_count_); - EXPECT_FALSE(last_callback_status_); - // Whatever the guid of the second failing request is, it cannot possibly be - // equal to the guid of the first request. - EXPECT_NE(args.dump_guid, last_callback_dump_guid_); - - // Also, check that no request has been forwarded to the browser (because the - // first request is still outstanding and has not received any response yet). - EXPECT_EQ(nullptr, render_thread_->sink().GetUniqueMessageMatching( - TracingHostMsg_GlobalMemoryDumpRequest::ID)); - - // Now send a synthetic browser -> child response to the first request. - SimulateSyntheticMessageFromBrowser( - TracingMsg_GlobalMemoryDumpResponse(args.dump_guid, true)); - - // Verify that the the callback for the first request is finally called. - EXPECT_EQ(2u, callback_call_count_); - EXPECT_EQ(args.dump_guid, last_callback_dump_guid_); - EXPECT_TRUE(last_callback_status_); - - DisableTracing(); -} - -// Covers the case of five child-initiated global memory dumps. Each global dump -// request has a callback, which is expected to fail for 3 out of 5 cases. -TEST_F(ChildTracingTest, MultipleChildInitiatedMemoryDumpWithFailures) { - const uint32_t kNumRequests = 5; - MemoryDumpType kDumpType = MemoryDumpType::EXPLICITLY_TRIGGERED; - - EnableTracingWithMemoryDumps(); - EXPECT_CALL(*mock_dump_provider_, OnMemoryDump(_, _)) - .Times(kNumRequests) - .WillRepeatedly(Return(true)); - - for (uint32_t i = 0; i < kNumRequests; ++i) { - render_thread_->sink().ClearMessages(); - MemoryDumpManager::GetInstance()->RequestGlobalDump( - kDumpType, MemoryDumpLevelOfDetail::DETAILED, callback_); - base::RunLoop().RunUntilIdle(); - - MemoryDumpRequestArgs args = GetInterceptedGlobalMemoryDumpRequest(); - EXPECT_EQ(kDumpType, args.dump_type); - RequestProcessMemoryDumpAndCheckResponse(args.dump_guid); - - const bool success = (i & 1) ? true : false; - SimulateSyntheticMessageFromBrowser( - TracingMsg_GlobalMemoryDumpResponse(args.dump_guid, success)); - EXPECT_EQ(i + 1, callback_call_count_); - EXPECT_EQ(args.dump_guid, last_callback_dump_guid_); - EXPECT_EQ(success, last_callback_status_); - } - - DisableTracing(); -} - -} // namespace tracing
diff --git a/components/translate/ios/browser/language_detection_controller.h b/components/translate/ios/browser/language_detection_controller.h index 72a3d5bc..c3271e82 100644 --- a/components/translate/ios/browser/language_detection_controller.h +++ b/components/translate/ios/browser/language_detection_controller.h
@@ -25,6 +25,7 @@ } namespace web { +class NavigationContext; class WebState; } @@ -78,8 +79,7 @@ // web::WebStateObserver implementation: void PageLoaded( web::PageLoadCompletionStatus load_completion_status) override; - void UrlHashChanged() override; - void HistoryStateChanged() override; + void DidFinishNavigation(web::NavigationContext* navigation_context) override; void WebStateDestroyed() override; CallbackList language_detection_callbacks_;
diff --git a/components/translate/ios/browser/language_detection_controller.mm b/components/translate/ios/browser/language_detection_controller.mm index 4292261..53fda593 100644 --- a/components/translate/ios/browser/language_detection_controller.mm +++ b/components/translate/ios/browser/language_detection_controller.mm
@@ -16,6 +16,7 @@ #import "components/translate/ios/browser/js_language_detection_manager.h" #include "components/translate/ios/browser/string_clipping_util.h" #import "ios/web/public/url_scheme_util.h" +#include "ios/web/public/web_state/navigation_context.h" #include "ios/web/public/web_state/web_state.h" #if !defined(__has_feature) || !__has_feature(objc_arc) @@ -137,12 +138,10 @@ StartLanguageDetection(); } -void LanguageDetectionController::UrlHashChanged() { - StartLanguageDetection(); -} - -void LanguageDetectionController::HistoryStateChanged() { - StartLanguageDetection(); +void LanguageDetectionController::DidFinishNavigation( + web::NavigationContext* navigation_context) { + if (navigation_context->IsSamePage()) + StartLanguageDetection(); } void LanguageDetectionController::WebStateDestroyed() {
diff --git a/content/browser/browser_main.cc b/content/browser/browser_main.cc index 772010c..5625a020 100644 --- a/content/browser/browser_main.cc +++ b/content/browser/browser_main.cc
@@ -6,7 +6,9 @@ #include <memory> +#include "base/trace_event/memory_dump_manager.h" #include "base/trace_event/trace_event.h" +#include "content/common/child_process_host_impl.h" #include "content/common/content_constants_internal.h" #include "content/public/browser/browser_main_runner.h" @@ -36,7 +38,8 @@ base::trace_event::TraceLog::GetInstance()->SetProcessName("Browser"); base::trace_event::TraceLog::GetInstance()->SetProcessSortIndex( kTraceEventBrowserProcessSortIndex); - + base::trace_event::MemoryDumpManager::GetInstance()->set_tracing_process_id( + ChildProcessHost::kBrowserTracingProcessId); std::unique_ptr<BrowserMainRunner> main_runner(BrowserMainRunner::Create()); int exit_code = main_runner->Initialize(parameters);
diff --git a/content/browser/tracing/memory_tracing_browsertest.cc b/content/browser/tracing/memory_tracing_browsertest.cc index fe96666..3ef05bfd 100644 --- a/content/browser/tracing/memory_tracing_browsertest.cc +++ b/content/browser/tracing/memory_tracing_browsertest.cc
@@ -20,6 +20,7 @@ #include "content/public/test/content_browser_test.h" #include "content/public/test/content_browser_test_utils.h" #include "content/shell/browser/shell.h" +#include "services/resource_coordinator/memory/coordinator/coordinator_impl.h" #include "testing/gmock/include/gmock/gmock.h" using base::trace_event::MemoryDumpArgs; @@ -122,6 +123,9 @@ GetTraceConfig_EmptyTriggers()); base::RunLoop run_loop; + // Start the Coordinator service. + memory_instrumentation::CoordinatorImpl::GetInstance( + base::ThreadTaskRunnerHandle::Get().get()); bool success = TracingController::GetInstance()->StartTracing( trace_config, run_loop.QuitClosure()); EXPECT_TRUE(success);
diff --git a/content/browser/tracing/trace_message_filter.cc b/content/browser/tracing/trace_message_filter.cc index 70089d9..a0e97d1b3 100644 --- a/content/browser/tracing/trace_message_filter.cc +++ b/content/browser/tracing/trace_message_filter.cc
@@ -46,10 +46,6 @@ OnTraceDataCollected) IPC_MESSAGE_HANDLER(TracingHostMsg_TraceLogStatusReply, OnTraceLogStatusReply) - IPC_MESSAGE_HANDLER(TracingHostMsg_GlobalMemoryDumpRequest, - OnGlobalMemoryDumpRequest) - IPC_MESSAGE_HANDLER(TracingHostMsg_ProcessMemoryDumpResponse, - OnProcessMemoryDumpResponse) IPC_MESSAGE_HANDLER(TracingHostMsg_TriggerBackgroundTrace, OnTriggerBackgroundTrace) IPC_MESSAGE_HANDLER(TracingHostMsg_AbortBackgroundTrace, @@ -87,18 +83,6 @@ Send(new TracingMsg_GetTraceLogStatus); } -// Called by TracingControllerImpl, which handles the multiprocess coordination. -void TraceMessageFilter::SendProcessMemoryDumpRequest( - const base::trace_event::MemoryDumpRequestArgs& args) { - Send(new TracingMsg_ProcessMemoryDumpRequest(args)); -} - -// Called by TracingControllerImpl, which handles the multiprocess coordination. -void TraceMessageFilter::SendGlobalMemoryDumpResponse(uint64_t dump_guid, - bool success) { - Send(new TracingMsg_GlobalMemoryDumpResponse(dump_guid, success)); -} - void TraceMessageFilter::OnChildSupportsTracing() { has_child_ = true; TracingControllerImpl::GetInstance()->AddTraceMessageFilter(this); @@ -133,19 +117,6 @@ } } -void TraceMessageFilter::OnGlobalMemoryDumpRequest( - const base::trace_event::MemoryDumpRequestArgs& args) { - TracingControllerImpl::GetInstance()->RequestGlobalMemoryDump( - args, - base::Bind(&TraceMessageFilter::SendGlobalMemoryDumpResponse, this)); -} - -void TraceMessageFilter::OnProcessMemoryDumpResponse(uint64_t dump_guid, - bool success) { - TracingControllerImpl::GetInstance()->OnProcessMemoryDumpResponse( - this, dump_guid, success); -} - void TraceMessageFilter::OnTriggerBackgroundTrace(const std::string& name) { BackgroundTracingManagerImpl::GetInstance()->OnHistogramTrigger(name); }
diff --git a/content/browser/tracing/trace_message_filter.h b/content/browser/tracing/trace_message_filter.h index 94c435e..97ae0a2 100644 --- a/content/browser/tracing/trace_message_filter.h +++ b/content/browser/tracing/trace_message_filter.h
@@ -11,7 +11,6 @@ #include <vector> #include "base/macros.h" -#include "base/trace_event/memory_dump_request_args.h" #include "base/trace_event/trace_event.h" #include "content/public/browser/browser_message_filter.h" @@ -36,8 +35,6 @@ void SendSetWatchEvent(const std::string& category_name, const std::string& event_name); void SendCancelWatchEvent(); - void SendProcessMemoryDumpRequest( - const base::trace_event::MemoryDumpRequestArgs& args); protected: ~TraceMessageFilter() override; @@ -49,11 +46,6 @@ void OnWatchEventMatched(); void OnTraceLogStatusReply(const base::trace_event::TraceLogStatus& status); void OnTraceDataCollected(const std::string& data); - void OnGlobalMemoryDumpRequest( - const base::trace_event::MemoryDumpRequestArgs& args); - void OnProcessMemoryDumpResponse(uint64_t dump_guid, bool success); - - void SendGlobalMemoryDumpResponse(uint64_t dump_guid, bool success); void OnTriggerBackgroundTrace(const std::string& histogram_name); void OnAbortBackgroundTrace();
diff --git a/content/browser/tracing/tracing_controller_impl.cc b/content/browser/tracing/tracing_controller_impl.cc index 5fc480346..54d1455 100644 --- a/content/browser/tracing/tracing_controller_impl.cc +++ b/content/browser/tracing/tracing_controller_impl.cc
@@ -193,13 +193,8 @@ pending_trace_log_status_ack_count_(0), maximum_trace_buffer_usage_(0), approximate_event_count_(0), - pending_memory_dump_ack_count_(0), - failed_memory_dump_count_(0), pending_clock_sync_ack_count_(0), is_tracing_(false) { - base::trace_event::MemoryDumpManager::GetInstance()->Initialize( - this /* delegate */, true /* is_coordinator */); - // Deliberately leaked, like this class. base::FileTracing::SetProvider(new FileTracingProviderImpl); } @@ -536,20 +531,6 @@ base::trace_event::TraceLogStatus())); } } - if (pending_memory_dump_ack_count_ > 0) { - DCHECK(!queued_memory_dump_requests_.empty()); - TraceMessageFilterSet::const_iterator it = - pending_memory_dump_filters_.find(trace_message_filter); - if (it != pending_memory_dump_filters_.end()) { - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind(&TracingControllerImpl::OnProcessMemoryDumpResponse, - base::Unretained(this), - base::RetainedRef(trace_message_filter), - queued_memory_dump_requests_.front().args.dump_guid, - false /* success */)); - } - } trace_message_filters_.erase(trace_message_filter); } @@ -896,87 +877,6 @@ sink->AddMetadata(std::move(filtered_metadata)); } -void TracingControllerImpl::RequestGlobalMemoryDump( - const base::trace_event::MemoryDumpRequestArgs& args, - const base::trace_event::MemoryDumpCallback& callback) { - if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind(&TracingControllerImpl::RequestGlobalMemoryDump, - base::Unretained(this), args, callback)); - return; - } - - bool another_dump_already_in_progress = !queued_memory_dump_requests_.empty(); - - // If this is a periodic memory dump request and there already is another - // request in the queue with the same level of detail, there's no point in - // enqueuing this request. - if (another_dump_already_in_progress && - args.dump_type == base::trace_event::MemoryDumpType::PERIODIC_INTERVAL) { - for (const auto& request : queued_memory_dump_requests_) { - if (request.args.level_of_detail == args.level_of_detail) { - VLOG(1) << base::trace_event::MemoryDumpManager::kLogPrefix << " (" - << base::trace_event::MemoryDumpTypeToString(args.dump_type) - << ") skipped because another dump request with the same " - "level of detail (" - << base::trace_event::MemoryDumpLevelOfDetailToString( - args.level_of_detail) - << ") is already in the queue"; - if (!callback.is_null()) - callback.Run(args.dump_guid, false /* success */); - return; - } - } - } - - queued_memory_dump_requests_.emplace_back(args, callback); - - // If another dump is already in progress, this dump will automatically be - // scheduled when the other dump finishes. - if (another_dump_already_in_progress) - return; - - PerformNextQueuedGlobalMemoryDump(); -} - -void TracingControllerImpl::PerformNextQueuedGlobalMemoryDump() { - DCHECK_CURRENTLY_ON(BrowserThread::UI); - DCHECK(!queued_memory_dump_requests_.empty()); - const base::trace_event::MemoryDumpRequestArgs& args = - queued_memory_dump_requests_.front().args; - - // Count myself (local trace) in pending_memory_dump_ack_count_, acked by - // OnBrowserProcessMemoryDumpDone(). - pending_memory_dump_ack_count_ = trace_message_filters_.size() + 1; - pending_memory_dump_filters_.clear(); - failed_memory_dump_count_ = 0; - - MemoryDumpManagerDelegate::CreateProcessDump( - args, base::Bind(&TracingControllerImpl::OnBrowserProcessMemoryDumpDone, - base::Unretained(this))); - - // If there are no child processes we are just done. - if (pending_memory_dump_ack_count_ == 1) - return; - - pending_memory_dump_filters_ = trace_message_filters_; - - for (const scoped_refptr<TraceMessageFilter>& tmf : trace_message_filters_) - tmf->SendProcessMemoryDumpRequest(args); -} - -TracingControllerImpl::QueuedMemoryDumpRequest::QueuedMemoryDumpRequest( - const base::trace_event::MemoryDumpRequestArgs& args, - const base::trace_event::MemoryDumpCallback& callback) - : args(args), callback(callback) {} - -TracingControllerImpl::QueuedMemoryDumpRequest::~QueuedMemoryDumpRequest() {} - -uint64_t TracingControllerImpl::GetTracingProcessId() const { - return ChildProcessHost::kBrowserTracingProcessId; -} - void TracingControllerImpl::AddTraceMessageFilterObserver( TraceMessageFilterObserver* observer) { DCHECK_CURRENTLY_ON(BrowserThread::UI); @@ -995,76 +895,4 @@ observer->OnTraceMessageFilterRemoved(filter.get()); } -void TracingControllerImpl::OnProcessMemoryDumpResponse( - TraceMessageFilter* trace_message_filter, - uint64_t dump_guid, - bool success) { - if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind(&TracingControllerImpl::OnProcessMemoryDumpResponse, - base::Unretained(this), - base::RetainedRef(trace_message_filter), dump_guid, - success)); - return; - } - - TraceMessageFilterSet::iterator it = - pending_memory_dump_filters_.find(trace_message_filter); - - DCHECK(!queued_memory_dump_requests_.empty()); - if (queued_memory_dump_requests_.front().args.dump_guid != dump_guid || - it == pending_memory_dump_filters_.end()) { - DLOG(WARNING) << "Received unexpected memory dump response: " << dump_guid; - return; - } - - DCHECK_GT(pending_memory_dump_ack_count_, 0); - --pending_memory_dump_ack_count_; - pending_memory_dump_filters_.erase(it); - if (!success) { - ++failed_memory_dump_count_; - VLOG(1) << base::trace_event::MemoryDumpManager::kLogPrefix - << " failed because of NACK from child " - << trace_message_filter->peer_pid(); - } - FinalizeGlobalMemoryDumpIfAllProcessesReplied(); -} - -void TracingControllerImpl::OnBrowserProcessMemoryDumpDone(uint64_t dump_guid, - bool success) { - DCHECK_GT(pending_memory_dump_ack_count_, 0); - --pending_memory_dump_ack_count_; - if (!success) { - ++failed_memory_dump_count_; - VLOG(1) << base::trace_event::MemoryDumpManager::kLogPrefix - << " aborted on the current process"; - } - FinalizeGlobalMemoryDumpIfAllProcessesReplied(); -} - -void TracingControllerImpl::FinalizeGlobalMemoryDumpIfAllProcessesReplied() { - if (pending_memory_dump_ack_count_ > 0) - return; - - DCHECK(!queued_memory_dump_requests_.empty()); - { - const auto& callback = queued_memory_dump_requests_.front().callback; - if (!callback.is_null()) { - const bool global_success = failed_memory_dump_count_ == 0; - callback.Run(queued_memory_dump_requests_.front().args.dump_guid, - global_success); - } - } - queued_memory_dump_requests_.pop_front(); - - // Schedule the next queued dump (if applicable). - if (!queued_memory_dump_requests_.empty()) { - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind(&TracingControllerImpl::PerformNextQueuedGlobalMemoryDump, - base::Unretained(this))); - } -} - } // namespace content
diff --git a/content/browser/tracing/tracing_controller_impl.h b/content/browser/tracing/tracing_controller_impl.h index 0c7b8ea7..81ce092 100644 --- a/content/browser/tracing/tracing_controller_impl.h +++ b/content/browser/tracing/tracing_controller_impl.h
@@ -47,7 +47,6 @@ class TracingControllerImpl : public TracingController, - public base::trace_event::MemoryDumpManagerDelegate, public base::trace_event::TracingAgent { public: // Create an endpoint that may be supplied to any TraceDataSink to @@ -88,12 +87,6 @@ const std::string& sync_id, const RecordClockSyncMarkerCallback& callback) override; - // base::trace_event::MemoryDumpManagerDelegate implementation. - void RequestGlobalMemoryDump( - const base::trace_event::MemoryDumpRequestArgs& args, - const base::trace_event::MemoryDumpCallback& callback) override; - uint64_t GetTracingProcessId() const override; - class TraceMessageFilterObserver { public: virtual void OnTraceMessageFilterAdded(TraceMessageFilter* filter) = 0; @@ -106,16 +99,6 @@ friend struct base::DefaultLazyInstanceTraits<TracingControllerImpl>; friend class TraceMessageFilter; - // The arguments and callback for an queued global memory dump request. - struct QueuedMemoryDumpRequest { - QueuedMemoryDumpRequest( - const base::trace_event::MemoryDumpRequestArgs& args, - const base::trace_event::MemoryDumpCallback& callback); - ~QueuedMemoryDumpRequest(); - const base::trace_event::MemoryDumpRequestArgs args; - const base::trace_event::MemoryDumpCallback callback; - }; - TracingControllerImpl(); ~TracingControllerImpl() override; @@ -139,8 +122,6 @@ return pending_trace_buffer_usage_callback_.is_null(); } - void PerformNextQueuedGlobalMemoryDump(); - // Methods for use by TraceMessageFilter. void AddTraceMessageFilter(TraceMessageFilter* trace_message_filter); void RemoveTraceMessageFilter(TraceMessageFilter* trace_message_filter); @@ -170,14 +151,6 @@ void OnTraceLogStatusReply(TraceMessageFilter* trace_message_filter, const base::trace_event::TraceLogStatus& status); - void OnProcessMemoryDumpResponse(TraceMessageFilter* trace_message_filter, - uint64_t dump_guid, - bool success); - - // Callback of MemoryDumpManager::CreateProcessDump(). - void OnBrowserProcessMemoryDumpDone(uint64_t dump_guid, bool success); - - void FinalizeGlobalMemoryDumpIfAllProcessesReplied(); void SetEnabledOnFileThread( const base::trace_event::TraceConfig& trace_config, @@ -218,12 +191,6 @@ float maximum_trace_buffer_usage_; size_t approximate_event_count_; - // Pending acks for memory RequestGlobalDumpPoint. - int pending_memory_dump_ack_count_; - int failed_memory_dump_count_; - TraceMessageFilterSet pending_memory_dump_filters_; - std::list<QueuedMemoryDumpRequest> queued_memory_dump_requests_; - std::vector<base::trace_event::TracingAgent*> additional_tracing_agents_; int pending_clock_sync_ack_count_; base::OneShotTimer clock_sync_timer_;
diff --git a/content/child/BUILD.gn b/content/child/BUILD.gn index da0aba5..4eb0e6b6 100644 --- a/content/child/BUILD.gn +++ b/content/child/BUILD.gn
@@ -240,6 +240,7 @@ "//net", "//services/device/public/cpp/power_monitor", "//services/device/public/interfaces:constants", + "//services/resource_coordinator/public/cpp", "//services/service_manager/public/cpp", "//services/service_manager/public/interfaces", "//services/service_manager/runner/common",
diff --git a/content/child/DEPS b/content/child/DEPS index 3f315c9..3a07c1cb 100644 --- a/content/child/DEPS +++ b/content/child/DEPS
@@ -11,6 +11,7 @@ "+content/public/child", "+services/device/public/cpp/power_monitor", "+services/device/public/interfaces", + "+services/resource_coordinator", "+services/service_manager", "+services/service_manager", "+v8/include/v8.h"
diff --git a/content/child/child_thread_impl.cc b/content/child/child_thread_impl.cc index 0e42540..135a424 100644 --- a/content/child/child_thread_impl.cc +++ b/content/child/child_thread_impl.cc
@@ -66,6 +66,7 @@ #include "mojo/public/cpp/system/platform_handle.h" #include "services/device/public/cpp/power_monitor/power_monitor_broadcast_source.h" #include "services/device/public/interfaces/constants.mojom.h" +#include "services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl.h" #include "services/service_manager/public/cpp/connector.h" #include "services/service_manager/public/cpp/interface_factory.h" #include "services/service_manager/public/cpp/interface_provider.h" @@ -502,6 +503,10 @@ channel_->AddFilter(new tracing::ChildTraceMessageFilter( ChildProcess::current()->io_task_runner())); channel_->AddFilter(new ChildMemoryMessageFilter()); + + memory_instrumentation::MemoryDumpManagerDelegateImpl* delegate = + memory_instrumentation::MemoryDumpManagerDelegateImpl::GetInstance(); + delegate->InitializeWithInterfaceProvider(GetRemoteInterfaces()); } // In single process mode we may already have a power monitor,
diff --git a/content/public/app/mojo/content_browser_manifest.json b/content/public/app/mojo/content_browser_manifest.json index 5628eb4..89024675 100644 --- a/content/public/app/mojo/content_browser_manifest.json +++ b/content/public/app/mojo/content_browser_manifest.json
@@ -4,6 +4,9 @@ "interface_provider_specs": { "service_manager:connector": { "provides": { + "gpu": [ + "memory_instrumentation::mojom::Coordinator" + ], "plugin": [ "discardable_memory::mojom::DiscardableSharedMemoryManager", "ui::mojom::Gpu" @@ -34,6 +37,7 @@ "discardable_memory::mojom::DiscardableSharedMemoryManager", "media::mojom::ImageCapture", "memory_coordinator::mojom::MemoryCoordinatorHandle", + "memory_instrumentation::mojom::Coordinator", "payments::mojom::PaymentAppManager", "shape_detection::mojom::BarcodeDetection", "shape_detection::mojom::FaceDetectionProvider",
diff --git a/content/renderer/media/media_stream_constraints_util_video_device.cc b/content/renderer/media/media_stream_constraints_util_video_device.cc index 3e2f3e80..84d415f 100644 --- a/content/renderer/media/media_stream_constraints_util_video_device.cc +++ b/content/renderer/media/media_stream_constraints_util_video_device.cc
@@ -21,8 +21,8 @@ // Number of default settings to be used as final tie-breaking criteria for // settings that are equally good at satisfying constraints: -// device ID, power-line frequency, resolution and frame rate. -const int kNumDefaultDistanceEntries = 4; +// device ID, power-line frequency, noise reduction, resolution and frame rate. +const int kNumDefaultDistanceEntries = 5; // The default resolution to be preferred as tie-breaking criterion. const int kDefaultResolutionArea = MediaStreamVideoSource::kDefaultWidth * @@ -60,11 +60,13 @@ const std::string& device_id, const media::VideoCaptureFormat& format, ::mojom::FacingMode facing_mode, - media::PowerLineFrequency power_line_frequency) + media::PowerLineFrequency power_line_frequency, + const rtc::Optional<bool>& noise_reduction) : device_id_(device_id), format_(format), facing_mode_(facing_mode), - power_line_frequency_(power_line_frequency) {} + power_line_frequency_(power_line_frequency), + noise_reduction_(noise_reduction) {} VideoDeviceCaptureSourceSettings( const VideoDeviceCaptureSourceSettings& other) = default; @@ -99,12 +101,16 @@ media::PowerLineFrequency power_line_frequency() const { return power_line_frequency_; } + const rtc::Optional<bool>& noise_reduction() const { + return noise_reduction_; + } private: std::string device_id_; media::VideoCaptureFormat format_; ::mojom::FacingMode facing_mode_; media::PowerLineFrequency power_line_frequency_; + rtc::Optional<bool> noise_reduction_; }; VideoDeviceCaptureSourceSelectionResult ResultFromSettings( @@ -114,6 +120,7 @@ result.capture_params.requested_format = settings.format(); result.device_id = settings.device_id(); result.facing_mode = settings.facing_mode(); + result.noise_reduction = settings.noise_reduction(); result.failed_constraint_name = nullptr; return result; @@ -324,6 +331,25 @@ return 0.0; } +// Returns a custom distance function suitable for the googNoiseReduction +// constraint, given a |constraint| and a candidate value |value|. +// The distance is HUGE_VAL if |candidate_value| cannot satisfy |constraint|. +// Otherwise, the distance is zero. +double NoiseReductionConstraintSourceDistance( + const blink::BooleanConstraint& constraint, + const rtc::Optional<bool>& value, + const char** failed_constraint_name) { + if (!constraint.hasExact()) + return 0.0; + + if (value && *value == constraint.exact()) + return 0.0; + + if (failed_constraint_name) + *failed_constraint_name = constraint.name(); + return HUGE_VAL; +} + // Returns a custom distance for constraints that depend on the device // characteristics that have a fixed value. double DeviceSourceDistance( @@ -379,7 +405,10 @@ failed_constraint_name) + PowerLineFrequencyConstraintSourceDistance( constraint_set.googPowerLineFrequency, - candidate.power_line_frequency(), failed_constraint_name); + candidate.power_line_frequency(), failed_constraint_name) + + NoiseReductionConstraintSourceDistance( + constraint_set.googNoiseReduction, candidate.noise_reduction(), + failed_constraint_name); } // Returns the fitness distance between |value| and |constraint|. @@ -511,6 +540,21 @@ return 1.0; } +// Returns the fitness distance between |value| and |constraint| for the +// googNoiseReduction constraint. +// Based on https://w3c.github.io/mediacapture-main/#dfn-fitness-distance. +double NoiseReductionConstraintFitnessDistance( + const rtc::Optional<bool>& value, + const blink::BooleanConstraint& constraint) { + if (!constraint.hasIdeal()) + return 0.0; + + if (value && value == constraint.ideal()) + return 0.0; + + return 1.0; +} + // Returns the fitness distance between a settings candidate and a constraint // set. The returned value is the sum of the fitness distances between each // setting in |candidate| and the corresponding constraint in |constraint_set|. @@ -534,6 +578,8 @@ constraint_set.videoKind); fitness += PowerLineFrequencyConstraintFitnessDistance( candidate.GetPowerLineFrequency(), constraint_set.googPowerLineFrequency); + fitness += NoiseReductionConstraintFitnessDistance( + candidate.noise_reduction(), constraint_set.googNoiseReduction); fitness += ResolutionConstraintFitnessDistance(candidate.GetHeight(), constraint_set.height); fitness += ResolutionConstraintFitnessDistance(candidate.GetWidth(), @@ -591,6 +637,12 @@ : HUGE_VAL; distance_vector->push_back(power_line_frequency_distance); + // Prefer not having a specific noise-reduction value and let the lower-layers + // implementation choose a noise-reduction strategy. + double noise_reduction_distance = + candidate.noise_reduction() ? HUGE_VAL : 0.0; + distance_vector->push_back(noise_reduction_distance); + // Prefer a resolution with area close to the default. int candidate_area = candidate.format().frame_size.GetArea(); double resolution_distance = @@ -692,52 +744,63 @@ if (!std::isfinite(basic_power_line_frequency_distance)) continue; - // The candidate satisfies the basic constraint set. - double candidate_basic_custom_distance = - basic_device_distance + basic_format_distance + - basic_power_line_frequency_distance; - DCHECK(std::isfinite(candidate_basic_custom_distance)); + for (auto& noise_reduction : + capabilities.noise_reduction_capabilities) { + double basic_noise_reduction_distance = + NoiseReductionConstraintSourceDistance( + constraints.basic().googNoiseReduction, noise_reduction, + &failed_constraint_name); + if (!std::isfinite(basic_noise_reduction_distance)) + continue; - // Temporary vector to save custom distances for advanced constraints. - // Custom distances must be added to the candidate distance vector after - // all the spec-mandated values. - DistanceVector advanced_custom_distance_vector; - VideoDeviceCaptureSourceSettings candidate(device->device_id, format, - device->facing_mode, - power_line_frequency); - DistanceVector candidate_distance_vector; - // First criteria for valid candidates is satisfaction of advanced - // constraint sets. - for (const auto& advanced : constraints.advanced()) { - double custom_distance = - CandidateSourceDistance(candidate, advanced, nullptr); - advanced_custom_distance_vector.push_back(custom_distance); - double spec_distance = std::isfinite(custom_distance) ? 0 : 1; - candidate_distance_vector.push_back(spec_distance); - } + // The candidate satisfies the basic constraint set. + double candidate_basic_custom_distance = + basic_device_distance + basic_format_distance + + basic_power_line_frequency_distance + + basic_noise_reduction_distance; + DCHECK(std::isfinite(candidate_basic_custom_distance)); - // Second criterion is fitness distance. - candidate_distance_vector.push_back( - CandidateFitnessDistance(candidate, constraints.basic())); + // Temporary vector to save custom distances for advanced constraints. + // Custom distances must be added to the candidate distance vector + // after all the spec-mandated values. + DistanceVector advanced_custom_distance_vector; + VideoDeviceCaptureSourceSettings candidate( + device->device_id, format, device->facing_mode, + power_line_frequency, noise_reduction); + DistanceVector candidate_distance_vector; + // First criteria for valid candidates is satisfaction of advanced + // constraint sets. + for (const auto& advanced : constraints.advanced()) { + double custom_distance = + CandidateSourceDistance(candidate, advanced, nullptr); + advanced_custom_distance_vector.push_back(custom_distance); + double spec_distance = std::isfinite(custom_distance) ? 0 : 1; + candidate_distance_vector.push_back(spec_distance); + } - // Third criteria are custom distances to constraint sets. - candidate_distance_vector.push_back(candidate_basic_custom_distance); - std::copy(advanced_custom_distance_vector.begin(), - advanced_custom_distance_vector.end(), - std::back_inserter(candidate_distance_vector)); + // Second criterion is fitness distance. + candidate_distance_vector.push_back( + CandidateFitnessDistance(candidate, constraints.basic())); - // Fourth criteria is native fitness distance. - candidate_distance_vector.push_back( - CandidateNativeFitnessDistance(candidate, constraints.basic())); + // Third criteria are custom distances to constraint sets. + candidate_distance_vector.push_back(candidate_basic_custom_distance); + std::copy(advanced_custom_distance_vector.begin(), + advanced_custom_distance_vector.end(), + std::back_inserter(candidate_distance_vector)); - // Final criteria are custom distances to default settings. - AppendDistanceFromDefault(candidate, capabilities, - &candidate_distance_vector); + // Fourth criteria is native fitness distance. + candidate_distance_vector.push_back( + CandidateNativeFitnessDistance(candidate, constraints.basic())); - DCHECK_EQ(best_distance.size(), candidate_distance_vector.size()); - if (candidate_distance_vector < best_distance) { - best_distance = candidate_distance_vector; - result = ResultFromSettings(candidate); + // Final criteria are custom distances to default settings. + AppendDistanceFromDefault(candidate, capabilities, + &candidate_distance_vector); + + DCHECK_EQ(best_distance.size(), candidate_distance_vector.size()); + if (candidate_distance_vector < best_distance) { + best_distance = candidate_distance_vector; + result = ResultFromSettings(candidate); + } } } }
diff --git a/content/renderer/media/media_stream_constraints_util_video_device.h b/content/renderer/media/media_stream_constraints_util_video_device.h index af55fdc..71a1925 100644 --- a/content/renderer/media/media_stream_constraints_util_video_device.h +++ b/content/renderer/media/media_stream_constraints_util_video_device.h
@@ -11,6 +11,7 @@ #include "content/common/content_export.h" #include "content/common/media/media_devices.mojom.h" #include "media/capture/video_capture_types.h" +#include "third_party/webrtc/base/optional.h" namespace blink { class WebString; @@ -34,6 +35,7 @@ // Each field is independent of each other. std::vector<::mojom::VideoInputDeviceCapabilitiesPtr> device_capabilities; std::vector<media::PowerLineFrequency> power_line_capabilities; + std::vector<rtc::Optional<bool>> noise_reduction_capabilities; }; struct CONTENT_EXPORT VideoDeviceCaptureSourceSelectionResult { @@ -69,6 +71,7 @@ std::string device_id; ::mojom::FacingMode facing_mode; media::VideoCaptureParams capture_params; + rtc::Optional<bool> noise_reduction; }; // This function performs source and source-settings selection based on @@ -130,9 +133,9 @@ // ideal value and thus has worse fitness according to step 2, even if C3's // native fitness is better than C1's and C2's. // 5. C1 is better than C2 if its settings are closer to certain default -// settings that include the device ID, power-line frequency, resolution, and -// frame rate, in that order. Note that there is no default facing mode or -// aspect ratio. +// settings that include the device ID, power-line frequency, noise +// reduction, resolution, and frame rate, in that order. Note that there is +// no default facing mode or aspect ratio. VideoDeviceCaptureSourceSelectionResult CONTENT_EXPORT SelectVideoDeviceCaptureSourceSettings( const VideoDeviceCaptureCapabilities& capabilities,
diff --git a/content/renderer/media/media_stream_constraints_util_video_device_unittest.cc b/content/renderer/media/media_stream_constraints_util_video_device_unittest.cc index 5247f39..beac59c 100644 --- a/content/renderer/media/media_stream_constraints_util_video_device_unittest.cc +++ b/content/renderer/media/media_stream_constraints_util_video_device_unittest.cc
@@ -100,6 +100,11 @@ media::PowerLineFrequency::FREQUENCY_60HZ, }; + capabilities_.noise_reduction_capabilities = { + rtc::Optional<bool>(), rtc::Optional<bool>(true), + rtc::Optional<bool>(false), + }; + default_device_ = capabilities_.device_capabilities[0].get(); low_res_device_ = capabilities_.device_capabilities[1].get(); high_res_device_ = capabilities_.device_capabilities[2].get(); @@ -138,6 +143,10 @@ EXPECT_EQ(default_device_->device_id, result.device_id); EXPECT_EQ(default_device_->facing_mode, result.facing_mode); EXPECT_EQ(*default_closest_format_, result.Format()); + // Should select default settings for other constraints. + EXPECT_EQ(media::PowerLineFrequency::FREQUENCY_DEFAULT, + result.PowerLineFrequency()); + EXPECT_EQ(rtc::Optional<bool>(), result.noise_reduction); } // The "Overconstrained" tests verify that failure of any single required @@ -293,6 +302,34 @@ result.failed_constraint_name); } +TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, + OverconstrainedOnNoiseReduction) { + // Simulate a system that does not support noise reduction. + // Manually adding device capabilities because VideoDeviceCaptureCapabilities + // is move only. + VideoDeviceCaptureCapabilities capabilities; + ::mojom::VideoInputDeviceCapabilitiesPtr device = + ::mojom::VideoInputDeviceCapabilities::New(); + device->device_id = kDeviceID1; + device->facing_mode = ::mojom::FacingMode::NONE; + device->formats = { + media::VideoCaptureFormat(gfx::Size(200, 200), 40.0f, + media::PIXEL_FORMAT_I420), + }; + capabilities.device_capabilities.push_back(std::move(device)); + capabilities.power_line_capabilities = capabilities_.power_line_capabilities; + capabilities.noise_reduction_capabilities = {rtc::Optional<bool>(false)}; + + constraint_factory_.Reset(); + constraint_factory_.basic().googNoiseReduction.setExact(true); + auto constraints = constraint_factory_.CreateWebMediaConstraints(); + auto result = + SelectVideoDeviceCaptureSourceSettings(capabilities, constraints); + EXPECT_FALSE(result.HasValue()); + EXPECT_EQ(constraint_factory_.basic().googNoiseReduction.name(), + result.failed_constraint_name); +} + // The "Mandatory" and "Ideal" tests check that various selection criteria work // for each individual constraint in the basic constraint set. TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryDeviceID) { @@ -385,6 +422,22 @@ } } +TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryNoiseReduction) { + constraint_factory_.Reset(); + const bool kNoiseReductionValues[] = {true, false}; + for (auto noise_reduction : kNoiseReductionValues) { + constraint_factory_.basic().googNoiseReduction.setExact(noise_reduction); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(noise_reduction, result.noise_reduction); + // The default device and settings closest to the default should be + // selected. + EXPECT_EQ(default_device_->device_id, result.device_id); + EXPECT_EQ(default_device_->facing_mode, result.facing_mode); + EXPECT_EQ(*default_closest_format_, result.Format()); + } +} + TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryExactHeight) { constraint_factory_.Reset(); const int kHeight = MediaStreamVideoSource::kDefaultHeight; @@ -1192,99 +1245,161 @@ // The "Advanced" tests check selection criteria involving advanced constraint // sets. TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, AdvancedExactResolution) { - { - constraint_factory_.Reset(); - blink::WebMediaTrackConstraintSet& advanced1 = - constraint_factory_.AddAdvanced(); - advanced1.width.setExact(4000); - advanced1.height.setExact(4000); - blink::WebMediaTrackConstraintSet& advanced2 = - constraint_factory_.AddAdvanced(); - advanced2.width.setExact(3000); - advanced2.height.setExact(3000); - auto result = SelectSettings(); - // No device supports the advanced constraint sets. - // Tie-breaker rule that applies is closeness to default settings. - EXPECT_EQ(default_device_->device_id, result.device_id); - EXPECT_EQ(*default_closest_format_, result.Format()); + constraint_factory_.Reset(); + blink::WebMediaTrackConstraintSet& advanced1 = + constraint_factory_.AddAdvanced(); + advanced1.width.setExact(4000); + advanced1.height.setExact(4000); + blink::WebMediaTrackConstraintSet& advanced2 = + constraint_factory_.AddAdvanced(); + advanced2.width.setExact(3000); + advanced2.height.setExact(3000); + auto result = SelectSettings(); + // No device supports the advanced constraint sets. + // Tie-breaker rule that applies is closeness to default settings. + EXPECT_EQ(default_device_->device_id, result.device_id); + EXPECT_EQ(*default_closest_format_, result.Format()); - blink::WebMediaTrackConstraintSet& advanced3 = - constraint_factory_.AddAdvanced(); - advanced3.width.setExact(1920); - advanced3.height.setExact(1080); - result = SelectSettings(); - EXPECT_TRUE(result.HasValue()); - // The high-res device natively supports the third advanced constraint set - // and should be selected. - // First tie-breaker rule that applies is support for advanced constraints - // that appear first. Second tie-breaker rule is custom distance to advanced - // constraint sets that appear first. - EXPECT_EQ(high_res_device_->device_id, result.device_id); - EXPECT_EQ(1920, result.Width()); - EXPECT_EQ(1080, result.Height()); + blink::WebMediaTrackConstraintSet& advanced3 = + constraint_factory_.AddAdvanced(); + advanced3.width.setExact(1920); + advanced3.height.setExact(1080); + result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // The high-res device natively supports the third advanced constraint set + // and should be selected. + // First tie-breaker rule that applies is support for advanced constraints + // that appear first. Second tie-breaker rule is custom distance to advanced + // constraint sets that appear first. + EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(1920, result.Width()); + EXPECT_EQ(1080, result.Height()); - blink::WebMediaTrackConstraintSet& advanced4 = - constraint_factory_.AddAdvanced(); - advanced4.width.setExact(640); - advanced4.height.setExact(480); - result = SelectSettings(); - EXPECT_TRUE(result.HasValue()); - // First tie-breaker rule that applies is support for advanced constraints - // that appear first, which leaves out configurations that only support the - // fourth advanced constraint set in favor of configurations that support - // the third set. - // Second tie-breaker rule is custom distance to advanced constraint sets - // that appear first. - EXPECT_EQ(high_res_device_->device_id, result.device_id); - EXPECT_EQ(1920, result.Width()); - EXPECT_EQ(1080, result.Height()); + blink::WebMediaTrackConstraintSet& advanced4 = + constraint_factory_.AddAdvanced(); + advanced4.width.setExact(640); + advanced4.height.setExact(480); + result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // First tie-breaker rule that applies is support for advanced constraints + // that appear first, which leaves out configurations that only support the + // fourth advanced constraint set in favor of configurations that support + // the third set. + // Second tie-breaker rule is custom distance to advanced constraint sets + // that appear first. + EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(1920, result.Width()); + EXPECT_EQ(1080, result.Height()); - constraint_factory_.basic().width.setIdeal(800); - constraint_factory_.basic().height.setIdeal(600); - result = SelectSettings(); - EXPECT_TRUE(result.HasValue()); - // The ideal value is supported by the same configuration, so nothing - // changes. - EXPECT_EQ(high_res_device_->device_id, result.device_id); - EXPECT_EQ(1920, result.Width()); - EXPECT_EQ(1080, result.Height()); + constraint_factory_.basic().width.setIdeal(800); + constraint_factory_.basic().height.setIdeal(600); + result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // The ideal value is supported by the same configuration, so nothing + // changes. + EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(1920, result.Width()); + EXPECT_EQ(1080, result.Height()); - constraint_factory_.basic().width.setIdeal(2000); - constraint_factory_.basic().height.setIdeal(1500); - result = SelectSettings(); - EXPECT_TRUE(result.HasValue()); - // The closest configuration to the ideal resolution is the high-res device - // at the highest resolution. - EXPECT_EQ(high_res_device_->device_id, result.device_id); - EXPECT_EQ(*high_res_highest_format_, result.Format()); - } + constraint_factory_.basic().width.setIdeal(2000); + constraint_factory_.basic().height.setIdeal(1500); + result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // The closest configuration to the ideal resolution is the high-res device + // at the highest resolution. + EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(*high_res_highest_format_, result.Format()); } TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, AdvancedResolutionAndFrameRate) { + constraint_factory_.Reset(); + blink::WebMediaTrackConstraintSet& advanced1 = + constraint_factory_.AddAdvanced(); + advanced1.width.setExact(1920); + advanced1.height.setExact(1080); + blink::WebMediaTrackConstraintSet& advanced2 = + constraint_factory_.AddAdvanced(); + advanced2.frameRate.setExact(60.0); + blink::WebMediaTrackConstraintSet& advanced3 = + constraint_factory_.AddAdvanced(); + advanced3.width.setExact(2304); + advanced3.height.setExact(1536); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // The high-res device is the only one that satisfies the first advanced + // set. 2304x1536x10.0 satisfies sets 1 and 3, while 1920x1080x60.0 + // satisfies sets 1, and 2. The latter must be selected, regardless of + // any other criteria. + EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(1920, result.Width()); + EXPECT_EQ(1080, result.Height()); + EXPECT_EQ(60.0, result.FrameRate()); +} + +TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, AdvancedNoiseReduction) { + constraint_factory_.Reset(); + blink::WebMediaTrackConstraintSet& advanced1 = + constraint_factory_.AddAdvanced(); + advanced1.width.setExact(640); + advanced1.height.setExact(480); + blink::WebMediaTrackConstraintSet& advanced2 = + constraint_factory_.AddAdvanced(); + advanced2.width.setExact(1920); + advanced2.height.setExact(1080); + advanced2.googNoiseReduction.setExact(false); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + EXPECT_EQ(high_res_device_->device_id, result.device_id); + EXPECT_EQ(1920, result.Width()); + EXPECT_EQ(1080, result.Height()); + EXPECT_TRUE(result.noise_reduction && !*result.noise_reduction); +} + +TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, + AdvancedContradictoryNoiseReduction) { { constraint_factory_.Reset(); blink::WebMediaTrackConstraintSet& advanced1 = constraint_factory_.AddAdvanced(); - advanced1.width.setExact(1920); - advanced1.height.setExact(1080); + advanced1.width.setMin(640); + advanced1.height.setMin(480); + advanced1.googNoiseReduction.setExact(true); blink::WebMediaTrackConstraintSet& advanced2 = constraint_factory_.AddAdvanced(); - advanced2.frameRate.setExact(60.0); - blink::WebMediaTrackConstraintSet& advanced3 = - constraint_factory_.AddAdvanced(); - advanced3.width.setExact(2304); - advanced3.height.setExact(1536); + advanced2.width.setMin(1920); + advanced2.height.setMin(1080); + advanced2.googNoiseReduction.setExact(false); auto result = SelectSettings(); EXPECT_TRUE(result.HasValue()); - // The high-res device is the only one that satisfies the first advanced - // set. 2304x1536x10.0 satisfies sets 1 and 3, while 1920x1080x60.0 - // satisfies sets 1, and 2. The latter must be selected, regardless of - // any other criteria. + // The second advanced set cannot be satisfied because it contradicts the + // first set. The default device supports the first set and should be + // selected. + EXPECT_EQ(default_device_->device_id, result.device_id); + EXPECT_LE(640, result.Width()); + EXPECT_LE(480, result.Height()); + EXPECT_TRUE(result.noise_reduction && *result.noise_reduction); + } + + // Same test without noise reduction + { + constraint_factory_.Reset(); + blink::WebMediaTrackConstraintSet& advanced1 = + constraint_factory_.AddAdvanced(); + advanced1.width.setMin(640); + advanced1.height.setMin(480); + blink::WebMediaTrackConstraintSet& advanced2 = + constraint_factory_.AddAdvanced(); + advanced2.width.setMin(1920); + advanced2.height.setMin(1080); + auto result = SelectSettings(); + EXPECT_TRUE(result.HasValue()); + // Only the high-res device can satisfy the second advanced set. EXPECT_EQ(high_res_device_->device_id, result.device_id); - EXPECT_EQ(1920, result.Width()); - EXPECT_EQ(1080, result.Height()); - EXPECT_EQ(60.0, result.FrameRate()); + EXPECT_LE(1920, result.Width()); + EXPECT_LE(1080, result.Height()); + // Should select default noise reduction setting. + EXPECT_TRUE(!result.noise_reduction); } }
diff --git a/content/renderer/media/user_media_client_impl.cc b/content/renderer/media/user_media_client_impl.cc index d8cc904..439e0af 100644 --- a/content/renderer/media/user_media_client_impl.cc +++ b/content/renderer/media/user_media_client_impl.cc
@@ -372,6 +372,9 @@ media::PowerLineFrequency::FREQUENCY_DEFAULT, media::PowerLineFrequency::FREQUENCY_50HZ, media::PowerLineFrequency::FREQUENCY_60HZ}; + capabilities.noise_reduction_capabilities = {rtc::Optional<bool>(), + rtc::Optional<bool>(true), + rtc::Optional<bool>(false)}; base::PostTaskAndReplyWithResult( worker_task_runner_.get(), FROM_HERE,
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index 9d993b3..ee8ec0b 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -738,6 +738,7 @@ "//net:test_support", "//ppapi/features", "//services/catalog:lib", + "//services/resource_coordinator:lib", "//services/service_manager/public/cpp", "//services/ui/public/cpp/gpu", "//storage/browser",
diff --git a/extensions/shell/OWNERS b/extensions/shell/OWNERS index 047582d..420da75e4 100644 --- a/extensions/shell/OWNERS +++ b/extensions/shell/OWNERS
@@ -1,3 +1,6 @@ derat@chromium.org jamescook@chromium.org steel@chromium.org + +# TEAM: extensions-dev@chromium.org +# COMPONENT: Platform>Extensions
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc index 5d7e214..3eaf1adc7 100644 --- a/gpu/command_buffer/service/feature_info.cc +++ b/gpu/command_buffer/service/feature_info.cc
@@ -110,6 +110,98 @@ GLint orig_binding_; }; +bool IsWebGLDrawBuffersSupported(GLenum depth_texture_internal_format, + GLenum depth_stencil_texture_internal_format) { + // This is called after we make sure GL_EXT_draw_buffers is supported. + GLint max_draw_buffers = 0; + GLint max_color_attachments = 0; + glGetIntegerv(GL_MAX_DRAW_BUFFERS, &max_draw_buffers); + glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &max_color_attachments); + if (max_draw_buffers < 4 || max_color_attachments < 4) { + return false; + } + + GLint fb_binding = 0; + GLint tex_binding = 0; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fb_binding); + glGetIntegerv(GL_TEXTURE_BINDING_2D, &tex_binding); + + GLuint fbo; + glGenFramebuffersEXT(1, &fbo); + glBindFramebufferEXT(GL_FRAMEBUFFER, fbo); + + GLuint depth_stencil_texture = 0; + if (depth_stencil_texture_internal_format != GL_NONE) { + glGenTextures(1, &depth_stencil_texture); + glBindTexture(GL_TEXTURE_2D, depth_stencil_texture); + glTexImage2D(GL_TEXTURE_2D, 0, depth_stencil_texture_internal_format, 1, 1, + 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, nullptr); + } + + GLuint depth_texture = 0; + if (depth_texture_internal_format != GL_NONE) { + glGenTextures(1, &depth_texture); + glBindTexture(GL_TEXTURE_2D, depth_texture); + glTexImage2D(GL_TEXTURE_2D, 0, depth_texture_internal_format, 1, 1, 0, + GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr); + } + + GLint max_allowed_buffers = std::min(max_draw_buffers, max_color_attachments); + std::vector<GLuint> colors(max_allowed_buffers, 0); + glGenTextures(max_allowed_buffers, colors.data()); + + bool result = true; + for (GLint i = 0; i < max_allowed_buffers; ++i) { + GLint color = colors[i]; + glBindTexture(GL_TEXTURE_2D, color); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, + nullptr); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, + GL_TEXTURE_2D, color, 0); + if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER) != + GL_FRAMEBUFFER_COMPLETE) { + result = false; + break; + } + if (depth_texture != 0) { + glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_TEXTURE_2D, depth_texture, 0); + if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER) != + GL_FRAMEBUFFER_COMPLETE) { + result = false; + break; + } + glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_TEXTURE_2D, 0, 0); + } + if (depth_stencil_texture != 0) { + // For ES 2.0 contexts DEPTH_STENCIL is not available natively, so we + // emulate it at the command buffer level for WebGL contexts. + glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, + GL_TEXTURE_2D, depth_stencil_texture, 0); + if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER) != + GL_FRAMEBUFFER_COMPLETE) { + result = false; + break; + } + glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, + GL_TEXTURE_2D, 0, 0); + } + } + + glBindFramebufferEXT(GL_FRAMEBUFFER, static_cast<GLuint>(fb_binding)); + glDeleteFramebuffersEXT(1, &fbo); + + glBindTexture(GL_TEXTURE_2D, static_cast<GLuint>(tex_binding)); + glDeleteTextures(1, &depth_texture); + glDeleteTextures(1, &depth_stencil_texture); + glDeleteTextures(colors.size(), colors.data()); + + DCHECK(glGetError() == GL_NO_ERROR); + + return result; +} + } // anonymous namespace. FeatureInfo::FeatureFlags::FeatureFlags() {} @@ -462,6 +554,7 @@ // get rid of it. // bool enable_depth_texture = false; + GLenum depth_texture_format = GL_NONE; if (!workarounds_.disable_depth_texture && (extensions.Contains("GL_ARB_depth_texture") || extensions.Contains("GL_OES_depth_texture") || @@ -472,6 +565,7 @@ // This is because depth textures are filterable under linear mode in // ES2 + extension, but not in core ES3. enable_depth_texture = true; + depth_texture_format = GL_DEPTH_COMPONENT; feature_flags_.angle_depth_texture = extensions.Contains("GL_ANGLE_depth_texture"); } @@ -487,6 +581,7 @@ GL_DEPTH_COMPONENT); } + GLenum depth_stencil_texture_format = GL_NONE; if (extensions.Contains("GL_EXT_packed_depth_stencil") || extensions.Contains("GL_OES_packed_depth_stencil") || gl_version_info_->is_es3 || @@ -494,6 +589,11 @@ AddExtensionString("GL_OES_packed_depth_stencil"); feature_flags_.packed_depth24_stencil8 = true; if (enable_depth_texture) { + if (gl_version_info_->is_es3) { + depth_stencil_texture_format = GL_DEPTH24_STENCIL8; + } else { + depth_stencil_texture_format = GL_DEPTH_STENCIL; + } validators_.texture_internal_format.AddValue(GL_DEPTH_STENCIL); validators_.texture_format.AddValue(GL_DEPTH_STENCIL); validators_.pixel_type.AddValue(GL_UNSIGNED_INT_24_8); @@ -998,10 +1098,14 @@ extensions.Contains("GL_EXT_draw_buffers"); bool can_emulate_es2_draw_buffers_on_es3_nv = gl_version_info_->is_es3 && extensions.Contains("GL_NV_draw_buffers"); - bool have_es2_draw_buffers = !workarounds_.disable_ext_draw_buffers && - IsWebGL1OrES2Context() && - (have_es2_draw_buffers_vendor_agnostic || - can_emulate_es2_draw_buffers_on_es3_nv); + bool have_es2_draw_buffers = + !workarounds_.disable_ext_draw_buffers && + (have_es2_draw_buffers_vendor_agnostic || + can_emulate_es2_draw_buffers_on_es3_nv) && + (context_type_ == CONTEXT_TYPE_OPENGLES2 || + (context_type_ == CONTEXT_TYPE_WEBGL1 && + IsWebGLDrawBuffersSupported(depth_texture_format, + depth_stencil_texture_format))); if (have_es2_draw_buffers) { AddExtensionString("GL_EXT_draw_buffers"); feature_flags_.ext_draw_buffers = true;
diff --git a/ios/chrome/browser/find_in_page/BUILD.gn b/ios/chrome/browser/find_in_page/BUILD.gn index 2ea3d5a..e13b876a 100644 --- a/ios/chrome/browser/find_in_page/BUILD.gn +++ b/ios/chrome/browser/find_in_page/BUILD.gn
@@ -41,8 +41,27 @@ ] deps = [ ":find_in_page", + ":unit_tests_nonarc", "//base", "//ios/web", "//ios/web:test_support", + "//testing/gtest", + ] +} + +source_set("unit_tests_nonarc") { + testonly = true + sources = [ + "find_in_page_js_unittest.mm", + "js_findinpage_manager_unittest.mm", + ] + deps = [ + ":find_in_page", + "//base", + "//base/test:test_support", + "//ios/chrome/browser/web:test_support", + "//ios/web", + "//ios/web:test_support", + "//testing/gtest", ] }
diff --git a/ios/chrome/browser/web/find_in_page_js_unittest.mm b/ios/chrome/browser/find_in_page/find_in_page_js_unittest.mm similarity index 88% rename from ios/chrome/browser/web/find_in_page_js_unittest.mm rename to ios/chrome/browser/find_in_page/find_in_page_js_unittest.mm index 89ee821..38cd267 100644 --- a/ios/chrome/browser/web/find_in_page_js_unittest.mm +++ b/ios/chrome/browser/find_in_page/find_in_page_js_unittest.mm
@@ -4,16 +4,19 @@ #import <UIKit/UIKit.h> +#include "base/mac/foundation_util.h" #include "base/mac/scoped_nsobject.h" #include "base/strings/sys_string_conversions.h" -#import "ios/chrome/browser/find_in_page/find_in_page_controller.h" +#import "ios/chrome/browser/find_in_page/find_in_page_model.h" +#import "ios/chrome/browser/find_in_page/js_findinpage_manager.h" #import "ios/chrome/browser/web/chrome_web_test.h" +#import "ios/web/public/web_state/crw_web_view_proxy.h" +#import "ios/web/public/web_state/js/crw_js_injection_receiver.h" #import "ios/web/public/web_state/web_state.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest_mac.h" -#import "third_party/ocmock/OCMock/OCMock.h" -// Unit tests for the models/resources/find_in_page.js JavaScript file. +// Unit tests for the find_in_page.js JavaScript file. namespace { @@ -63,7 +66,11 @@ // Loads the given HTML, then loads the |findInPage| JavaScript. void LoadHtml(NSString* html) { ChromeWebTest::LoadHtml(html); - [findInPageController_ initFindInPage]; + + // Inject and initialize the find in page javascript. + [findInPageJsManager_ inject]; + CGRect frame = [web_state()->GetWebViewProxy() bounds]; + [findInPageJsManager_ setWidth:frame.size.width height:frame.size.height]; } // Runs the given JavaScript and asserts that the result matches the given @@ -94,15 +101,15 @@ void SetUp() override { ChromeWebTest::SetUp(); - mockDelegate_.reset([[OCMockObject - niceMockForProtocol:@protocol(FindInPageControllerDelegate)] retain]); - findInPageController_.reset([[FindInPageController alloc] - initWithWebState:web_state() - delegate:mockDelegate_]); + findInPageModel_.reset([[FindInPageModel alloc] init]); + findInPageJsManager_.reset([base::mac::ObjCCastStrict<JsFindinpageManager>( + [web_state()->GetJSInjectionReceiver() + instanceOfClass:[JsFindinpageManager class]]) retain]); + findInPageJsManager_.get().findInPageModel = findInPageModel_; } - base::scoped_nsobject<FindInPageController> findInPageController_; - base::scoped_nsobject<id> mockDelegate_; + base::scoped_nsobject<FindInPageModel> findInPageModel_; + base::scoped_nsobject<JsFindinpageManager> findInPageJsManager_; }; // Performs a search, then calls |incrementIndex| to loop through the
diff --git a/ios/chrome/browser/web/js_findinpage_manager_unittest.mm b/ios/chrome/browser/find_in_page/js_findinpage_manager_unittest.mm similarity index 99% rename from ios/chrome/browser/web/js_findinpage_manager_unittest.mm rename to ios/chrome/browser/find_in_page/js_findinpage_manager_unittest.mm index cd914d7e..ec13bec 100644 --- a/ios/chrome/browser/web/js_findinpage_manager_unittest.mm +++ b/ios/chrome/browser/find_in_page/js_findinpage_manager_unittest.mm
@@ -2,10 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#import "ios/chrome/browser/find_in_page/js_findinpage_manager.h" + #import <Foundation/Foundation.h> #import "base/test/ios/wait_util.h" -#import "ios/chrome/browser/find_in_page/js_findinpage_manager.h" #import "ios/chrome/browser/web/chrome_web_test.h" #import "ios/web/public/web_state/js/crw_js_injection_receiver.h" #import "ios/web/public/web_state/web_state.h"
diff --git a/ios/chrome/browser/web/BUILD.gn b/ios/chrome/browser/web/BUILD.gn index d1ce428..8514df5b 100644 --- a/ios/chrome/browser/web/BUILD.gn +++ b/ios/chrome/browser/web/BUILD.gn
@@ -225,8 +225,6 @@ "chrome_web_client_unittest.mm", "error_page_generator_unittest.mm", "external_app_launcher_unittest.mm", - "find_in_page_js_unittest.mm", - "js_findinpage_manager_unittest.mm", ] deps = [ ":test_support",
diff --git a/ios/clean/chrome/browser/ui/tab/tab_container_view_controller.mm b/ios/clean/chrome/browser/ui/tab/tab_container_view_controller.mm index 792a6ab..305eac0 100644 --- a/ios/clean/chrome/browser/ui/tab/tab_container_view_controller.mm +++ b/ios/clean/chrome/browser/ui/tab/tab_container_view_controller.mm
@@ -17,7 +17,7 @@ namespace { CGFloat kToolbarHeight = 44.0f; -CGFloat kTabStripHeight = 200.0f; +CGFloat kTabStripHeight = 90.0f; } @interface TabContainerViewController ()
diff --git a/ios/clean/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm b/ios/clean/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm index 6624402e..938f900 100644 --- a/ios/clean/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm +++ b/ios/clean/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm
@@ -94,6 +94,10 @@ return urlText; } +- (NSInteger)indexOfActiveTab { + return static_cast<NSInteger>(_activeWebStateIndex); +} + #pragma mark - TabCommands - (void)showTabAtIndexPath:(NSIndexPath*)indexPath {
diff --git a/ios/clean/chrome/browser/ui/tab_grid/tab_grid_tab_cell.h b/ios/clean/chrome/browser/ui/tab_grid/tab_grid_tab_cell.h index c42d8ed9..cc9dc5f 100644 --- a/ios/clean/chrome/browser/ui/tab_grid/tab_grid_tab_cell.h +++ b/ios/clean/chrome/browser/ui/tab_grid/tab_grid_tab_cell.h
@@ -11,12 +11,13 @@ #import <UIKit/UIKit.h> -// Placeholder cell implementation for use in the tab grid. -// A square cell with rounded corners and a label placed in the center. -@interface TabGridTabCell : UICollectionViewCell +#import "ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_cell.h" -// The label in the center of the tab cell. -@property(nonatomic, readonly) UILabel* label; +// Cell represents a tab for use in the tab grid. It has a title, favicon, +// screenshot image, and close button. Cell selection is represented by a border +// highlight in the tintColor. +// PLACEHOLDER: Create custom implemementation rather than subclassing. +@interface TabGridTabCell : TabSwitcherLocalSessionCell @end
diff --git a/ios/clean/chrome/browser/ui/tab_grid/tab_grid_tab_cell.mm b/ios/clean/chrome/browser/ui/tab_grid/tab_grid_tab_cell.mm index 8e02a69e..abf9f5cb 100644 --- a/ios/clean/chrome/browser/ui/tab_grid/tab_grid_tab_cell.mm +++ b/ios/clean/chrome/browser/ui/tab_grid/tab_grid_tab_cell.mm
@@ -13,38 +13,22 @@ #endif namespace { -const CGFloat kCornerRadius = 4.0; -const CGFloat kSelectedBorderWidth = 2.0; +const CGFloat kSelectedBorderCornerRadius = 8.0f; +const CGFloat kSelectedBorderWidth = 4.0f; } @implementation TabGridTabCell -@synthesize label = _label; - - (instancetype)initWithFrame:(CGRect)frame { if ((self = [super initWithFrame:frame])) { - self.contentView.layer.cornerRadius = kCornerRadius; - self.selectedBackgroundView.layer.cornerRadius = kCornerRadius; + self.selectedBackgroundView = [[UIView alloc] init]; + self.selectedBackgroundView.backgroundColor = [UIColor blackColor]; + self.selectedBackgroundView.layer.cornerRadius = + kSelectedBorderCornerRadius; self.selectedBackgroundView.layer.borderWidth = kSelectedBorderWidth; - self.selectedBackgroundView.layer.borderColor = [UIColor blueColor].CGColor; + self.selectedBackgroundView.layer.borderColor = self.tintColor.CGColor; self.selectedBackgroundView.transform = CGAffineTransformScale( - self.selectedBackgroundView.transform, 1.05, 1.05); - - _label = [[UILabel alloc] initWithFrame:CGRectZero]; - _label.translatesAutoresizingMaskIntoConstraints = NO; - _label.numberOfLines = 1; - _label.textAlignment = NSTextAlignmentCenter; - [self.contentView addSubview:_label]; - [NSLayoutConstraint activateConstraints:@[ - [_label.centerYAnchor - constraintEqualToAnchor:self.contentView.centerYAnchor], - [_label.leadingAnchor - constraintEqualToAnchor:self.contentView.layoutMarginsGuide - .leadingAnchor], - [_label.trailingAnchor - constraintEqualToAnchor:self.contentView.layoutMarginsGuide - .trailingAnchor], - ]]; + self.selectedBackgroundView.transform, 1.08, 1.08); } return self; }
diff --git a/ios/clean/chrome/browser/ui/tab_grid/tab_grid_view_controller.h b/ios/clean/chrome/browser/ui/tab_grid/tab_grid_view_controller.h index 09c59f0..2bc70ab 100644 --- a/ios/clean/chrome/browser/ui/tab_grid/tab_grid_view_controller.h +++ b/ios/clean/chrome/browser/ui/tab_grid/tab_grid_view_controller.h
@@ -29,6 +29,9 @@ // Title for the tab at |index| in the grid. - (NSString*)titleAtIndex:(NSInteger)index; +// Index for the active tab. +- (NSInteger)indexOfActiveTab; + @end // Controller for a scrolling view displaying square cells that represent
diff --git a/ios/clean/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm b/ios/clean/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm index 706910fe..9ee9700b 100644 --- a/ios/clean/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm +++ b/ios/clean/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
@@ -9,7 +9,6 @@ #import "ios/clean/chrome/browser/ui/tab_grid/tab_grid_view_controller.h" #include "base/mac/foundation_util.h" -#import "ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_cell.h" #import "ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_collection_view_layout.h" #import "ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_overlay_view.h" #import "ios/clean/chrome/browser/ui/actions/settings_actions.h" @@ -19,6 +18,7 @@ #import "ios/clean/chrome/browser/ui/commands/tab_grid_commands.h" #import "ios/clean/chrome/browser/ui/tab_grid/mdc_floating_button+cr_tab_grid.h" #import "ios/clean/chrome/browser/ui/tab_grid/tab_grid_collection_view_layout.h" +#import "ios/clean/chrome/browser/ui/tab_grid/tab_grid_tab_cell.h" #import "ios/clean/chrome/browser/ui/tab_grid/ui_stack_view+cr_tab_grid.h" #if !defined(__has_feature) || !__has_feature(objc_arc) @@ -73,8 +73,8 @@ self.grid = grid; self.grid.dataSource = self; self.grid.delegate = self; - [self.grid registerClass:[TabSwitcherLocalSessionCell class] - forCellWithReuseIdentifier:[TabSwitcherLocalSessionCell identifier]]; + [self.grid registerClass:[TabGridTabCell class] + forCellWithReuseIdentifier:[TabGridTabCell identifier]]; [NSLayoutConstraint activateConstraints:@[ [self.grid.topAnchor constraintEqualToAnchor:toolbar.bottomAnchor], @@ -85,7 +85,6 @@ } - (void)viewWillAppear:(BOOL)animated { - [self.grid reloadData]; self.floatingNewTabButton = [MDCFloatingButton cr_tabGridNewTabButton]; [self.floatingNewTabButton setFrame:[MDCFloatingButton @@ -119,19 +118,27 @@ - (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath*)indexPath { - TabSwitcherLocalSessionCell* cell = - base::mac::ObjCCastStrict<TabSwitcherLocalSessionCell>([collectionView - dequeueReusableCellWithReuseIdentifier: - [TabSwitcherLocalSessionCell identifier] + TabGridTabCell* cell = + base::mac::ObjCCastStrict<TabGridTabCell>([collectionView + dequeueReusableCellWithReuseIdentifier:[TabGridTabCell identifier] forIndexPath:indexPath]); cell.delegate = self; [cell setSessionType:TabSwitcherSessionType::REGULAR_SESSION]; [cell setAppearanceForTabTitle:[self.dataSource titleAtIndex:indexPath.item] favicon:nil cellSize:CGSizeZero]; + [cell setSelected:(indexPath.item == [self.dataSource indexOfActiveTab])]; return cell; } +#pragma mark - UICollectionViewDelegate methods + +- (BOOL)collectionView:(UICollectionView*)collectionView + shouldSelectItemAtIndexPath:(NSIndexPath*)indexPath { + // Prevent user selection of items. + return NO; +} + #pragma mark - ZoomTransitionDelegate methods - (CGRect)rectForZoomWithKey:(NSObject*)key inView:(UIView*)view { @@ -160,6 +167,13 @@ NSInteger index = [self.grid numberOfItemsInSection:0]; NSIndexPath* indexPath = [NSIndexPath indexPathForItem:index inSection:0]; auto updateBlock = ^{ + // Unselect current selected item. + NSInteger selectedIndex = [self.dataSource indexOfActiveTab]; + NSIndexPath* selectedIndexPath = + [NSIndexPath indexPathForItem:selectedIndex inSection:0]; + [self.grid reloadItemsAtIndexPaths:@[ selectedIndexPath ]]; + + // Create and show new tab. [self.tabCommandHandler createNewTabAtIndexPath:indexPath]; [self.tabCommandHandler showTabAtIndexPath:indexPath]; [self.grid insertItemsAtIndexPaths:@[ indexPath ]]; @@ -175,7 +189,15 @@ } - (void)cellPressed:(UICollectionViewCell*)cell { - [self.tabCommandHandler showTabAtIndexPath:[self.grid indexPathForCell:cell]]; + NSInteger selectedIndex = [self.dataSource indexOfActiveTab]; + NSIndexPath* newSelectedIndexPath = [self.grid indexPathForCell:cell]; + [self.tabCommandHandler showTabAtIndexPath:newSelectedIndexPath]; + if (newSelectedIndexPath.item != selectedIndex) { + NSIndexPath* selectedIndexPath = + [NSIndexPath indexPathForItem:selectedIndex inSection:0]; + [self.grid + reloadItemsAtIndexPaths:@[ selectedIndexPath, newSelectedIndexPath ]]; + } } - (void)deleteButtonPressedForCell:(UICollectionViewCell*)cell {
diff --git a/ios/showcase/tab_grid/sc_tab_grid_coordinator.mm b/ios/showcase/tab_grid/sc_tab_grid_coordinator.mm index b92f4a6..e47bd47b 100644 --- a/ios/showcase/tab_grid/sc_tab_grid_coordinator.mm +++ b/ios/showcase/tab_grid/sc_tab_grid_coordinator.mm
@@ -48,4 +48,8 @@ return [NSString stringWithFormat:@"Tab %" PRIdNS, index]; } +- (NSInteger)indexOfActiveTab { + return NSNotFound; +} + @end
diff --git a/ios/web/public/test/fakes/crw_test_web_state_observer.h b/ios/web/public/test/fakes/crw_test_web_state_observer.h index fb5fe73..5befde4 100644 --- a/ios/web/public/test/fakes/crw_test_web_state_observer.h +++ b/ios/web/public/test/fakes/crw_test_web_state_observer.h
@@ -35,11 +35,6 @@ WebState* web_state; }; -// Arguments passed to |webStateDidChangeURLHash:|. -struct TestChangeUrlHashInfo { - WebState* web_state; -}; - // Arguments passed to |webStateDidChangeHistoryState:|. struct TestChangeHistoryStateInfo { WebState* web_state; @@ -115,8 +110,6 @@ // Arguments passed to |webStateDidDismissInterstitial:|. @property(nonatomic, readonly) web::TestDismissInterstitialInfo* dismissInterstitialInfo; -// Arguments passed to |webStateDidChangeURLHash:|. -@property(nonatomic, readonly) web::TestChangeUrlHashInfo* changeUrlHashInfo; // Arguments passed to |webStateDidChangeHistoryState:|. @property(nonatomic, readonly) web::TestChangeHistoryStateInfo* changeHistoryStateInfo;
diff --git a/ios/web/public/test/fakes/crw_test_web_state_observer.mm b/ios/web/public/test/fakes/crw_test_web_state_observer.mm index 755753f..b7e785c 100644 --- a/ios/web/public/test/fakes/crw_test_web_state_observer.mm +++ b/ios/web/public/test/fakes/crw_test_web_state_observer.mm
@@ -24,8 +24,6 @@ std::unique_ptr<web::TestLoadPageInfo> _loadPageInfo; // Arguments passed to |webStateDidDismissInterstitial:|. std::unique_ptr<web::TestDismissInterstitialInfo> _dismissInterstitialInfo; - // Arguments passed to |webStateDidChangeURLHash:|. - std::unique_ptr<web::TestChangeUrlHashInfo> _changeUrlHashInfo; // Arguments passed to |webStateDidChangeHistoryState:|. std::unique_ptr<web::TestChangeHistoryStateInfo> _changeHistoryStateInfo; // Arguments passed to |webState:didChangeLoadingProgress:|. @@ -66,10 +64,6 @@ return _dismissInterstitialInfo.get(); } -- (web::TestChangeUrlHashInfo*)changeUrlHashInfo { - return _changeUrlHashInfo.get(); -} - - (web::TestChangeHistoryStateInfo*)changeHistoryStateInfo { return _changeHistoryStateInfo.get(); } @@ -136,11 +130,6 @@ _dismissInterstitialInfo->web_state = webState; } -- (void)webStateDidChangeURLHash:(web::WebState*)webState { - _changeUrlHashInfo = base::MakeUnique<web::TestChangeUrlHashInfo>(); - _changeUrlHashInfo->web_state = webState; -} - - (void)webStateDidChangeHistoryState:(web::WebState*)webState { _changeHistoryStateInfo = base::MakeUnique<web::TestChangeHistoryStateInfo>(); _changeHistoryStateInfo->web_state = webState;
diff --git a/ios/web/public/web_state/web_state_observer.h b/ios/web/public/web_state/web_state_observer.h index 62114a0..ff0a15de 100644 --- a/ios/web/public/web_state/web_state_observer.h +++ b/ios/web/public/web_state/web_state_observer.h
@@ -80,14 +80,6 @@ // Called when the interstitial is dismissed by the user. virtual void InterstitialDismissed() {} - // Called on URL hash change events. - // TODO(crbug.com/692331): Remove this method and use |DidFinishNavigation|. - virtual void UrlHashChanged() {} - - // Called on history state change events. - // TODO(crbug.com/692331): Remove this method and use |DidFinishNavigation|. - virtual void HistoryStateChanged() {} - // Notifies the observer that the page has made some progress loading. // |progress| is a value between 0.0 (nothing loaded) to 1.0 (page fully // loaded).
diff --git a/ios/web/public/web_state/web_state_observer_bridge.h b/ios/web/public/web_state/web_state_observer_bridge.h index 9ee95c4..93614ab 100644 --- a/ios/web/public/web_state/web_state_observer_bridge.h +++ b/ios/web/public/web_state/web_state_observer_bridge.h
@@ -35,12 +35,6 @@ // Invoked by WebStateObserverBridge::InterstitialDismissed. - (void)webStateDidDismissInterstitial:(web::WebState*)webState; -// Invoked by WebStateObserverBridge::UrlHashChanged. -- (void)webStateDidChangeURLHash:(web::WebState*)webState; - -// Invoked by WebStateObserverBridge::HistoryStateChanged. -- (void)webStateDidChangeHistoryState:(web::WebState*)webState; - // Invoked by WebStateObserverBridge::LoadProgressChanged. - (void)webState:(web::WebState*)webState didChangeLoadingProgress:(double)progress; @@ -100,8 +94,6 @@ void PageLoaded( web::PageLoadCompletionStatus load_completion_status) override; void InterstitialDismissed() override; - void UrlHashChanged() override; - void HistoryStateChanged() override; void LoadProgressChanged(double progress) override; void DocumentSubmitted(const std::string& form_name, bool user_initiated) override;
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm index 3564aab..a232f4c6 100644 --- a/ios/web/web_state/ui/crw_web_controller.mm +++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -2862,8 +2862,6 @@ item->SetIsCreatedFromHashChange(true); } - // Notify the observers. - _webStateImpl->OnUrlHashChanged(); return YES; } @@ -2962,8 +2960,6 @@ return; base::scoped_nsobject<CRWWebController> strongSelf([weakSelf retain]); [strongSelf optOutScrollsToTopForSubviews]; - // Notify the observers. - strongSelf.get()->_webStateImpl->OnHistoryStateChanged(); [strongSelf didFinishNavigation]; }]; return YES;
diff --git a/ios/web/web_state/web_state_impl.h b/ios/web/web_state/web_state_impl.h index 4b7754a..5d4f0e8 100644 --- a/ios/web/web_state/web_state_impl.h +++ b/ios/web/web_state/web_state_impl.h
@@ -82,12 +82,6 @@ // Called when a navigation is committed. void OnNavigationCommitted(const GURL& url); - // Notifies the observers that the URL hash of the current page changed. - void OnUrlHashChanged(); - - // Notifies the observers that the history state of the current page changed. - void OnHistoryStateChanged(); - // Notifies the observers that same page navigation did finish. void OnSamePageNavigation(const GURL& url);
diff --git a/ios/web/web_state/web_state_impl.mm b/ios/web/web_state/web_state_impl.mm index 2a3034f..824affd 100644 --- a/ios/web/web_state/web_state_impl.mm +++ b/ios/web/web_state/web_state_impl.mm
@@ -193,16 +193,6 @@ observer.DidFinishNavigation(context.get()); } -void WebStateImpl::OnUrlHashChanged() { - for (auto& observer : observers_) - observer.UrlHashChanged(); -} - -void WebStateImpl::OnHistoryStateChanged() { - for (auto& observer : observers_) - observer.HistoryStateChanged(); -} - void WebStateImpl::OnSamePageNavigation(const GURL& url) { std::unique_ptr<NavigationContext> context = NavigationContextImpl::CreateSamePageNavigationContext(this, url);
diff --git a/ios/web/web_state/web_state_impl_unittest.mm b/ios/web/web_state/web_state_impl_unittest.mm index 992132f..3aa7097 100644 --- a/ios/web/web_state/web_state_impl_unittest.mm +++ b/ios/web/web_state/web_state_impl_unittest.mm
@@ -127,7 +127,6 @@ navigation_item_changed_called_(false), navigation_item_committed_called_(false), page_loaded_called_with_success_(false), - url_hash_changed_called_(false), history_state_changed_called_(false), did_finish_navigation_called_(false), web_state_destroyed_called_(false) {} @@ -149,7 +148,6 @@ bool page_loaded_called_with_success() const { return page_loaded_called_with_success_; } - bool url_hash_changed_called() const { return url_hash_changed_called_; } bool history_state_changed_called() const { return history_state_changed_called_; } @@ -182,8 +180,6 @@ page_loaded_called_with_success_ = load_completion_status == PageLoadCompletionStatus::SUCCESS; } - void UrlHashChanged() override { url_hash_changed_called_ = true; } - void HistoryStateChanged() override { history_state_changed_called_ = true; } void WebStateDestroyed() override { EXPECT_TRUE(web_state()->IsBeingDestroyed()); web_state_destroyed_called_ = true; @@ -195,7 +191,6 @@ bool navigation_item_changed_called_; bool navigation_item_committed_called_; bool page_loaded_called_with_success_; - bool url_hash_changed_called_; bool history_state_changed_called_; bool did_finish_navigation_called_; bool web_state_destroyed_called_; @@ -392,16 +387,6 @@ web_state_->OnPageLoaded(GURL("http://test"), true); EXPECT_TRUE(observer->page_loaded_called_with_success()); - // Test that UrlHashChanged() is called. - EXPECT_FALSE(observer->url_hash_changed_called()); - web_state_->OnUrlHashChanged(); - EXPECT_TRUE(observer->url_hash_changed_called()); - - // Test that HistoryStateChanged() is called. - EXPECT_FALSE(observer->history_state_changed_called()); - web_state_->OnHistoryStateChanged(); - EXPECT_TRUE(observer->history_state_changed_called()); - // Test that DidFinishNavigation() is called for same page navigations. EXPECT_FALSE(observer->did_finish_navigation_called()); web_state_->OnSamePageNavigation(GURL("http://test"));
diff --git a/ios/web/web_state/web_state_observer_bridge.mm b/ios/web/web_state/web_state_observer_bridge.mm index 13fbde3..bf22c02c 100644 --- a/ios/web/web_state/web_state_observer_bridge.mm +++ b/ios/web/web_state/web_state_observer_bridge.mm
@@ -67,18 +67,6 @@ [observer_ webStateDidDismissInterstitial:web_state()]; } -void WebStateObserverBridge::UrlHashChanged() { - SEL selector = @selector(webStateDidChangeURLHash:); - if ([observer_ respondsToSelector:selector]) - [observer_ webStateDidChangeURLHash:web_state()]; -} - -void WebStateObserverBridge::HistoryStateChanged() { - SEL selector = @selector(webStateDidChangeHistoryState:); - if ([observer_ respondsToSelector:selector]) - [observer_ webStateDidChangeHistoryState:web_state()]; -} - void WebStateObserverBridge::LoadProgressChanged(double progress) { SEL selector = @selector(webState:didChangeLoadingProgress:); if ([observer_ respondsToSelector:selector])
diff --git a/ios/web/web_state/web_state_observer_bridge_unittest.mm b/ios/web/web_state/web_state_observer_bridge_unittest.mm index 4e20088..8d626ef 100644 --- a/ios/web/web_state/web_state_observer_bridge_unittest.mm +++ b/ios/web/web_state/web_state_observer_bridge_unittest.mm
@@ -90,24 +90,6 @@ EXPECT_EQ(&test_web_state_, [observer_ dismissInterstitialInfo]->web_state); } -// Tests |webState:webStateDidChangeURLHash:| forwarding. -TEST_F(WebStateObserverBridgeTest, UrlHashChanged) { - ASSERT_FALSE([observer_ changeUrlHashInfo]); - - bridge_->UrlHashChanged(); - ASSERT_TRUE([observer_ changeUrlHashInfo]); - EXPECT_EQ(&test_web_state_, [observer_ changeUrlHashInfo]->web_state); -} - -// Tests |webState:webStateDidChangeHistoryState:| forwarding. -TEST_F(WebStateObserverBridgeTest, HistoryStateChanged) { - ASSERT_FALSE([observer_ changeHistoryStateInfo]); - - bridge_->HistoryStateChanged(); - ASSERT_TRUE([observer_ changeHistoryStateInfo]); - EXPECT_EQ(&test_web_state_, [observer_ changeHistoryStateInfo]->web_state); -} - // Tests |webState:didChangeLoadingProgress:| forwarding. TEST_F(WebStateObserverBridgeTest, LoadProgressChanged) { ASSERT_FALSE([observer_ changeLoadingProgressInfo]);
diff --git a/services/resource_coordinator/BUILD.gn b/services/resource_coordinator/BUILD.gn index 9c5f07ef..27edac5 100644 --- a/services/resource_coordinator/BUILD.gn +++ b/services/resource_coordinator/BUILD.gn
@@ -10,6 +10,7 @@ public_deps = [ "//base", + "//mojo/public/cpp/bindings", "//services/resource_coordinator/public/cpp", "//services/resource_coordinator/public/interfaces", ] @@ -20,12 +21,15 @@ sources = [ "memory/coordinator/coordinator_impl_unittest.cc", + "public/cpp/memory/memory_dump_manager_delegate_impl_unittest.cc", ] deps = [ ":lib", "//base", "//mojo/public/cpp/bindings", + "//services/resource_coordinator/public/cpp", + "//services/resource_coordinator/public/interfaces", "//testing/gtest", ] }
diff --git a/services/resource_coordinator/memory/coordinator/coordinator_impl.cc b/services/resource_coordinator/memory/coordinator/coordinator_impl.cc index 5c133f8..68e6de84b 100644 --- a/services/resource_coordinator/memory/coordinator/coordinator_impl.cc +++ b/services/resource_coordinator/memory/coordinator/coordinator_impl.cc
@@ -4,14 +4,18 @@ #include "services/resource_coordinator/memory/coordinator/coordinator_impl.h" +#include "base/bind.h" #include "base/bind_helpers.h" #include "base/lazy_instance.h" #include "base/location.h" #include "base/logging.h" #include "base/memory/ref_counted.h" +#include "base/single_thread_task_runner.h" +#include "base/threading/platform_thread.h" #include "base/threading/thread_task_runner_handle.h" #include "base/trace_event/memory_dump_manager.h" #include "base/trace_event/memory_dump_request_args.h" +#include "services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl.h" #include "services/resource_coordinator/public/interfaces/memory/memory_instrumentation.mojom.h" namespace memory_instrumentation { @@ -24,20 +28,38 @@ } // namespace // static -CoordinatorImpl* CoordinatorImpl::GetInstance() { - return g_coordinator.Pointer(); +CoordinatorImpl* CoordinatorImpl::GetInstance( + scoped_refptr<base::SingleThreadTaskRunner> task_runner) { + CoordinatorImpl* out = g_coordinator.Pointer(); + out->Initialize(task_runner); + return out; } -// TODO(chiniforooshan): Initialize the global MemoryDumpManager instance here. -// This is how the global MemoryDumpManager gets a reference to the delegate on -// the service (read the browser) process for service process memory dumps. This -// can be done when the delegate implementation is landed. -CoordinatorImpl::CoordinatorImpl() : failed_memory_dump_count_(0) {} +CoordinatorImpl::CoordinatorImpl() + : failed_memory_dump_count_(0), task_runner_(nullptr) {} CoordinatorImpl::~CoordinatorImpl() {} +void CoordinatorImpl::Initialize( + scoped_refptr<base::SingleThreadTaskRunner> task_runner) { + DCHECK(!task_runner_ || task_runner_ == task_runner); + + if (!task_runner_) { + task_runner_ = task_runner; + MemoryDumpManagerDelegateImpl* delegate = + MemoryDumpManagerDelegateImpl::GetInstance(); + delegate->InitializeWithCoordinator(this, task_runner_); + } +} + +void CoordinatorImpl::InitializeForTest( + scoped_refptr<base::SingleThreadTaskRunner> task_runner) { + task_runner_ = task_runner; +} + void CoordinatorImpl::BindCoordinatorRequest( mojom::CoordinatorRequest request) { + DCHECK(task_runner_->RunsTasksOnCurrentThread()); bindings_.AddBinding(this, std::move(request)); } @@ -51,8 +73,7 @@ void CoordinatorImpl::RequestGlobalMemoryDump( const base::trace_event::MemoryDumpRequestArgs& args, const RequestGlobalMemoryDumpCallback& callback) { - DCHECK(thread_checker_.CalledOnValidThread()); - + DCHECK(task_runner_->RunsTasksOnCurrentThread()); bool another_dump_already_in_progress = !queued_memory_dump_requests_.empty(); // If this is a periodic memory dump request and there already is another @@ -87,8 +108,7 @@ void CoordinatorImpl::RegisterProcessLocalDumpManager( mojom::ProcessLocalDumpManagerPtr process_manager) { - DCHECK(thread_checker_.CalledOnValidThread()); - + DCHECK(task_runner_->RunsTasksOnCurrentThread()); process_manager.set_connection_error_handler( base::Bind(&CoordinatorImpl::UnregisterProcessLocalDumpManager, base::Unretained(this), process_manager.get())); @@ -101,7 +121,8 @@ void CoordinatorImpl::UnregisterProcessLocalDumpManager( mojom::ProcessLocalDumpManager* process_manager) { - DCHECK(process_managers_.erase(process_manager) == 1); + size_t num_deleted = process_managers_.erase(process_manager); + DCHECK(num_deleted == 1); // Check if we are waiting for an ack from this process-local manager. if (pending_process_managers_.find(process_manager) !=
diff --git a/services/resource_coordinator/memory/coordinator/coordinator_impl.h b/services/resource_coordinator/memory/coordinator/coordinator_impl.h index 80ce6ae..69f63cd 100644 --- a/services/resource_coordinator/memory/coordinator/coordinator_impl.h +++ b/services/resource_coordinator/memory/coordinator/coordinator_impl.h
@@ -11,7 +11,7 @@ #include "base/lazy_instance.h" #include "base/memory/ref_counted.h" -#include "base/threading/thread_checker.h" +#include "base/single_thread_task_runner.h" #include "base/trace_event/memory_dump_request_args.h" #include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/bindings/binding_set.h" @@ -22,13 +22,15 @@ class CoordinatorImpl : public Coordinator, public mojom::Coordinator { public: - static CoordinatorImpl* GetInstance(); + static CoordinatorImpl* GetInstance( + scoped_refptr<base::SingleThreadTaskRunner> task_runner); // Coordinator void BindCoordinatorRequest(mojom::CoordinatorRequest) override; private: - friend class CoordinatorImplTest; // For testing + friend std::default_delete<CoordinatorImpl>; // For testing + friend class CoordinatorImplTest; // For testing friend struct base::DefaultLazyInstanceTraits<CoordinatorImpl>; struct QueuedMemoryDumpRequest { @@ -42,6 +44,10 @@ CoordinatorImpl(); ~CoordinatorImpl() override; + void Initialize(scoped_refptr<base::SingleThreadTaskRunner> task_runner); + void InitializeForTest( + scoped_refptr<base::SingleThreadTaskRunner> task_runner); + // mojom::Coordinator void RegisterProcessLocalDumpManager( mojom::ProcessLocalDumpManagerPtr process_manager) override; @@ -78,7 +84,7 @@ int failed_memory_dump_count_; std::list<QueuedMemoryDumpRequest> queued_memory_dump_requests_; - base::ThreadChecker thread_checker_; + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; DISALLOW_COPY_AND_ASSIGN(CoordinatorImpl); };
diff --git a/services/resource_coordinator/memory/coordinator/coordinator_impl_unittest.cc b/services/resource_coordinator/memory/coordinator/coordinator_impl_unittest.cc index 1bc8254..4d63e98 100644 --- a/services/resource_coordinator/memory/coordinator/coordinator_impl_unittest.cc +++ b/services/resource_coordinator/memory/coordinator/coordinator_impl_unittest.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "services/resource_coordinator/memory/coordinator/coordinator_impl.h" +#include "base/bind.h" #include "base/bind_helpers.h" #include "base/callback_forward.h" #include "base/memory/ref_counted.h" @@ -20,15 +21,20 @@ public: CoordinatorImplTest() {} void SetUp() override { - dump_response_args_ = {static_cast<uint64_t>(-1), false}; + dump_response_args_ = {0U, false}; + coordinator_.reset(new CoordinatorImpl()); + coordinator_->InitializeForTest(base::ThreadTaskRunnerHandle::Get()); } + void TearDown() override { coordinator_.reset(); } + void RegisterProcessLocalDumpManager( mojom::ProcessLocalDumpManagerPtr process_manager) { base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(&CoordinatorImpl::RegisterProcessLocalDumpManager, - base::Unretained(&coordinator_), - base::Passed(&process_manager))); + FROM_HERE, + base::Bind(&CoordinatorImpl::RegisterProcessLocalDumpManager, + base::Unretained(coordinator_.get()), + base::Passed(&process_manager))); } void RequestGlobalMemoryDump(base::trace_event::MemoryDumpRequestArgs args, @@ -36,7 +42,7 @@ base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::Bind(&CoordinatorImpl::RequestGlobalMemoryDump, - base::Unretained(&coordinator_), args, + base::Unretained(coordinator_.get()), args, base::Bind(&CoordinatorImplTest::OnGlobalMemoryDumpResponse, base::Unretained(this), closure))); } @@ -57,11 +63,11 @@ DumpResponseArgs dump_response_args_; private: - CoordinatorImpl coordinator_; + std::unique_ptr<CoordinatorImpl> coordinator_; base::MessageLoop message_loop_; }; -class MockDumpManager : mojom::ProcessLocalDumpManager { +class MockDumpManager : public mojom::ProcessLocalDumpManager { public: MockDumpManager(CoordinatorImplTest* test_coordinator, int expected_calls) : binding_(this), expected_calls_(expected_calls) { @@ -93,7 +99,7 @@ base::trace_event::MemoryDumpLevelOfDetail::DETAILED}; RequestGlobalMemoryDump(args, run_loop.QuitClosure()); run_loop.Run(); - EXPECT_EQ(static_cast<uint64_t>(1234), dump_response_args_.dump_guid); + EXPECT_EQ(1234U, dump_response_args_.dump_guid); EXPECT_TRUE(dump_response_args_.success); } @@ -109,7 +115,7 @@ run_loop.Run(); - EXPECT_EQ(static_cast<uint64_t>(2345), dump_response_args_.dump_guid); + EXPECT_EQ(2345U, dump_response_args_.dump_guid); EXPECT_TRUE(dump_response_args_.success); } @@ -132,7 +138,7 @@ run_loop.Run(); - EXPECT_EQ(static_cast<uint64_t>(3456), dump_response_args_.dump_guid); + EXPECT_EQ(3456U, dump_response_args_.dump_guid); EXPECT_FALSE(dump_response_args_.success); } } // namespace memory_instrumentation
diff --git a/services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl.cc b/services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl.cc index 7072b67..1057794 100644 --- a/services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl.cc +++ b/services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl.cc
@@ -4,6 +4,11 @@ #include "services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl.h" +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/lazy_instance.h" +#include "base/single_thread_task_runner.h" +#include "base/synchronization/lock.h" #include "base/trace_event/memory_dump_request_args.h" #include "mojo/public/cpp/bindings/interface_request.h" #include "services/resource_coordinator/public/cpp/memory/coordinator.h" @@ -12,26 +17,68 @@ namespace memory_instrumentation { -MemoryDumpManagerDelegateImpl::MemoryDumpManagerDelegateImpl( - service_manager::InterfaceProvider* interface_provider) - : is_coordinator_(false), binding_(this) { - interface_provider->GetInterface(mojo::MakeRequest(&coordinator_)); - coordinator_->RegisterProcessLocalDumpManager( - binding_.CreateInterfacePtrAndBind()); +namespace { + +base::LazyInstance<MemoryDumpManagerDelegateImpl>::Leaky + g_memory_dump_manager_delegate = LAZY_INSTANCE_INITIALIZER; + +} // namespace + +// static +MemoryDumpManagerDelegateImpl* MemoryDumpManagerDelegateImpl::GetInstance() { + return g_memory_dump_manager_delegate.Pointer(); } -MemoryDumpManagerDelegateImpl::MemoryDumpManagerDelegateImpl( - Coordinator* coordinator) - : is_coordinator_(true), binding_(this) { - coordinator->BindCoordinatorRequest(mojo::MakeRequest(&coordinator_)); - coordinator_->RegisterProcessLocalDumpManager( - binding_.CreateInterfacePtrAndBind()); -} +MemoryDumpManagerDelegateImpl::MemoryDumpManagerDelegateImpl() + : initialized_(false), + binding_(this), + task_runner_(nullptr), + pending_memory_dump_guid_(0) {} MemoryDumpManagerDelegateImpl::~MemoryDumpManagerDelegateImpl() {} +void MemoryDumpManagerDelegateImpl::InitializeWithInterfaceProvider( + service_manager::InterfaceProvider* interface_provider) { + { + base::AutoLock lock(initialized_lock_); + DCHECK(!initialized_); + initialized_ = true; + } + + interface_provider->GetInterface(mojo::MakeRequest(&coordinator_)); + coordinator_->RegisterProcessLocalDumpManager( + binding_.CreateInterfacePtrAndBind()); + base::trace_event::MemoryDumpManager::GetInstance()->Initialize(this); +} + +void MemoryDumpManagerDelegateImpl::InitializeWithCoordinator( + Coordinator* coordinator, + scoped_refptr<base::SingleThreadTaskRunner> task_runner) { + DCHECK(task_runner); + if (!task_runner->RunsTasksOnCurrentThread()) { + task_runner->PostTask( + FROM_HERE, + base::Bind(&MemoryDumpManagerDelegateImpl::InitializeWithCoordinator, + base::Unretained(this), base::Unretained(coordinator), + task_runner)); + return; + } + + { + base::AutoLock lock(initialized_lock_); + DCHECK(!initialized_); + initialized_ = true; + } + + task_runner_ = task_runner; + coordinator->BindCoordinatorRequest(mojo::MakeRequest(&coordinator_)); + coordinator_->RegisterProcessLocalDumpManager( + binding_.CreateInterfacePtrAndBind()); + base::trace_event::MemoryDumpManager::GetInstance()->Initialize(this); +} + bool MemoryDumpManagerDelegateImpl::IsCoordinator() const { - return is_coordinator_; + return task_runner_ != nullptr; } void MemoryDumpManagerDelegateImpl::RequestProcessMemoryDump( @@ -43,7 +90,50 @@ void MemoryDumpManagerDelegateImpl::RequestGlobalMemoryDump( const base::trace_event::MemoryDumpRequestArgs& args, const base::trace_event::MemoryDumpCallback& callback) { - coordinator_->RequestGlobalMemoryDump(args, callback); + // Note: This condition is here to match the old behavior. If the delegate is + // in the browser process, we do not drop parallel requests in the delegate + // and so they will be queued by the Coordinator service (see + // CoordinatorImpl::RequestGlobalMemoryDump). If the delegate is in a child + // process, parallel requests will be cancelled. + // + // TODO(chiniforooshan): After transitioning to the mojo-based service is + // completed, we should enable queueing parallel global memory dump requests + // by delegates on all processes. + if (task_runner_) { + DCHECK(task_runner_); + task_runner_->PostTask( + FROM_HERE, + base::Bind(&mojom::Coordinator::RequestGlobalMemoryDump, + base::Unretained(coordinator_.get()), args, callback)); + return; + } + + { + base::AutoLock lock(pending_memory_dump_guid_lock_); + if (pending_memory_dump_guid_) { + callback.Run(args.dump_guid, false); + return; + } + pending_memory_dump_guid_ = args.dump_guid; + } + DCHECK(!task_runner_); + auto callback_proxy = + base::Bind(&MemoryDumpManagerDelegateImpl::MemoryDumpCallbackProxy, + base::Unretained(this), callback); + coordinator_->RequestGlobalMemoryDump(args, callback_proxy); +} + +void MemoryDumpManagerDelegateImpl::MemoryDumpCallbackProxy( + const base::trace_event::MemoryDumpCallback& callback, + uint64_t dump_guid, + bool success) { + DCHECK_NE(0U, pending_memory_dump_guid_); + pending_memory_dump_guid_ = 0; + callback.Run(dump_guid, success); +} + +void MemoryDumpManagerDelegateImpl::SetAsNonCoordinatorForTesting() { + task_runner_ = nullptr; } } // namespace memory_instrumentation
diff --git a/services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl.h b/services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl.h index 1176619..0986e22 100644 --- a/services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl.h +++ b/services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl.h
@@ -5,6 +5,9 @@ #ifndef SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_MEMORY_DUMP_MANAGER_DELEGATE_IMPL_H_ #define SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_MEMORY_DUMP_MANAGER_DELEGATE_IMPL_H_ +#include "base/lazy_instance.h" +#include "base/single_thread_task_runner.h" +#include "base/synchronization/lock.h" #include "base/trace_event/memory_dump_manager.h" #include "base/trace_event/memory_dump_request_args.h" #include "mojo/public/cpp/bindings/binding.h" @@ -18,30 +21,56 @@ : public base::trace_event::MemoryDumpManagerDelegate, public mojom::ProcessLocalDumpManager { public: + static MemoryDumpManagerDelegateImpl* GetInstance(); + // Use to bind to a remote coordinator. - MemoryDumpManagerDelegateImpl( + void InitializeWithInterfaceProvider( service_manager::InterfaceProvider* interface_provider); // Use to bind to a coordinator in the same process. - MemoryDumpManagerDelegateImpl(Coordinator* coordinator); - ~MemoryDumpManagerDelegateImpl() override; + void InitializeWithCoordinator( + Coordinator* coordinator, + scoped_refptr<base::SingleThreadTaskRunner> task_runner); - bool IsCoordinator() const; + bool IsCoordinator() const override; // The base::trace_event::MemoryDumpManager calls this. void RequestGlobalMemoryDump( const base::trace_event::MemoryDumpRequestArgs& args, const base::trace_event::MemoryDumpCallback& callback) override; + void SetAsNonCoordinatorForTesting(); + private: + friend std::default_delete<MemoryDumpManagerDelegateImpl>; // For testing + friend class MemoryDumpManagerDelegateImplTest; // For testing + friend struct base::DefaultLazyInstanceTraits<MemoryDumpManagerDelegateImpl>; + + MemoryDumpManagerDelegateImpl(); + ~MemoryDumpManagerDelegateImpl() override; + // The ProcessLocalDumpManager interface. The coordinator calls this. void RequestProcessMemoryDump( const base::trace_event::MemoryDumpRequestArgs& args, const RequestProcessMemoryDumpCallback& callback) override; - bool is_coordinator_; + // A proxy callback for updating |pending_memory_dump_guid_|. + void MemoryDumpCallbackProxy( + const base::trace_event::MemoryDumpCallback& callback, + uint64_t dump_guid, + bool success); + + bool initialized_; mojom::CoordinatorPtr coordinator_; mojo::Binding<mojom::ProcessLocalDumpManager> binding_; + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + uint64_t pending_memory_dump_guid_; + + // Prevents racy access to |pending_memory_dump_guid_|. + base::Lock pending_memory_dump_guid_lock_; + + // Prevents racy access to |initialized_|. + base::Lock initialized_lock_; DISALLOW_COPY_AND_ASSIGN(MemoryDumpManagerDelegateImpl); };
diff --git a/services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl_unittest.cc b/services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl_unittest.cc new file mode 100644 index 0000000..09a712b --- /dev/null +++ b/services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl_unittest.cc
@@ -0,0 +1,139 @@ +// 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 "services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl.h" +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "base/trace_event/memory_dump_manager.h" +#include "base/trace_event/memory_dump_request_args.h" +#include "base/trace_event/trace_config.h" +#include "base/trace_event/trace_log.h" +#include "mojo/public/cpp/bindings/binding_set.h" +#include "services/resource_coordinator/public/cpp/memory/coordinator.h" +#include "services/resource_coordinator/public/interfaces/memory/memory_instrumentation.mojom.h" +#include "testing/gtest/include/gtest/gtest.h" + +using base::trace_event::MemoryDumpLevelOfDetail; +using base::trace_event::MemoryDumpManager; +using base::trace_event::MemoryDumpType; + +namespace memory_instrumentation { + +class MockCoordinator : public Coordinator, public mojom::Coordinator { + public: + void BindCoordinatorRequest(mojom::CoordinatorRequest request) override { + bindings_.AddBinding(this, std::move(request)); + } + + void RegisterProcessLocalDumpManager( + mojom::ProcessLocalDumpManagerPtr process_manager) override {} + + void RequestGlobalMemoryDump( + const base::trace_event::MemoryDumpRequestArgs& args, + const RequestGlobalMemoryDumpCallback& callback) override { + callback.Run(args.dump_guid, true); + } + + private: + mojo::BindingSet<mojom::Coordinator> bindings_; +}; + +class MemoryDumpManagerDelegateImplTest : public testing::Test { + public: + void SetUp() override { + message_loop_.reset(new base::MessageLoop()); + coordinator_.reset(new MockCoordinator()); + delegate_.reset(new MemoryDumpManagerDelegateImpl()); + mdm_.reset(new MemoryDumpManager()); + MemoryDumpManager::SetInstanceForTesting(mdm_.get()); + + // This will initialize |MemoryDumpManager|, too. + delegate_->InitializeWithCoordinator(coordinator_.get(), + base::ThreadTaskRunnerHandle::Get()); + delegate_->SetAsNonCoordinatorForTesting(); + + // Enable tracing. + std::string category_filter = "-*,"; + category_filter += MemoryDumpManager::kTraceCategory; + base::trace_event::TraceConfig trace_config(category_filter, ""); + base::trace_event::TraceLog::GetInstance()->SetEnabled( + trace_config, base::trace_event::TraceLog::RECORDING_MODE); + + // Reset the counters. + expected_callback_calls_ = 0; + dump_requests_received_by_coordinator_ = 0; + quit_closure_.Reset(); + } + + void TearDown() override { + base::trace_event::TraceLog::GetInstance()->SetDisabled(); + MemoryDumpManager::SetInstanceForTesting(nullptr); + mdm_.reset(); + delegate_.reset(); + coordinator_.reset(); + message_loop_.reset(); + } + + void OnGlobalMemoryDumpDone(int more_requests, + uint64_t dump_guid, + bool success) { + EXPECT_GT(expected_callback_calls_, 0); + EXPECT_FALSE(quit_closure_.is_null()); + + dump_requests_received_by_coordinator_ += success ? 1 : 0; + expected_callback_calls_--; + if (expected_callback_calls_ == 0) + quit_closure_.Run(); + + if (more_requests > 0) + SequentiallyRequestGlobalDumps(more_requests); + } + + void SequentiallyRequestGlobalDumps(int num_requests) { + MemoryDumpManager::GetInstance()->RequestGlobalDump( + MemoryDumpType::EXPLICITLY_TRIGGERED, MemoryDumpLevelOfDetail::LIGHT, + base::Bind(&MemoryDumpManagerDelegateImplTest::OnGlobalMemoryDumpDone, + base::Unretained(this), num_requests - 1)); + } + + int expected_callback_calls_; + int dump_requests_received_by_coordinator_; + base::Closure quit_closure_; + + private: + std::unique_ptr<base::MessageLoop> message_loop_; + std::unique_ptr<MockCoordinator> coordinator_; + std::unique_ptr<MemoryDumpManagerDelegateImpl> delegate_; + std::unique_ptr<MemoryDumpManager> mdm_; +}; + +// Makes several global dump requests each after receiving the ACK for the +// previous one. There should be no throttling and all requests should be +// forwarded to the coordinator. +TEST_F(MemoryDumpManagerDelegateImplTest, NonOverlappingMemoryDumpRequests) { + base::RunLoop run_loop; + expected_callback_calls_ = 3; + quit_closure_ = run_loop.QuitClosure(); + SequentiallyRequestGlobalDumps(3); + run_loop.Run(); + EXPECT_EQ(3, dump_requests_received_by_coordinator_); +} + +// Makes several global dump requests without waiting for previous requests to +// finish. Only the first request should make it to the coordinator. The rest +// should be cancelled. +TEST_F(MemoryDumpManagerDelegateImplTest, OverlappingMemoryDumpRequests) { + base::RunLoop run_loop; + expected_callback_calls_ = 3; + quit_closure_ = run_loop.QuitClosure(); + SequentiallyRequestGlobalDumps(1); + SequentiallyRequestGlobalDumps(1); + SequentiallyRequestGlobalDumps(1); + run_loop.Run(); + EXPECT_EQ(1, dump_requests_received_by_coordinator_); +} + +} // namespace memory_instrumentation
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index 0955f5ce..49eb5d9a 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -840,21 +840,22 @@ crbug.com/567965 [ Debug ] external/wpt/user-timing/test_user_timing_mark.html [ Skip ] crbug.com/518993 external/wpt/user-timing/test_user_timing_measure_navigation_timing.html [ Skip ] -crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/flexbox/scrollbars-changed.html [ NeedsManualRebaseline ] -crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/css-grid-layout/grid-element-change-columns-repaint.html [ NeedsManualRebaseline ] -crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/selection/selection-in-non-composited-scrolling-container.html [ NeedsManualRebaseline ] -crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/compositing/iframe-inside-squashed-layer.html [ NeedsManualRebaseline ] -crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/table/border-collapse-change-collapse-to-separate.html [ NeedsManualRebaseline ] -crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/flexbox/repaint.html [ NeedsManualRebaseline ] -crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/table/resize-table-row-repaint.html [ NeedsManualRebaseline ] -crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/css-grid-layout/grid-element-change-rows-repaint.html [ NeedsManualRebaseline ] -crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/table/resize-table-repaint-percent-size-cell.html [ NeedsManualRebaseline ] -crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/table/border-collapse-change-separate-to-collapse.html [ NeedsManualRebaseline ] -crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/compositing/should-not-repaint-composited-descendants.html [ NeedsManualRebaseline ] -crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/forms/button-reset-focus-by-mouse-then-keydown.html [ NeedsManualRebaseline ] -crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/forms/range-focus-by-mouse-then-keydown.html [ NeedsManualRebaseline ] -crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/forms/submit-focus-by-mouse-then-keydown.html [ NeedsManualRebaseline ] -crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/table/resize-table-repaint-vertical-align-cell.html [ NeedsManualRebaseline ] +crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/flexbox/scrollbars-changed.html [ NeedsRebaseline ] +crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/css-grid-layout/grid-element-change-columns-repaint.html [ NeedsRebaseline ] +crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/selection/selection-in-non-composited-scrolling-container.html [ NeedsRebaseline ] +crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/compositing/iframe-inside-squashed-layer.html [ NeedsRebaseline ] +crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/table/border-collapse-change-collapse-to-separate.html [ NeedsRebaseline ] +crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/flexbox/repaint.html [ NeedsRebaseline ] +crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/table/resize-table-row-repaint.html [ NeedsRebaseline ] +crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/css-grid-layout/grid-element-change-rows-repaint.html [ NeedsRebaseline ] +crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/table/resize-table-repaint-percent-size-cell.html [ NeedsRebaseline ] +crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/table/border-collapse-change-separate-to-collapse.html [ NeedsRebaseline ] +crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/compositing/should-not-repaint-composited-descendants.html [ NeedsRebaseline ] +crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/forms/button-reset-focus-by-mouse-then-keydown.html [ NeedsRebaseline ] +crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/forms/range-focus-by-mouse-then-keydown.html [ NeedsRebaseline ] +crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/forms/submit-focus-by-mouse-then-keydown.html [ NeedsRebaseline ] +crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/table/resize-table-repaint-vertical-align-cell.html [ NeedsRebaseline ] +crbug.com/696398 virtual/disable-spinvalidation/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem.html [ NeedsRebaseline ] crbug.com/636053 [ Mac Win ] printing/thead-repeats-at-top-of-each-page-multiple-tables.html [ NeedsManualRebaseline ] crbug.com/636053 [ Mac Win ] virtual/threaded/printing/thead-repeats-at-top-of-each-page-multiple-tables.html [ NeedsManualRebaseline ] @@ -2562,7 +2563,6 @@ crbug.com/695352 [ Mac ] virtual/threaded/compositing/visibility/overlays-persist-on-navigation.html [ Pass Crash ] # Sheriff failures 2017-02-27 -crbug.com/696398 [ Win7 ] virtual/disable-spinvalidation/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem.html [ Failure ] crbug.com/696407 [ Linux ] external/wpt/html/browsers/history/the-location-interface/location-protocol-setter-with-colon.sub.html [ Failure Pass ] crbug.com/694338 [ Mac10.9 ] fast/forms/calendar-picker/calendar-picker-appearance-zoom125.html [ Failure ] crbug.com/694338 [ Mac10.9 ] fast/forms/calendar-picker/calendar-picker-appearance-zoom200.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/change-context-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/change-context-expected.txt deleted file mode 100644 index d8f83e3..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/change-context-expected.txt +++ /dev/null
@@ -1,2 +0,0 @@ -This test ensures that changing the context does not crash. -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/change-context.html b/third_party/WebKit/LayoutTests/fast/canvas/change-context.html index 9e24759..675742dc 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/change-context.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/change-context.html
@@ -1,19 +1,22 @@ -This test ensures that changing the context does not crash. +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> <canvas id="canvas"></canvas><br /> + <script> -if (window.testRunner) - testRunner.dumpAsText(); +test(function(t) { -var canvas = document.getElementById("canvas"); -var ctx1 = canvas.getContext("2d"); -var ctx2 = canvas.getContext(""); -ctx1.save(); - -canvas.parentNode.removeChild(canvas); - -if (window.GCController) - GCController.collect(); + var canvas = document.getElementById("canvas"); + var ctx1 = canvas.getContext("2d"); + var ctx2 = canvas.getContext(""); + ctx1.save(); -ctx1.save(); - + canvas.parentNode.removeChild(canvas); + + if (window.GCController) + GCController.collect(); + + ctx1.save(); + +}, 'This test ensures that changing the context does not crash.'); </script> +</body>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-expected.txt deleted file mode 100644 index d7fa08a7..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-expected.txt +++ /dev/null
@@ -1,9 +0,0 @@ -PASS canvas.drawFocusIfNeeded(null); threw exception TypeError: Failed to execute 'drawFocusIfNeeded' on 'CanvasRenderingContext2D': parameter 1 is not of type 'Element'.. -PASS canvas.drawFocusIfNeeded(); threw exception TypeError: Failed to execute 'drawFocusIfNeeded' on 'CanvasRenderingContext2D': 1 argument required, but only 0 present.. -PASS canvas.drawFocusIfNeeded(null); threw exception TypeError: Failed to execute 'drawFocusIfNeeded' on 'CanvasRenderingContext2D': parameter 1 is not of type 'Element'.. -PASS data[0] != 0 || data[1] != 0 || data[2] != 0 is true -PASS data[0] == 0 && data[1] == 0 && data[2] == 0 is true -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-invisible-crash-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-invisible-crash-expected.txt deleted file mode 100644 index 909dda9..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-invisible-crash-expected.txt +++ /dev/null
@@ -1 +0,0 @@ -This test passes by not crashing.
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-invisible-crash.html b/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-invisible-crash.html index 314268f..87f2362 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-invisible-crash.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-invisible-crash.html
@@ -1,17 +1,20 @@ -<!DOCTYPE HTML> -<p>This test passes by not crashing.</p> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> + <canvas id="canvas"> <button id="button"></button> </canvas> -<script> -if (window.testRunner) - testRunner.dumpAsText(); -var button = document.getElementById("button"); -button.focus(); -var canvas = document.getElementById("canvas") -var ctx = canvas.getContext("2d"); -ctx.rect(0, 0, 10, 10); -canvas.style.display = "none"; -ctx.drawFocusIfNeeded(button); -</script> +<script> +test(function(t) { + + var button = document.getElementById("button"); + button.focus(); + var canvas = document.getElementById("canvas") + var ctx = canvas.getContext("2d"); + ctx.rect(0, 0, 10, 10); + canvas.style.display = "none"; + ctx.drawFocusIfNeeded(button); + +}, 'Test that drawFocusIfNeeded does not crash.'); +</script> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-on-event-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-on-event-expected.txt deleted file mode 100644 index 2a5eb81d..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-on-event-expected.txt +++ /dev/null
@@ -1,6 +0,0 @@ -PASS data[0] != 0 || data[1] != 0 || data[2] != 0 is true -PASS data[0] == 0 && data[1] == 0 && data[2] == 0 is true -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-on-event.html b/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-on-event.html index aef285b0..6fcf15d 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-on-event.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-on-event.html
@@ -1,17 +1,10 @@ -<!DOCTYPE HTML> -<head> -<title>Canvas test: drawFocusIfNeeded</title> -<script src="../../resources/js-test.js"></script> -</head> -<body style="padding: 0; margin: 0"> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> <canvas id="canvas" class="output" width="300" height="350"> <button id="button1"></button> <button id="button2"></button> </canvas> <script> -if (window.testRunner) - testRunner.dumpAsText(); - var canvas = document.getElementById("canvas").getContext("2d"); document.getElementById("button1").addEventListener('focus', function() { @@ -28,17 +21,21 @@ canvas.drawFocusIfNeeded(document.getElementById("button2")); }); -document.getElementById("button1").focus(); +test(function(t) { -// The top rect's focus ring is tied to button1, which is focused. -// It should have an outline in some color other than the background color. -var imageData = canvas.getImageData(49, 50, 1, 1); -var data = imageData.data; -shouldBe("data[0] != 0 || data[1] != 0 || data[2] != 0", "true"); - -// The bottom rect"s focus ring is tied to button2, which is not focused. -imageData = canvas.getImageData(49, 200, 1, 1); -data = imageData.data; -shouldBe("data[0] == 0 && data[1] == 0 && data[2] == 0", "true"); + document.getElementById("button1").focus(); + + // The top rect's focus ring is tied to button1, which is focused. + // It should have an outline in some color other than the background color. + var imageData = canvas.getImageData(49, 50, 1, 1); + var data = imageData.data; + assert_true(data[0] != 0 || data[1] != 0 || data[2] != 0); + + // The bottom rect"s focus ring is tied to button2, which is not focused. + imageData = canvas.getImageData(49, 200, 1, 1); + data = imageData.data; + assert_true(data[0] == 0 && data[1] == 0 && data[2] == 0); + +}, 'Test that drawFocusIfNeeded does not crash on event.'); </script> </body>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-scrolls-horiz-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-scrolls-horiz-expected.txt deleted file mode 100644 index 3f1cc39..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-scrolls-horiz-expected.txt +++ /dev/null
@@ -1,11 +0,0 @@ -PASS window.pageXOffset is 0 -PASS window.pageXOffset is >= minXOffset -PASS maxXOffset is >= window.pageXOffset -PASS window.pageXOffset is >= minXOffset -PASS maxXOffset is >= window.pageXOffset -PASS window.pageXOffset is >= minXOffset -PASS maxXOffset is >= window.pageXOffset -PASS successfullyParsed is true - -TEST COMPLETE -1000-pixel box
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-scrolls-horiz.html b/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-scrolls-horiz.html index 46a66d9..3e8ffe0 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-scrolls-horiz.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-scrolls-horiz.html
@@ -1,9 +1,6 @@ -<!DOCTYPE HTML> -<head> -<title>Canvas test: drawFocusIfNeeded scrolls</title> -<script src="../../resources/js-test.js"></script> -</head> -<body style="padding: 0; margin: 0"> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> + <div style="width: 6500px;"> <div style="float: left; border: 1px solid #000; width: 1000px; height: 300px"> 1000-pixel box @@ -13,49 +10,50 @@ <button id="right_button"></button> </canvas> </div> + <script> -if (window.testRunner) - testRunner.dumpAsText(); +test(function(t) { -var canvas = document.getElementById("canvas"); -var context = canvas.getContext("2d"); + var canvas = document.getElementById("canvas"); + var context = canvas.getContext("2d"); + + var LEFT_BUTTON_X_POS = 50; + var RIGHT_BUTTON_X_POS = 4750; -var LEFT_BUTTON_X_POS = 50; -var RIGHT_BUTTON_X_POS = 4750; + function draw() { + context.beginPath(); + context.rect(LEFT_BUTTON_X_POS, 50, 200, 100); + context.fillStyle = "#ccf"; + context.fill(); + context.drawFocusIfNeeded(document.getElementById("left_button")); + + context.beginPath(); + context.rect(RIGHT_BUTTON_X_POS, 50, 200, 100); + context.fillStyle = "#fcc"; + context.fill(); + context.drawFocusIfNeeded(document.getElementById("right_button")); + } -function draw() { - context.beginPath(); - context.rect(LEFT_BUTTON_X_POS, 50, 200, 100); - context.fillStyle = "#ccf"; - context.fill(); - context.drawFocusIfNeeded(document.getElementById("left_button")); + document.getElementById("right_button").focus(); + window.scrollTo(0, 0); + assert_true(window.pageXOffset == 0); + draw(); - context.beginPath(); - context.rect(RIGHT_BUTTON_X_POS, 50, 200, 100); - context.fillStyle = "#fcc"; - context.fill(); - context.drawFocusIfNeeded(document.getElementById("right_button")); -} + var minXOffset = RIGHT_BUTTON_X_POS + canvas.offsetLeft - window.innerWidth; + var maxXOffset = RIGHT_BUTTON_X_POS + canvas.offsetLeft; + assert_true(window.pageXOffset >= minXOffset); + assert_true(maxXOffset >= window.pageXOffset); -document.getElementById("right_button").focus(); -window.scrollTo(0, 0); -shouldBe("window.pageXOffset", "0"); -draw(); + document.getElementById("left_button").focus(); + assert_true(window.pageXOffset >= minXOffset); + assert_true(maxXOffset >= window.pageXOffset); -var minXOffset = RIGHT_BUTTON_X_POS + canvas.offsetLeft - window.innerWidth; -var maxXOffset = RIGHT_BUTTON_X_POS + canvas.offsetLeft; -shouldBeGreaterThanOrEqual("window.pageXOffset", "minXOffset"); -shouldBeGreaterThanOrEqual("maxXOffset", "window.pageXOffset"); + draw(); + minXOffset = LEFT_BUTTON_X_POS + canvas.offsetLeft - window.innerWidth; + maxXOffset = LEFT_BUTTON_X_POS + canvas.offsetLeft; + assert_true(window.pageXOffset >= minXOffset); + assert_true(maxXOffset >= window.pageXOffset); -document.getElementById("left_button").focus(); -shouldBeGreaterThanOrEqual("window.pageXOffset", "minXOffset"); -shouldBeGreaterThanOrEqual("maxXOffset", "window.pageXOffset"); - -draw(); -minXOffset = LEFT_BUTTON_X_POS + canvas.offsetLeft - window.innerWidth; -maxXOffset = LEFT_BUTTON_X_POS + canvas.offsetLeft; -shouldBeGreaterThanOrEqual("window.pageXOffset", "minXOffset"); -shouldBeGreaterThanOrEqual("maxXOffset", "window.pageXOffset"); - +}, 'Canvas test: drawFocusIfNeeded scrolls'); </script> </body>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-with-path2d-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-with-path2d-expected.txt deleted file mode 100644 index dd990cf..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-with-path2d-expected.txt +++ /dev/null
@@ -1,13 +0,0 @@ -PASS canvas.drawFocusIfNeeded(undefined); threw exception TypeError: Failed to execute 'drawFocusIfNeeded' on 'CanvasRenderingContext2D': parameter 1 is not of type 'Element'.. -PASS canvas.drawFocusIfNeeded(undefined, undefined); threw exception TypeError: Failed to execute 'drawFocusIfNeeded' on 'CanvasRenderingContext2D': parameter 1 is not of type 'Path2D'.. -PASS canvas.drawFocusIfNeeded(null); threw exception TypeError: Failed to execute 'drawFocusIfNeeded' on 'CanvasRenderingContext2D': parameter 1 is not of type 'Element'.. -PASS canvas.drawFocusIfNeeded(null, null); threw exception TypeError: Failed to execute 'drawFocusIfNeeded' on 'CanvasRenderingContext2D': parameter 1 is not of type 'Path2D'.. -PASS canvas.drawFocusIfNeeded(); threw exception TypeError: Failed to execute 'drawFocusIfNeeded' on 'CanvasRenderingContext2D': 1 argument required, but only 0 present.. -PASS canvas.drawFocusIfNeeded(null); threw exception TypeError: Failed to execute 'drawFocusIfNeeded' on 'CanvasRenderingContext2D': parameter 1 is not of type 'Element'.. -PASS canvas.drawFocusIfNeeded(null, null); threw exception TypeError: Failed to execute 'drawFocusIfNeeded' on 'CanvasRenderingContext2D': parameter 1 is not of type 'Path2D'.. -PASS data[0] != 0 || data[1] != 0 || data[2] != 0 is true -PASS data[0] == 0 && data[1] == 0 && data[2] == 0 is true -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-with-path2d.html b/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-with-path2d.html index 24731b8..479a692 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-with-path2d.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-with-path2d.html
@@ -1,51 +1,50 @@ -<!DOCTYPE HTML> -<head> -<title>Canvas test: drawFocusIfNeeded with Path2D</title> -<script src="../../resources/js-test.js"></script> -</head> -<body style="padding: 0; margin: 0"> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> + <canvas id="canvas" class="output" width="300" height="350"> <button id="button1"></button> <button id="button2"></button> </canvas> + <script> -if (window.testRunner) - testRunner.dumpAsText(); +test(function(t) { -document.getElementById("button1").focus(); - -var canvas = document.getElementById("canvas").getContext("2d"); - -shouldThrow('canvas.drawFocusIfNeeded(undefined);'); -shouldThrow('canvas.drawFocusIfNeeded(undefined, undefined);'); -shouldThrow('canvas.drawFocusIfNeeded(null);'); -shouldThrow('canvas.drawFocusIfNeeded(null, null);'); -shouldThrow('canvas.drawFocusIfNeeded();'); - -var path = new Path2D(); -path.rect(50, 50, 200, 100); -canvas.fillStyle = "#ccf"; -canvas.fill(path); -// re-test null case after having defined a path (regression test for crbug.com/353248) -shouldThrow('canvas.drawFocusIfNeeded(null);'); -shouldThrow('canvas.drawFocusIfNeeded(null, null);'); -canvas.drawFocusIfNeeded(path, document.getElementById("button1")); - -path = new Path2D(); -path.rect(50, 200, 200, 100); -canvas.fillStyle = "#cfc"; -canvas.fill(path); -canvas.drawFocusIfNeeded(path, document.getElementById("button2")); - -// The top rect"s focus ring is tied to button1, which is focused. -// It should have an outline in some color other than the background color. -var imageData = canvas.getImageData(49, 50, 1, 1); -var data = imageData.data; -shouldBe("data[0] != 0 || data[1] != 0 || data[2] != 0", "true"); - -// The bottom rect"s focus ring is tied to button2, which is not focused. -imageData = canvas.getImageData(49, 200, 1, 1); -data = imageData.data; -shouldBe("data[0] == 0 && data[1] == 0 && data[2] == 0", "true"); + document.getElementById("button1").focus(); + + var canvas = document.getElementById("canvas").getContext("2d"); + + assert_throws(null, function(){canvas.drawFocusIfNeeded(undefined);}); + assert_throws(null, function(){canvas.drawFocusIfNeeded(undefined, undefined);}); + assert_throws(null, function(){canvas.drawFocusIfNeeded(null);}); + assert_throws(null, function(){canvas.drawFocusIfNeeded(null, null);}); + assert_throws(null, function(){canvas.drawFocusIfNeeded();}); + + var path = new Path2D(); + path.rect(50, 50, 200, 100); + canvas.fillStyle = "#ccf"; + canvas.fill(path); + // re-test null case after having defined a path (regression test for crbug.com/353248) + assert_throws(null, function(){canvas.drawFocusIfNeeded(null);}); + assert_throws(null, function(){canvas.drawFocusIfNeeded(null, null);}); + canvas.drawFocusIfNeeded(path, document.getElementById("button1")); + + path = new Path2D(); + path.rect(50, 200, 200, 100); + canvas.fillStyle = "#cfc"; + canvas.fill(path); + canvas.drawFocusIfNeeded(path, document.getElementById("button2")); + + // The top rect"s focus ring is tied to button1, which is focused. + // It should have an outline in some color other than the background color. + var imageData = canvas.getImageData(49, 50, 1, 1); + var data = imageData.data; + assert_true(data[0] != 0 || data[1] != 0 || data[2] != 0); + + // The bottom rect"s focus ring is tied to button2, which is not focused. + imageData = canvas.getImageData(49, 200, 1, 1); + data = imageData.data; + assert_true(data[0] == 0 && data[1] == 0 && data[2] == 0); + +}, 'Canvas test: drawFocusIfNeeded with Path2D'); </script> </body>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed.html b/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed.html index 8bfb2ea3..394f4b9 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed.html
@@ -1,47 +1,47 @@ <!DOCTYPE HTML> <head> -<title>Canvas test: drawFocusIfNeeded</title> -<script src="../../resources/js-test.js"></script> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> </head> -<body style="padding: 0; margin: 0"> <canvas id="canvas" class="output" width="300" height="350"> <button id="button1"></button> <button id="button2"></button> </canvas> <script> -if (window.testRunner) - testRunner.dumpAsText(); +test(function(t) { -document.getElementById("button1").focus(); - -var canvas = document.getElementById("canvas").getContext("2d"); - -shouldThrow('canvas.drawFocusIfNeeded(null);'); -shouldThrow('canvas.drawFocusIfNeeded();'); - -canvas.beginPath(); -canvas.rect(50, 50, 200, 100); -canvas.fillStyle = "#ccf"; -canvas.fill(); -// re-test null case after having defined a path (regression test for crbug.com/353248) -shouldThrow('canvas.drawFocusIfNeeded(null);'); -canvas.drawFocusIfNeeded(document.getElementById("button1")); - -canvas.beginPath(); -canvas.rect(50, 200, 200, 100); -canvas.fillStyle = "#cfc"; -canvas.fill(); -canvas.drawFocusIfNeeded(document.getElementById("button2")); - -// The top rect"s focus ring is tied to button1, which is focused. -// It should have an outline in some color other than the background color. -var imageData = canvas.getImageData(49, 50, 1, 1); -var data = imageData.data; -shouldBe("data[0] != 0 || data[1] != 0 || data[2] != 0", "true"); - -// The bottom rect"s focus ring is tied to button2, which is not focused. -imageData = canvas.getImageData(49, 200, 1, 1); -data = imageData.data; -shouldBe("data[0] == 0 && data[1] == 0 && data[2] == 0", "true"); + document.getElementById("button1").focus(); + + var canvas = document.getElementById("canvas").getContext("2d"); + + assert_throws(null, function(){canvas.drawFocusIfNeeded(null);}); + assert_throws(null, function(){canvas.drawFocusIfNeeded();}); + + canvas.beginPath(); + canvas.rect(50, 50, 200, 100); + canvas.fillStyle = "#ccf"; + canvas.fill(); + // re-test null case after having defined a path (regression test for crbug.com/353248) + assert_throws(null, function(){canvas.drawFocusIfNeeded(null);}); + canvas.drawFocusIfNeeded(document.getElementById("button1")); + + canvas.beginPath(); + canvas.rect(50, 200, 200, 100); + canvas.fillStyle = "#cfc"; + canvas.fill(); + canvas.drawFocusIfNeeded(document.getElementById("button2")); + + // The top rect's focus ring is tied to button1, which is focused. + // It should have an outline in some color other than the background color. + var imageData = canvas.getImageData(49, 50, 1, 1); + var data = imageData.data; + assert_true(data[0] != 0 || data[1] != 0 || data[2] != 0); + + // The bottom rect"s focus ring is tied to button2, which is not focused. + imageData = canvas.getImageData(49, 200, 1, 1); + data = imageData.data; + assert_true(data[0] == 0 && data[1] == 0 && data[2] == 0); + +}, 'Canvas test: drawFocusIfNeeded'); </script> </body>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-bad-canvas-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-bad-canvas-expected.txt deleted file mode 100644 index feb6b5c..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-bad-canvas-expected.txt +++ /dev/null
@@ -1,9 +0,0 @@ -This test checks behavior of drawImage on a canvas that failed to allocate its backing store. This test passes by not crashing. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-bad-canvas.html b/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-bad-canvas.html index 9b30429..d191d4e0 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-bad-canvas.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-bad-canvas.html
@@ -1,10 +1,9 @@ -<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> -<html> -<head> -<script src="../../resources/js-test.js"></script> -</head> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> + <script> - description("This test checks behavior of drawImage on a canvas that failed to allocate its backing store. This test passes by not crashing."); +test(function(){ + var canvas1 = document.createElement("canvas"); var ctx1 = canvas1.getContext('2d'); var canvas2 = document.createElement("canvas"); @@ -13,6 +12,6 @@ canvas2.height = 1000000; var ctx2 = canvas2.getContext('2d'); ctx2.drawImage(canvas1, 0, 0); + +}, "This test checks behavior of drawImage on a canvas that failed to allocate its backing store. This test passes by not crashing."); </script> -</body> -</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-broken-image-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-broken-image-expected.txt deleted file mode 100644 index 33ea039e..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-broken-image-expected.txt +++ /dev/null
@@ -1,20 +0,0 @@ -This test checks behavior of Canvas::drawImage with a broken source image. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -PASS ctx.drawImage(null, 0, 0) threw exception TypeError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The provided value is not of type '(CSSImageValue or HTMLImageElement or HTMLVideoElement or HTMLCanvasElement or ImageBitmap or OffscreenCanvas)'. -PASS ctx.drawImage(null, 0, 0, 20, 20) threw exception TypeError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The provided value is not of type '(CSSImageValue or HTMLImageElement or HTMLVideoElement or HTMLCanvasElement or ImageBitmap or OffscreenCanvas)'. -PASS ctx.drawImage(null, 0, 0, 20, 20, 0, 0, 20, 20) threw exception TypeError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The provided value is not of type '(CSSImageValue or HTMLImageElement or HTMLVideoElement or HTMLCanvasElement or ImageBitmap or OffscreenCanvas)'. -PASS ctx.drawImage(undefined, 0, 0) threw exception TypeError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The provided value is not of type '(CSSImageValue or HTMLImageElement or HTMLVideoElement or HTMLCanvasElement or ImageBitmap or OffscreenCanvas)'. -PASS ctx.drawImage(undefined, 0, 0, 20, 20) threw exception TypeError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The provided value is not of type '(CSSImageValue or HTMLImageElement or HTMLVideoElement or HTMLCanvasElement or ImageBitmap or OffscreenCanvas)'. -PASS ctx.drawImage(undefined, 0, 0, 20, 20, 0, 0, 20, 20) threw exception TypeError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The provided value is not of type '(CSSImageValue or HTMLImageElement or HTMLVideoElement or HTMLCanvasElement or ImageBitmap or OffscreenCanvas)'. -PASS ctx.drawImage(invalidImage, 0, 0) threw exception InvalidStateError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The HTMLImageElement provided is in the 'broken' state.. -PASS ctx.drawImage(invalidImage, 0, 0, 20, 20) threw exception InvalidStateError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The HTMLImageElement provided is in the 'broken' state.. -PASS ctx.drawImage(invalidImage, 0, 0, 20, 20, 0, 0, 20, 20) threw exception InvalidStateError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The HTMLImageElement provided is in the 'broken' state.. -PASS ctx.drawImage(invalidImage, 0, 0, 0, 20) threw exception InvalidStateError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The HTMLImageElement provided is in the 'broken' state.. -PASS ctx.drawImage(invalidImage, 0, 0, 0, 20, 0, 0, 20, 20) threw exception InvalidStateError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The HTMLImageElement provided is in the 'broken' state.. -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-broken-image.html b/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-broken-image.html index afb0f143..16d4500 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-broken-image.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-broken-image.html
@@ -1,36 +1,37 @@ -<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> -<html> -<head> -<script src="../../resources/js-test.js"></script> -</head> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> + <script> - window.jsTestIsAsync = true; - description("This test checks behavior of Canvas::drawImage with a broken source image."); - // Create an image with invalid data. - var invalidImage = new Image(); - invalidImage.src = 'resources/shadow-offset.js'; - invalidImage.onerror = draw; +// Create an image with invalid data. +var invalidImage = new Image(); +invalidImage.src = 'resources/shadow-offset.js'; - var ctx = document.createElement("canvas").getContext('2d'); - function draw() { - // null and undefined images should throw TypeError - shouldThrow("ctx.drawImage(null, 0, 0)"); - shouldThrow("ctx.drawImage(null, 0, 0, 20, 20)"); - shouldThrow("ctx.drawImage(null, 0, 0, 20, 20, 0, 0, 20, 20)"); - shouldThrow("ctx.drawImage(undefined, 0, 0)"); - shouldThrow("ctx.drawImage(undefined, 0, 0, 20, 20)"); - shouldThrow("ctx.drawImage(undefined, 0, 0, 20, 20, 0, 0, 20, 20)"); +var ctx = document.createElement("canvas").getContext('2d'); +function draw() { + // null and undefined images should throw TypeError + assert_throws(null, function() {ctx.drawImage(null, 0, 0)}); + assert_throws(null, function() {ctx.drawImage(null, 0, 0, 20, 20)}); + assert_throws(null, function() {ctx.drawImage(null, 0, 0, 20, 20, 0, 0, 20, 20)}); + assert_throws(null, function() {ctx.drawImage(undefined, 0, 0)}); + assert_throws(null, function() {ctx.drawImage(undefined, 0, 0, 20, 20)}); + assert_throws(null, function() {ctx.drawImage(undefined, 0, 0, 20, 20, 0, 0, 20, 20)}); - // broken images should not throw - shouldThrow("ctx.drawImage(invalidImage, 0, 0)"); - shouldThrow("ctx.drawImage(invalidImage, 0, 0, 20, 20)"); - shouldThrow("ctx.drawImage(invalidImage, 0, 0, 20, 20, 0, 0, 20, 20)"); - shouldThrow("ctx.drawImage(invalidImage, 0, 0, 0, 20)"); - shouldThrow("ctx.drawImage(invalidImage, 0, 0, 0, 20, 0, 0, 20, 20)"); + // broken images should not throw + assert_throws(null, function() {ctx.drawImage(invalidImage, 0, 0)}); + assert_throws(null, function() {ctx.drawImage(invalidImage, 0, 0, 20, 20)}); + assert_throws(null, function() {ctx.drawImage(invalidImage, 0, 0, 20, 20, 0, 0, 20, 20)}); + assert_throws(null, function() {ctx.drawImage(invalidImage, 0, 0, 0, 20)}); + assert_throws(null, function() {ctx.drawImage(invalidImage, 0, 0, 0, 20, 0, 0, 20, 20)}); +} + +async_test(t => { + invalidImage.onerror = function() { + t.step(draw); + t.done(); + } +}, "This test checks behavior of Canvas::drawImage with a broken source image."); - finishJSTest(); - } </script> </body> </html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-negative-source-destination-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-negative-source-destination-expected.txt deleted file mode 100644 index f41ac92..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-negative-source-destination-expected.txt +++ /dev/null
@@ -1,18 +0,0 @@ -Series of tests to ensure correct behaviour on negative source/destination of a HTMLCanvasElement - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -PASS imgdata[4] is 0 -PASS imgdata[5] is 255 -PASS imgdata[6] is 0 -PASS imgdata[0] is 255 -PASS imgdata[1] is 0 -PASS imgdata[2] is 0 -PASS imgdata[4] is 0 -PASS imgdata[5] is 0 -PASS imgdata[6] is 0 -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-negative-source-destination.html b/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-negative-source-destination.html index ad0dbc6..3d866ef 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-negative-source-destination.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-negative-source-destination.html
@@ -1,13 +1,38 @@ -<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> <!-- Test based on that found at http://philip.html5.org/tests/canvas/suite/tests/2d.drawImage.negativesource.html --> -<html> -<head> -<script src="../../resources/js-test.js"></script> -</head> -<body> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> <canvas id="canvas" width="100" height="100"></canvas> -<script src="drawImage-with-negative-source-destination.js"></script> -</body> -</html> +<script> + +test(function(){ + + var canvas2 = document.createElement('canvas'); + canvas2.width = 100; + canvas2.height = 100; + var ctx2 = canvas2.getContext('2d'); + ctx2.fillStyle = '#f00'; + ctx2.fillRect(0, 0, 100, 50); + ctx2.fillStyle = '#0f0'; + ctx2.fillRect(0, 50, 100, 50); + + var canvas = document.getElementById('canvas').getContext('2d'); + canvas.drawImage(canvas2, 100, 50, -50, 50, 0, 0, 50, 50); + canvas.drawImage(canvas2, 100, 100, -50, -50, 0, 100, 50, -50); + canvas.drawImage(canvas2, 0, 100, 100, -50, 100, 100, -50, -50); + canvas.drawImage(canvas2, 0, 50, 100, 50, 100, 0, -50, 50); + + var imageData = canvas.getImageData(1, 0, 1, 1).data; + assert_array_equals(imageData.slice(0,3), [0, 255, 0]); + + // test width or height -1 + canvas.fillStyle = '#000'; + canvas.fillRect(0, 0, 1, 2); + canvas.drawImage(canvas2, 0, 0, 1, 1, 1, 1, -1, -1); + var imageData = canvas.getImageData(0, 0, 1, 2).data; + assert_array_equals(imageData.slice(0,3), [255, 0, 0]); + assert_array_equals(imageData.slice(4,7), [0, 0, 0]); + +}, "Series of tests to ensure correct behaviour on negative source/destination of a HTMLCanvasElement"); +</script> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-negative-source-destination.js b/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-negative-source-destination.js deleted file mode 100644 index 671fd73b..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-negative-source-destination.js +++ /dev/null
@@ -1,34 +0,0 @@ -description("Series of tests to ensure correct behaviour on negative source/destination of a HTMLCanvasElement"); -var canvas2 = document.createElement('canvas'); -canvas2.width = 100; -canvas2.height = 100; -var ctx2 = canvas2.getContext('2d'); -ctx2.fillStyle = '#f00'; -ctx2.fillRect(0, 0, 100, 50); -ctx2.fillStyle = '#0f0'; -ctx2.fillRect(0, 50, 100, 50); - -var canvas = document.getElementById('canvas').getContext('2d'); -canvas.drawImage(canvas2, 100, 50, -50, 50, 0, 0, 50, 50); -canvas.drawImage(canvas2, 100, 100, -50, -50, 0, 100, 50, -50); -canvas.drawImage(canvas2, 0, 100, 100, -50, 100, 100, -50, -50); -canvas.drawImage(canvas2, 0, 50, 100, 50, 100, 0, -50, 50); - -var imageData = canvas.getImageData(0, 0, 100, 100); -var imgdata = imageData.data; -shouldBe("imgdata[4]", "0"); -shouldBe("imgdata[5]", "255"); -shouldBe("imgdata[6]", "0"); - -// test width or height -1 -canvas.fillStyle = '#000'; -canvas.fillRect(0, 0, 1, 2); -canvas.drawImage(canvas2, 0, 0, 1, 1, 1, 1, -1, -1); -var imageData = canvas.getImageData(0, 0, 1, 2); -var imgdata = imageData.data; -shouldBe("imgdata[0]", "255"); -shouldBe("imgdata[1]", "0"); -shouldBe("imgdata[2]", "0"); -shouldBe("imgdata[4]", "0"); -shouldBe("imgdata[5]", "0"); -shouldBe("imgdata[6]", "0");
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-valid-image-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-valid-image-expected.txt deleted file mode 100644 index a319f0f..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-valid-image-expected.txt +++ /dev/null
@@ -1,51 +0,0 @@ -This test checks behavior of valid arguments to Canvas::drawImage that use a valid source image. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -PASS ctx.drawImage() threw exception TypeError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': 3 arguments required, but only 0 present.. -PASS ctx.drawImage(myImage) threw exception TypeError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': 3 arguments required, but only 1 present.. -PASS ctx.drawImage(myImage, 0) threw exception TypeError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': 3 arguments required, but only 2 present.. -PASS ctx.drawImage(myImage, 0, 0) did not throw exception. -PASS ctx.drawImage(myImage, 0, 0, 20, 20) did not throw exception. -PASS ctx.drawImage(myImage, 0, 0, 20, 20, 0, 0, 20, 20) did not throw exception. -PASS ctx.drawImage(myImage, 0, 0, 0, 0) did not throw exception. -PASS ctx.drawImage(myImage, 0, 0, 20, 20, 0, 0, 0, 0) did not throw exception. -PASS ctx.drawImage(myImage, -10, 0, 52, 64, 0, 0, 20, 20) did not throw exception. -PASS ctx.drawImage(myImage, 10, 0, 52, 64, 0, 0, 20, 20) did not throw exception. -PASS ctx.drawImage(myImage, 0, -10, 52, 64, 0, 0, 20, 20) did not throw exception. -PASS ctx.drawImage(myImage, 0, 10, 52, 64, 0, 0, 20, 20) did not throw exception. -PASS ctx.drawImage(myImage, -10, -10, 72, 84, 0, 0, 20, 20) did not throw exception. -PASS ctx.drawImage(myImage, 42, 64, -52, -64, 0, 0, 20, 20) did not throw exception. -PASS ctx.drawImage(myImage, 62, 64, -52, -64, 0, 0, 20, 20) did not throw exception. -PASS ctx.drawImage(myImage, 52, 54, -52, -64, 0, 0, 20, 20) did not throw exception. -PASS ctx.drawImage(myImage, 52, 74, -52, -64, 0, 0, 20, 20) did not throw exception. -PASS ctx.drawImage(myImage, 62, 74, -72, -84, 0, 0, 20, 20) did not throw exception. -PASS ctx.drawImage(new Image(), 0, 0) did not throw exception. -PASS ctx.drawImage(new Image(), 0, 0, 20, 20) did not throw exception. -PASS ctx.drawImage(new Image(), 0, 0, 20, 20, 0, 0, 20, 20) did not throw exception. -PASS ctx.drawImage(new Image(), 0, 0) did not throw exception. -PASS ctx.drawImage(new Image(), 0, 0, 0, 20) did not throw exception. -PASS ctx.drawImage(new Image(), 0, 0, 0, 20, 0, 0, 20, 20) did not throw exception. -PASS ctx.drawImage(bitmap, 0, 0) did not throw exception. -PASS ctx.drawImage(bitmap, 0, 0, 20, 20) did not throw exception. -PASS ctx.drawImage(bitmap, 0, 0, 20, 20, 0, 0, 20, 20) did not throw exception. -PASS ctx.drawImage(bitmap, 0, 0, 0, 0) did not throw exception. -PASS ctx.drawImage(bitmap, 0, 0, 20, 20, 0, 0, 0, 0) did not throw exception. -PASS ctx.drawImage(bitmap, 20, 20, -20, 0, 0, 0, 20, 20) did not throw exception. -PASS ctx.drawImage(bitmap, 0, 0, 20, 0, 20, 20, -20, -20) did not throw exception. -PASS ctx.drawImage(bitmap, 20, 20, -20, 0, 20, 20, -20, -20) did not throw exception. -PASS ctx.drawImage(bitmap, -10, 0, 52, 64, 0, 0, 20, 20) did not throw exception. -PASS ctx.drawImage(bitmap, 10, 0, 52, 64, 0, 0, 20, 20) did not throw exception. -PASS ctx.drawImage(bitmap, 0, -10, 52, 64, 0, 0, 20, 20) did not throw exception. -PASS ctx.drawImage(bitmap, 0, 10, 52, 64, 0, 0, 20, 20) did not throw exception. -PASS ctx.drawImage(bitmap, -10, -10, 72, 84, 0, 0, 20, 20) did not throw exception. -PASS ctx.drawImage(bitmap, 42, 64, -52, -64, 0, 0, 20, 20) did not throw exception. -PASS ctx.drawImage(bitmap, 62, 64, -52, -64, 0, 0, 20, 20) did not throw exception. -PASS ctx.drawImage(bitmap, 52, 54, -52, -64, 0, 0, 20, 20) did not throw exception. -PASS ctx.drawImage(bitmap, 52, 74, -52, -64, 0, 0, 20, 20) did not throw exception. -PASS ctx.drawImage(bitmap, 62, 74, -72, -84, 0, 0, 20, 20) did not throw exception. -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-valid-image.html b/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-valid-image.html index b05a4963..fb1c9a6 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-valid-image.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-valid-image.html
@@ -1,155 +1,153 @@ -<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> -<html> -<head> -<script src="../../resources/js-test.js"></script> -</head> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> + <script> - window.jsTestIsAsync = true; - description("This test checks behavior of valid arguments to Canvas::drawImage that use a valid source image."); - function ExpectedNotEnoughArgumentsMessage(num) { - return "\"TypeError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': 3 arguments required, but only " + num + " present.\""; - } - var IndexSizeError = "IndexSizeError: Index or size was negative, or greater than the allowed value."; +function ExpectedNotEnoughArgumentsMessage(num) { + return "\"TypeError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': 3 arguments required, but only " + num + " present.\""; +} - // Create image - var myImage = new Image(); - var img_src = 'resources/apple.gif'; - myImage.src = img_src; - myImage.onload = draw; +var IndexSizeError = "IndexSizeError: Index or size was negative, or greater than the allowed value."; - var bitmap; - var ctx = document.createElement("canvas").getContext('2d'); - function draw() { - // No arguments should get exception - shouldThrow("ctx.drawImage()", ExpectedNotEnoughArgumentsMessage(0)); +// Create image +var myImage = new Image(); +var img_src = 'resources/apple.gif'; +myImage.src = img_src; - // image argument only should get exception - shouldThrow("ctx.drawImage(myImage)", ExpectedNotEnoughArgumentsMessage(1)); +var bitmap; +var ctx = document.createElement("canvas").getContext('2d'); - // image argument plus one number should get exception - shouldThrow("ctx.drawImage(myImage, 0)", ExpectedNotEnoughArgumentsMessage(2)); +function draw() { + // No arguments should get exception + assert_throws(null, function() {ctx.drawImage();}, ExpectedNotEnoughArgumentsMessage(0)); - // image argument plus 2 numbers - shouldNotThrow("ctx.drawImage(myImage, 0, 0)"); + // image argument only should get exception + assert_throws(null, function() {ctx.drawImage(myImage);}, ExpectedNotEnoughArgumentsMessage(1)); - // image argument plus 4 numbers - shouldNotThrow("ctx.drawImage(myImage, 0, 0, 20, 20)"); + // image argument plus one number should get exception + assert_throws(null, function() {ctx.drawImage(myImage, 0);}, ExpectedNotEnoughArgumentsMessage(2)); - // image argument plus 8 numbers - shouldNotThrow("ctx.drawImage(myImage, 0, 0, 20, 20, 0, 0, 20, 20)"); + // image argument plus 2 numbers + ctx.drawImage(myImage, 0, 0); - // image argument plus zero size - shouldNotThrow("ctx.drawImage(myImage, 0, 0, 0, 0)"); + // image argument plus 4 numbers + ctx.drawImage(myImage, 0, 0, 20, 20); - // image argument plus 8 numbers, zero size - shouldNotThrow("ctx.drawImage(myImage, 0, 0, 20, 20, 0, 0, 0, 0)"); + // image argument plus 8 numbers + ctx.drawImage(myImage, 0, 0, 20, 20, 0, 0, 20, 20); - // imageRect does not contain sourceRect on the left side - shouldNotThrow("ctx.drawImage(myImage, -10, 0, 52, 64, 0, 0, 20, 20)"); + // image argument plus zero size + ctx.drawImage(myImage, 0, 0, 0, 0); - // imageRect does not contain sourceRect on the right side - shouldNotThrow("ctx.drawImage(myImage, 10, 0, 52, 64, 0, 0, 20, 20)"); + // image argument plus 8 numbers, zero size + ctx.drawImage(myImage, 0, 0, 20, 20, 0, 0, 0, 0); - // imageRect does not contain sourceRect on top - shouldNotThrow("ctx.drawImage(myImage, 0, -10, 52, 64, 0, 0, 20, 20)"); + // imageRect does not contain sourceRect on the left side + ctx.drawImage(myImage, -10, 0, 52, 64, 0, 0, 20, 20); - // imageRect does not contain sourceRect on bottom - shouldNotThrow("ctx.drawImage(myImage, 0, 10, 52, 64, 0, 0, 20, 20)"); + // imageRect does not contain sourceRect on the right side + ctx.drawImage(myImage, 10, 0, 52, 64, 0, 0, 20, 20); - // sourceRect is bigger than imageSource on every side - shouldNotThrow("ctx.drawImage(myImage, -10, -10, 72, 84, 0, 0, 20, 20)"); + // imageRect does not contain sourceRect on top + ctx.drawImage(myImage, 0, -10, 52, 64, 0, 0, 20, 20); - // negative size of source, imageRect does not contain sourceRect on the left side - shouldNotThrow("ctx.drawImage(myImage, 42, 64, -52, -64, 0, 0, 20, 20)"); + // imageRect does not contain sourceRect on bottom + ctx.drawImage(myImage, 0, 10, 52, 64, 0, 0, 20, 20); - // negative size of source, imageRect does not contain sourceRect on the right side - shouldNotThrow("ctx.drawImage(myImage, 62, 64, -52, -64, 0, 0, 20, 20)"); + // sourceRect is bigger than imageSource on every side + ctx.drawImage(myImage, -10, -10, 72, 84, 0, 0, 20, 20); - // negative size of source, imageRect does not contain sourceRect on top - shouldNotThrow("ctx.drawImage(myImage, 52, 54, -52, -64, 0, 0, 20, 20)"); + // negative size of source, imageRect does not contain sourceRect on the left side + ctx.drawImage(myImage, 42, 64, -52, -64, 0, 0, 20, 20); - // negative size of source, imageRect does not contain sourceRect on bottom - shouldNotThrow("ctx.drawImage(myImage, 52, 74, -52, -64, 0, 0, 20, 20)"); + // negative size of source, imageRect does not contain sourceRect on the right side + ctx.drawImage(myImage, 62, 64, -52, -64, 0, 0, 20, 20); - // negative size of source, imageRect does not contain sourceRect on every side - shouldNotThrow("ctx.drawImage(myImage, 62, 74, -72, -84, 0, 0, 20, 20)"); + // negative size of source, imageRect does not contain sourceRect on top + ctx.drawImage(myImage, 52, 54, -52, -64, 0, 0, 20, 20); - // images with no src can be drawn - shouldNotThrow("ctx.drawImage(new Image(), 0, 0)"); - shouldNotThrow("ctx.drawImage(new Image(), 0, 0, 20, 20)"); - shouldNotThrow("ctx.drawImage(new Image(), 0, 0, 20, 20, 0, 0, 20, 20)"); + // negative size of source, imageRect does not contain sourceRect on bottom + ctx.drawImage(myImage, 52, 74, -52, -64, 0, 0, 20, 20); - // images with no src exit early before IndexSizeError is thrown - shouldNotThrow("ctx.drawImage(new Image(), 0, 0)"); - shouldNotThrow("ctx.drawImage(new Image(), 0, 0, 0, 20)"); - shouldNotThrow("ctx.drawImage(new Image(), 0, 0, 0, 20, 0, 0, 20, 20)"); + // negative size of source, imageRect does not contain sourceRect on every side + ctx.drawImage(myImage, 62, 74, -72, -84, 0, 0, 20, 20); - createImageBitmap(myImage).then(drawBitmap, function() { - testFailed("Promise was rejected."); - finishJSTest(); - }); - } + // images with no src can be drawn + ctx.drawImage(new Image(), 0, 0); + ctx.drawImage(new Image(), 0, 0, 20, 20); + ctx.drawImage(new Image(), 0, 0, 20, 20, 0, 0, 20, 20); - function drawBitmap(imageBitmap) { - bitmap = imageBitmap; + // images with no src exit early before IndexSizeError is thrown + ctx.drawImage(new Image(), 0, 0); + ctx.drawImage(new Image(), 0, 0, 0, 20); + ctx.drawImage(new Image(), 0, 0, 0, 20, 0, 0, 20, 20); +} - // bitmap argument plus 2 numbers - shouldNotThrow("ctx.drawImage(bitmap, 0, 0)"); +function drawBitmap(imageBitmap) { + bitmap = imageBitmap; - // bitmap argument plus 4 numbers - shouldNotThrow("ctx.drawImage(bitmap, 0, 0, 20, 20)"); + // bitmap argument plus 2 numbers + ctx.drawImage(bitmap, 0, 0); - // bitmap argument plus 8 numbers - shouldNotThrow("ctx.drawImage(bitmap, 0, 0, 20, 20, 0, 0, 20, 20)"); + // bitmap argument plus 4 numbers + ctx.drawImage(bitmap, 0, 0, 20, 20); - // bitmap argument plus zero size - shouldNotThrow("ctx.drawImage(bitmap, 0, 0, 0, 0)"); + // bitmap argument plus 8 numbers + ctx.drawImage(bitmap, 0, 0, 20, 20, 0, 0, 20, 20); - // bitmap argument plus 8 numbers, zero size - shouldNotThrow("ctx.drawImage(bitmap, 0, 0, 20, 20, 0, 0, 0, 0)"); + // bitmap argument plus zero size + ctx.drawImage(bitmap, 0, 0, 0, 0); - // bitmap argument plus 8 numbers, negative size of source, zero size - shouldNotThrow("ctx.drawImage(bitmap, 20, 20, -20, 0, 0, 0, 20, 20)"); + // bitmap argument plus 8 numbers, zero size + ctx.drawImage(bitmap, 0, 0, 20, 20, 0, 0, 0, 0); - // bitmap argument plus 8 numbers, negative size of destination, zero size - shouldNotThrow("ctx.drawImage(bitmap, 0, 0, 20, 0, 20, 20, -20, -20)"); + // bitmap argument plus 8 numbers, negative size of source, zero size + ctx.drawImage(bitmap, 20, 20, -20, 0, 0, 0, 20, 20); - // bitmap argument plus 8 numbers, negative size of source and destination, zero size - shouldNotThrow("ctx.drawImage(bitmap, 20, 20, -20, 0, 20, 20, -20, -20)"); + // bitmap argument plus 8 numbers, negative size of destination, zero size + ctx.drawImage(bitmap, 0, 0, 20, 0, 20, 20, -20, -20); - // imageRect does not contain sourceRect on the left side - shouldNotThrow("ctx.drawImage(bitmap, -10, 0, 52, 64, 0, 0, 20, 20)"); + // bitmap argument plus 8 numbers, negative size of source and destination, zero size + ctx.drawImage(bitmap, 20, 20, -20, 0, 20, 20, -20, -20); - // imageRect does not contain sourceRect on the right side - shouldNotThrow("ctx.drawImage(bitmap, 10, 0, 52, 64, 0, 0, 20, 20)"); + // imageRect does not contain sourceRect on the left side + ctx.drawImage(bitmap, -10, 0, 52, 64, 0, 0, 20, 20); - // imageRect does not contain sourceRect on top - shouldNotThrow("ctx.drawImage(bitmap, 0, -10, 52, 64, 0, 0, 20, 20)"); + // imageRect does not contain sourceRect on the right side + ctx.drawImage(bitmap, 10, 0, 52, 64, 0, 0, 20, 20); - // imageRect does not contain sourceRect on bottom - shouldNotThrow("ctx.drawImage(bitmap, 0, 10, 52, 64, 0, 0, 20, 20)"); + // imageRect does not contain sourceRect on top + ctx.drawImage(bitmap, 0, -10, 52, 64, 0, 0, 20, 20); - // sourceRect is bigger than imageSource on every side - shouldNotThrow("ctx.drawImage(bitmap, -10, -10, 72, 84, 0, 0, 20, 20)"); + // imageRect does not contain sourceRect on bottom + ctx.drawImage(bitmap, 0, 10, 52, 64, 0, 0, 20, 20); - // negative size of source, imageRect does not contain sourceRect on the left side - shouldNotThrow("ctx.drawImage(bitmap, 42, 64, -52, -64, 0, 0, 20, 20)"); + // sourceRect is bigger than imageSource on every side + ctx.drawImage(bitmap, -10, -10, 72, 84, 0, 0, 20, 20); - // negative size of source, imageRect does not contain sourceRect on the right side - shouldNotThrow("ctx.drawImage(bitmap, 62, 64, -52, -64, 0, 0, 20, 20)"); + // negative size of source, imageRect does not contain sourceRect on the left side + ctx.drawImage(bitmap, 42, 64, -52, -64, 0, 0, 20, 20); - // negative size of source, imageRect does not contain sourceRect on top - shouldNotThrow("ctx.drawImage(bitmap, 52, 54, -52, -64, 0, 0, 20, 20)"); + // negative size of source, imageRect does not contain sourceRect on the right side + ctx.drawImage(bitmap, 62, 64, -52, -64, 0, 0, 20, 20); - // negative size of source, imageRect does not contain sourceRect on bottom - shouldNotThrow("ctx.drawImage(bitmap, 52, 74, -52, -64, 0, 0, 20, 20)"); + // negative size of source, imageRect does not contain sourceRect on top + ctx.drawImage(bitmap, 52, 54, -52, -64, 0, 0, 20, 20); - // negative size of source, imageRect does not contain sourceRect on every side - shouldNotThrow("ctx.drawImage(bitmap, 62, 74, -72, -84, 0, 0, 20, 20)"); + // negative size of source, imageRect does not contain sourceRect on bottom + ctx.drawImage(bitmap, 52, 74, -52, -64, 0, 0, 20, 20); - finishJSTest(); - } + // negative size of source, imageRect does not contain sourceRect on every side + ctx.drawImage(bitmap, 62, 74, -72, -84, 0, 0, 20, 20); +} + +async_test(t => { + myImage.onload = function() { + t.step(draw); + createImageBitmap(myImage).then(t.step_func(function(image) { + drawBitmap(image); + })); + t.done(); + } +}, "This test checks behavior of valid arguments to Canvas::drawImage that use a valid source image."); </script> -</body> -</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/fallback-content-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/fallback-content-expected.txt deleted file mode 100644 index ce1a3cf..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/fallback-content-expected.txt +++ /dev/null
@@ -1,78 +0,0 @@ -This test makes sure that focusable elements in canvas fallback content are focusable. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -link1 should be focusable. -PASS document.activeElement == element is true - -button1 should be focusable. -PASS document.activeElement == element is true - -text1 should be focusable. -PASS document.activeElement == element is true - -checkbox1 should be focusable. -PASS document.activeElement == element is true - -radio1 should be focusable. -PASS document.activeElement == element is true - -slider1 should be focusable. -PASS document.activeElement == element is true - -submit1 should be focusable. -PASS document.activeElement == element is true - -combobox1 should be focusable. -PASS document.activeElement == element is true - -listbox1 should be focusable. -PASS document.activeElement == element is true - -textarea1 should be focusable. -PASS document.activeElement == element is true - -focusable1 should be focusable. -PASS document.activeElement == element is true - -link2 should be focusable. -PASS document.activeElement == element is true - -button2 should be focusable. -PASS document.activeElement == element is true - -text2 should be focusable. -PASS document.activeElement == element is true - -checkbox2 should be focusable. -PASS document.activeElement == element is true - -radio2 should be focusable. -PASS document.activeElement == element is true - -slider2 should be focusable. -PASS document.activeElement == element is true - -submit2 should be focusable. -PASS document.activeElement == element is true - -combobox2 should be focusable. -PASS document.activeElement == element is true - -listbox2 should be focusable. -PASS document.activeElement == element is true - -textarea2 should be focusable. -PASS document.activeElement == element is true - -focusable2 should be focusable. -PASS document.activeElement == element is true - -linkInHiddenCanvas should not be focusable. -PASS document.activeElement == previousFocusedElement is true - -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/fallback-content.html b/third_party/WebKit/LayoutTests/fast/canvas/fallback-content.html index 699aecb..9dff9a65 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/fallback-content.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/fallback-content.html
@@ -1,8 +1,9 @@ -<!DOCTYPE HTML> <html> <body> -<script src="../../resources/js-test.js"></script> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> <div id="container"> + <div> <a id="link1" href="#">Link</a> <button id="button1">Button</button> @@ -34,61 +35,59 @@ <canvas hidden id="hiddenCanvas" width="300" height="300"> <a id="linkInHiddenCanvas" href="#">Link</a> </canvas> + </div> -<div id="console"></div> <script> -description("This test makes sure that focusable elements in canvas fallback content are focusable."); - -if (window.testRunner) - window.testRunner.dumpAsText(); - var element; +var previousFocusedElement; + function checkFocusable(id) { - debug(id + " should be focusable."); element = document.getElementById(id); element.focus(); - shouldBe("document.activeElement == element", "true"); - debug(""); + assert_true(document.activeElement == element); } -checkFocusable("link1"); -checkFocusable("button1"); -checkFocusable("text1"); -checkFocusable("checkbox1"); -checkFocusable("radio1"); -checkFocusable("slider1"); -checkFocusable("submit1"); -checkFocusable("combobox1"); -checkFocusable("listbox1"); -checkFocusable("textarea1"); -checkFocusable("focusable1"); - -checkFocusable("link2"); -checkFocusable("button2"); -checkFocusable("text2"); -checkFocusable("checkbox2"); -checkFocusable("radio2"); -checkFocusable("slider2"); -checkFocusable("submit2"); -checkFocusable("combobox2"); -checkFocusable("listbox2"); -checkFocusable("textarea2"); -checkFocusable("focusable2"); - -var previousFocusedElement; function checkNotFocusable(id) { - debug(id + " should not be focusable."); previousFocusedElement = document.activeElement; element = document.getElementById(id); element.focus(); - shouldBe("document.activeElement == previousFocusedElement", "true"); - debug(""); + assert_true(document.activeElement == previousFocusedElement); } -checkNotFocusable("linkInHiddenCanvas"); +var focusableTestScenarios = [ + ['FocusableTestCase1', "link1"], + ['FocusableTestCase2', "button1"], + ['FocusableTestCase3', "text1"], + ['FocusableTestCase4', "checkbox1"], + ['FocusableTestCase5', "radio1"], + ['FocusableTestCase6', "slider1"], + ['FocusableTestCase7', "submit1"], + ['FocusableTestCase8', "combobox1"], + ['FocusableTestCase9', "listbox1"], + ['FocusableTestCase10', "textarea1"], + ['FocusableTestCase11', "focusable1"], + ['FocusableTestCase12', "link2"], + ['FocusableTestCase13', "button2"], + ['FocusableTestCase14', "text2"], + ['FocusableTestCase15', "checkbox2"], + ['FocusableTestCase16', "radio2"], + ['FocusableTestCase17', "slider2"], + ['FocusableTestCase18', "submit2"], + ['FocusableTestCase19', "combobox2"], + ['FocusableTestCase20', "listbox2"], + ['FocusableTestCase21', "textarea2"], + ['FocusableTestCase22', "focusable2"] +]; + +var notFocusableTestScenarios = [ + ['NotFocusableTestCase', "linkInHiddenCanvas"], +]; + +generate_tests(checkFocusable, focusableTestScenarios); +generate_tests(checkNotFocusable, notFocusableTestScenarios); document.querySelector("#container").remove(); -</script> +</script> </body> </html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/fillText-shadow-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/fillText-shadow-expected.txt deleted file mode 100644 index 8f245b9..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/fillText-shadow-expected.txt +++ /dev/null
@@ -1,65 +0,0 @@ -Tests that (vertical) shadow offsets are applied correctly when using fillText() regardless of blur amount. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -Testing with no transform -Testing with blur of 0 pixels -PASS imgdata[0] is 0 -PASS imgdata[1] is 0 -PASS imgdata[2] is 0 -PASS imgdata[3] is 0 -PASS imgdata[0] is 255 -PASS imgdata[1] is 0 -PASS imgdata[2] is 0 -PASS imgdata[3] is 255 -Testing with blur of 1 pixels -PASS imgdata[0] is 0 -PASS imgdata[1] is 0 -PASS imgdata[2] is 0 -PASS imgdata[3] is 0 -PASS imgdata[0] is 255 -PASS imgdata[1] is 0 -PASS imgdata[2] is 0 -PASS imgdata[3] is 255 -Testing with blur of 5 pixels -PASS imgdata[0] is 0 -PASS imgdata[1] is 0 -PASS imgdata[2] is 0 -PASS imgdata[3] is 0 -PASS imgdata[0] is 255 -PASS imgdata[1] is 0 -PASS imgdata[2] is 0 -PASS imgdata[3] is 255 -Testing with scale transform -Testing with blur of 0 pixels -PASS imgdata[0] is 0 -PASS imgdata[1] is 0 -PASS imgdata[2] is 0 -PASS imgdata[3] is 0 -PASS imgdata[0] is 255 -PASS imgdata[1] is 0 -PASS imgdata[2] is 0 -PASS imgdata[3] is 255 -Testing with blur of 1 pixels -PASS imgdata[0] is 0 -PASS imgdata[1] is 0 -PASS imgdata[2] is 0 -PASS imgdata[3] is 0 -PASS imgdata[0] is 255 -PASS imgdata[1] is 0 -PASS imgdata[2] is 0 -PASS imgdata[3] is 255 -Testing with blur of 5 pixels -PASS imgdata[0] is 0 -PASS imgdata[1] is 0 -PASS imgdata[2] is 0 -PASS imgdata[3] is 0 -PASS imgdata[0] is 255 -PASS imgdata[1] is 0 -PASS imgdata[2] is 0 -PASS imgdata[3] is 255 -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/fillText-shadow.html b/third_party/WebKit/LayoutTests/fast/canvas/fillText-shadow.html index 57611ca..57dca07 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/fillText-shadow.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/fillText-shadow.html
@@ -1,55 +1,47 @@ -<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> -<html> -<head> -<script src="../../resources/js-test.js"></script> -</head> -<body> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> <canvas width="600" height="300" style="border: solid 1px gray"></canvas> + <script> -description('Tests that (vertical) shadow offsets are applied correctly when using fillText() regardless of blur amount.'); + +// Tests that (vertical) shadow offsets are applied correctly when using fillText() regardless of blur amount. + var ctx = document.getElementsByTagName('canvas')[0].getContext('2d'); ctx.font = 'bold 128px sans-serif'; ctx.shadowColor = 'red' ctx.shadowOffsetY = 100; function testWithBlur(blur, belowOffset) { - ctx.clearRect(0, 0, 600, 300); - ctx.shadowBlur = blur; - - // Center the I around the Y axis. - ctx.fillText('I', -ctx.measureText('I').width/2, 128); - - debug('Testing with blur of ' + blur + ' pixels'); + ctx.clearRect(0, 0, 600, 300); + ctx.shadowBlur = blur; + + // Center the I around the Y axis. + ctx.fillText('I', -ctx.measureText('I').width/2, 128); - // Make sure that the shadow doesn't end up above the text... - var imageData = ctx.getImageData(0, 0, 1, 1); - imgdata = imageData.data; + // Make sure that the shadow doesn't end up above the text... + var imageData = ctx.getImageData(0, 0, 1, 1).data; + assert_array_equals(imageData, [0, 0, 0, 0]); - shouldBe('imgdata[0]', '0'); - shouldBe('imgdata[1]', '0'); - shouldBe('imgdata[2]', '0'); - shouldBe('imgdata[3]', '0'); - - // ...but below. - var imageData = ctx.getImageData(0, belowOffset, 1, 1); - imgdata = imageData.data; - shouldBe('imgdata[0]', '255'); - shouldBe('imgdata[1]', '0'); - shouldBe('imgdata[2]', '0'); - shouldBe('imgdata[3]', '255'); + // ...but below. + var imageData = ctx.getImageData(0, belowOffset, 1, 1).data; + assert_array_equals(imageData, [255, 0, 0, 255]); } -debug('Testing with no transform'); -testWithBlur(0, 150); -testWithBlur(1, 150); -testWithBlur(5, 150); +var testScenariosNoTransform = [ + ['TestShadowOffsetWithNoTransform 1', 0, 150], + ['TestShadowOffsetWithNoTransform 2', 1, 150], + ['TestShadowOffsetWithNoTransform 3', 5, 150], +]; -debug('Testing with scale transform'); +var testScenariosScaleTransform = [ + ['TestShadowOffsetWithScaleTransform 1', 0, 299], + ['TestShadowOffsetWithScaleTransform 2', 1, 299], + ['TestShadowOffsetWithScaleTransform 3', 5, 299], +]; + +generate_tests(testWithBlur, testScenariosNoTransform); + ctx.scale(1, 2); -testWithBlur(0, 299); -testWithBlur(1, 299); -testWithBlur(5, 299); +generate_tests(testWithBlur, testScenariosScaleTransform); </script> -</body> -</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/getPutImageDataPairTest-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/getPutImageDataPairTest-expected.txt deleted file mode 100644 index d8300436..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/getPutImageDataPairTest-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -Test that putImageData(getImageData) pair leaves canvas ImageData the same. - - -Result: PASS
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/getPutImageDataPairTest.html b/third_party/WebKit/LayoutTests/fast/canvas/getPutImageDataPairTest.html index 94ac797..ab075af 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/getPutImageDataPairTest.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/getPutImageDataPairTest.html
@@ -1,33 +1,11 @@ -<!DOCTYPE html> -<title>putImageData(getImageData) pair test</title> -<body class="show_output"> -<h3>Test that putImageData(getImageData) pair leaves canvas ImageData the same.</h3> -<canvas id="c" class="output" width="64" height="64"><p class="fallback">FAIL (fallback content)</p></canvas> -<br> -Result: <a id="result"></a> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> + <script> -if (window.testRunner) - testRunner.dumpAsText(); +var canvas = document.createElement('canvas'); +var ctx = canvas.getContext('2d'); -var canvas = document.getElementById("c"); -var ctx = canvas.getContext("2d"); -var passed = getPutImageData(50, ctx, 0, 0, 0, 0.0); -passed |= getPutImageData(50, ctx, 0, 0, 0, 0.5); -passed |= getPutImageData(50, ctx, 0, 0, 0, 1.0); -passed |= getPutImageData(50, ctx, 127, 128, 129, 0.49); -passed |= getPutImageData(50, ctx, 127, 128, 129, 0.51); -passed |= getPutImageData(50, ctx, 127, 128, 129, 0.5); -passed |= getPutImageData(50, ctx, 128, 128, 128, 0.0); -passed |= getPutImageData(50, ctx, 128, 128, 128, 0.5); -passed |= getPutImageData(50, ctx, 128, 128, 128, 1.0); - -var result_a = document.getElementById("result"); -if (!passed) - result_a.innerHTML = "FAIL"; -else - result_a.innerHTML = "PASS"; - -function getPutImageData(numIters, ctx, r, g, b, a) { +function getPutImageData(numIters, ctx, rgba) { var x = 0, y = 0, w = ctx.canvas.width, h = ctx.canvas.height; // Paint the canvas green to start @@ -35,7 +13,7 @@ ctx.fillRect(x,y,w,h); // Now paint the canvas a random hue of gray - var color = 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')'; + var color = 'rgba(' + rgba + ')'; ctx.fillStyle = color; ctx.fillRect(x,y,w,h); @@ -45,20 +23,33 @@ // Get and put the image data 'numIters' times for(var i = 0; i < numIters; i++) - ctx.putImageData(ctx.getImageData(x,y,w,h), x,y); + ctx.putImageData(ctx.getImageData(x, y, w, h), x,y); // Grab new current image data var currImageData = ctx.getImageData(x, y, w, h); // Verify that original and new current image datas are equal - for(var i = 0; i < currImageData.data.length; i++) { - var origSubpixel = origImageData.data[i]; - var currSubpixel = currImageData.data[i]; - - // If even 1 subpixel is off, return failure - if (origSubpixel != currSubpixel) - return false; - } - return true; + var dataMatch = true; + for(var i = 0; i < currImageData.data.length; i++) + if (origImageData.data[i] != currImageData.data[i]) { + dataMatch = false; + break; + } + assert_true(dataMatch); } -</script> \ No newline at end of file + +var testScenarios = [ + ['GetPutImageDataTestCase ', 50, ctx, '0, 0, 0, 0.0'], + ['GetPutImageDataTestCase ', 50, ctx, '0, 0, 0, 0.5'], + ['GetPutImageDataTestCase ', 50, ctx, '0, 0, 0, 1.0'], + ['GetPutImageDataTestCase ', 50, ctx, '127, 128, 129, 0.49'], + ['GetPutImageDataTestCase ', 50, ctx, '127, 128, 129, 0.51'], + ['GetPutImageDataTestCase ', 50, ctx, '127, 128, 129, 0.5'], + ['GetPutImageDataTestCase ', 50, ctx, '128, 128, 128, 0.0'], + ['GetPutImageDataTestCase ', 50, ctx, '128, 128, 128, 0.5'], + ['GetPutImageDataTestCase ', 50, ctx, '128, 128, 128, 1.0'], +]; + +generate_tests(getPutImageData, testScenarios); + +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/gradient-addColorStop-with-invalid-color-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/gradient-addColorStop-with-invalid-color-expected.txt deleted file mode 100644 index 560a3bd3..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/gradient-addColorStop-with-invalid-color-expected.txt +++ /dev/null
@@ -1,13 +0,0 @@ -This test checks invalid colors on gradients. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -PASS gradient.addColorStop(0, '') threw exception SyntaxError: Failed to execute 'addColorStop' on 'CanvasGradient': The value provided ('') could not be parsed as a color.. -PASS gradient.addColorStop(0, '#cc') threw exception SyntaxError: Failed to execute 'addColorStop' on 'CanvasGradient': The value provided ('#cc') could not be parsed as a color.. -PASS gradient.addColorStop(0, 'rgb(257, 0)') threw exception SyntaxError: Failed to execute 'addColorStop' on 'CanvasGradient': The value provided ('rgb(257, 0)') could not be parsed as a color.. -PASS gradient.addColorStop(0, 'rgb(257, 0, 5, 0)') threw exception SyntaxError: Failed to execute 'addColorStop' on 'CanvasGradient': The value provided ('rgb(257, 0, 5, 0)') could not be parsed as a color.. -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/gradient-addColorStop-with-invalid-color.html b/third_party/WebKit/LayoutTests/fast/canvas/gradient-addColorStop-with-invalid-color.html index 51eb48f..d731bc77 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/gradient-addColorStop-with-invalid-color.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/gradient-addColorStop-with-invalid-color.html
@@ -1,9 +1,17 @@ -<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> -<html> -<head> -<script src="../../resources/js-test.js"></script> -</head> -<body> -<script src="script-tests/gradient-addColorStop-with-invalid-color.js"></script> -</body> -</html> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script> +test(function(){ + + var gradient = document.createElement('canvas').getContext('2d').createLinearGradient(0, 0, 150, 0); + + assert_throws(null, function(){gradient.addColorStop(0, '');}, '"SyntaxError: Failed to execute \'addColorStop\' on \'CanvasGradient\': The value provided (\'\') could not be parsed as a color."'); + + assert_throws(null, function(){gradient.addColorStop(0, '#cc');}, '"SyntaxError: Failed to execute \'addColorStop\' on \'CanvasGradient\': The value provided (\'#cc\') could not be parsed as a color."'); + + assert_throws(null, function(){gradient.addColorStop(0, 'rgb(257, 0)');}, '"SyntaxError: Failed to execute \'addColorStop\' on \'CanvasGradient\': The value provided (\'rgb(257, 0)\') could not be parsed as a color."'); + + assert_throws(null, function(){gradient.addColorStop(0, 'rgb(257, 0, 5, 0)');}, '"SyntaxError: Failed to execute \'addColorStop\' on \'CanvasGradient\': The value provided (\'rgb(257, 0, 5, 0)\') could not be parsed as a color."'); + +}, 'This test checks invalid colors on gradients.'); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/gradient-addColorStop-with-invalid-offset-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/gradient-addColorStop-with-invalid-offset-expected.txt deleted file mode 100644 index cad908e4..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/gradient-addColorStop-with-invalid-offset-expected.txt +++ /dev/null
@@ -1,14 +0,0 @@ -This test checks invalid offsets on gradients. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -PASS gradient.addColorStop(-1, '#000') threw exception IndexSizeError: Failed to execute 'addColorStop' on 'CanvasGradient': The provided value (-1) is outside the range (0.0, 1.0).. -PASS gradient.addColorStop(2, '#000') threw exception IndexSizeError: Failed to execute 'addColorStop' on 'CanvasGradient': The provided value (2) is outside the range (0.0, 1.0).. -PASS gradient.addColorStop(Infinity, '#000') threw exception TypeError: Failed to execute 'addColorStop' on 'CanvasGradient': The provided float value is non-finite.. -PASS gradient.addColorStop(-Infinity, '#000') threw exception TypeError: Failed to execute 'addColorStop' on 'CanvasGradient': The provided float value is non-finite.. -PASS gradient.addColorStop(NaN, '#000') threw exception TypeError: Failed to execute 'addColorStop' on 'CanvasGradient': The provided float value is non-finite.. -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/gradient-addColorStop-with-invalid-offset.html b/third_party/WebKit/LayoutTests/fast/canvas/gradient-addColorStop-with-invalid-offset.html index f340a48..c2640a4 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/gradient-addColorStop-with-invalid-offset.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/gradient-addColorStop-with-invalid-offset.html
@@ -1,9 +1,15 @@ -<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> -<html> -<head> -<script src="../../resources/js-test.js"></script> -</head> -<body> -<script src="script-tests/gradient-addColorStop-with-invalid-offset.js"></script> -</body> -</html> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script> +test(function() { + + var gradient = document.createElement('canvas').getContext('2d').createLinearGradient(0, 0, 150, 0); + + assert_throws(null, function(){gradient.addColorStop(-1, '#000');}); + assert_throws(null, function(){gradient.addColorStop(2, '#000');}); + assert_throws(null, function(){gradient.addColorStop(Infinity, '#000');}); + assert_throws(null, function(){gradient.addColorStop(-Infinity, '#000');}); + assert_throws(null, function(){gradient.addColorStop(NaN, '#000');}); + +}, 'This test checks invalid offsets on gradients.'); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/gradient-with-clip-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/gradient-with-clip-expected.txt deleted file mode 100644 index 160a7dd1..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/gradient-with-clip-expected.txt +++ /dev/null
@@ -1,10 +0,0 @@ -Test for canvas regression where gradient clips were not cleared https://bugs.webkit.org/show_bug.cgi?id=21498 - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -PASS pixel 20, 20 is [0, 128, 0, 255] -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/gradient-with-clip.html b/third_party/WebKit/LayoutTests/fast/canvas/gradient-with-clip.html index 99d2171..7797585 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/gradient-with-clip.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/gradient-with-clip.html
@@ -1,9 +1,50 @@ -<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> -<html> -<head> -<script src="../../resources/js-test.js"></script> -</head> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> <body> -<script src="script-tests/gradient-with-clip.js"></script> +<script> + +var canvas; +function fillWithColor(context, color) { + context.save(); + context.fillStyle = color; + context.fillRect(0, 0, canvas.width, canvas.height); + context.restore(); +} + +test(function(t) { + canvas = document.createElement("canvas"); + canvas.height = 100; + canvas.width = 100; + canvas.style.height = "100"; + canvas.style.width = "100"; + + document.body.appendChild(canvas); + + var greenImage = document.createElement("canvas"); + greenImage.height = 10; + greenImage.width = 10; + var greenCtx = greenImage.getContext('2d'); + fillWithColor(greenCtx, "green"); + var greenPixel = greenCtx.getImageData(0, 0, 1, 1).data; + + var ctx = canvas.getContext('2d'); + var gradient = ctx.createLinearGradient(0, 0, 10, 0); + gradient.addColorStop(0, "blue"); + gradient.addColorStop(1, "red"); + ctx.fillStyle = gradient; + ctx.beginPath(); + ctx.moveTo(0, 0); + ctx.lineTo(10, 5); + ctx.lineTo(10, 10); + ctx.lineTo(5, 10); + ctx.closePath(); + ctx.fill(); + + ctx.fillStyle = "green"; + ctx.fillRect(20, 20, 10, 10); + + assert_array_equals(ctx.getImageData(20, 20, 1, 1).data, greenPixel); + +}, "Test for canvas regression where gradient clips were not cleared https://bugs.webkit.org/show_bug.cgi?id=21498") +</script> </body> -</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/image-pattern-rotate-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/image-pattern-rotate-expected.txt deleted file mode 100644 index 7ccec9e..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/image-pattern-rotate-expected.txt +++ /dev/null
@@ -1,53 +0,0 @@ -PASS successfullyParsed is true - -TEST COMPLETE -PASS imgdata[0] is 0 -PASS imgdata[1] is 255 -PASS imgdata[2] is 0 -PASS imgdata[0] is 0 -PASS imgdata[1] is 255 -PASS imgdata[2] is 0 -PASS imgdata[0] is 0 -PASS imgdata[1] is 255 -PASS imgdata[2] is 0 -PASS imgdata[0] is 0 -PASS imgdata[1] is 255 -PASS imgdata[2] is 0 -PASS imgdata[0] is 0 -PASS imgdata[1] is 255 -PASS imgdata[2] is 0 -PASS imgdata[0] is 0 -PASS imgdata[1] is 255 -PASS imgdata[2] is 0 -PASS imgdata[0] is 0 -PASS imgdata[1] is 255 -PASS imgdata[2] is 0 -PASS imgdata[0] is 0 -PASS imgdata[1] is 255 -PASS imgdata[2] is 0 -PASS imgdata[0] is 0 -PASS imgdata[1] is 255 -PASS imgdata[2] is 0 -PASS imgdata[0] is 0 -PASS imgdata[1] is 255 -PASS imgdata[2] is 0 -PASS imgdata[0] is 0 -PASS imgdata[1] is 255 -PASS imgdata[2] is 0 -PASS imgdata[0] is 0 -PASS imgdata[1] is 255 -PASS imgdata[2] is 0 -PASS imgdata[0] is 0 -PASS imgdata[1] is 255 -PASS imgdata[2] is 0 -PASS imgdata[0] is 0 -PASS imgdata[1] is 255 -PASS imgdata[2] is 0 -PASS imgdata[0] is 0 -PASS imgdata[1] is 255 -PASS imgdata[2] is 0 -PASS imgdata[0] is 0 -PASS imgdata[1] is 255 -PASS imgdata[2] is 0 -Visual result below is for debugging purposes only (test uses text baseline only). You should see sixteen canvases with a green dot (rotated square) in the center. -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/image-pattern-rotate.html b/third_party/WebKit/LayoutTests/fast/canvas/image-pattern-rotate.html index 0c970d3e..87a120a 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/image-pattern-rotate.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/image-pattern-rotate.html
@@ -1,19 +1,21 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" - "http://www.w3.org/TR/html4/loose.dtd"> -<html> -<head> -<script src="../../resources/js-test.js"></script> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> + <style> canvas { border: 1px solid #000; margin: 2px; } </style> +<div id="canvases"></div> + <script> +// Visual result for debugging (test uses text baseline only): You should see sixteen canvases with a green dot (rotated square) in the center. + var img; var imgdata; -function imageLoaded() { +function runTests() { var NUM_IMAGE = 16; for (var i = 0; i < NUM_IMAGE; i++) { var canvases = document.getElementById('canvases') @@ -34,40 +36,25 @@ div.appendChild(canvas); canvases.appendChild(div); - var imageData = ctx.getImageData(4, 4, 1, 1); - imgdata = imageData.data; - shouldBe("imgdata[0]", "0"); - shouldBe("imgdata[1]", "255"); - shouldBe("imgdata[2]", "0"); - } - - if (window.testRunner) { - testRunner.notifyDone(); + assert_array_equals(ctx.getImageData(4, 4, 1, 1).data.slice(0,3), [0, 255, 0]); } } -function runTests() { - if (window.testRunner) { - testRunner.dumpAsText(); - testRunner.waitUntilDone(); - } - var patternCanvas = document.createElement('canvas'); - patternCanvas.width = 9; - patternCanvas.height = 9; - var patternCtx = patternCanvas.getContext('2d'); - patternCtx.fillStyle = '#0F0'; - patternCtx.fillRect(3, 3, 3, 3); - img = new Image(); - img.onload = imageLoaded; - img.src = patternCanvas.toDataURL(); +var patternCanvas = document.createElement('canvas'); +patternCanvas.width = 9; +patternCanvas.height = 9; +var patternCtx = patternCanvas.getContext('2d'); +patternCtx.fillStyle = '#0F0'; +patternCtx.fillRect(3, 3, 3, 3); +img = new Image(); +img.src = patternCanvas.toDataURL(); -} + +async_test(t => { + img.onload = function() { + t.step(runTests); + t.done(); + } +}, "Test image pattern rotation."); </script> -</head> -<body onload="runTests();"> -Visual result below is for debugging purposes only (test uses text baseline only). You should see sixteen canvases with a green dot (rotated square) in the center. -<div id="canvases"></div> -</pre> -</body> -</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/imagedata-contains-uint8clampedarray-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/imagedata-contains-uint8clampedarray-expected.txt deleted file mode 100644 index 7093c38..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/imagedata-contains-uint8clampedarray-expected.txt +++ /dev/null
@@ -1,10 +0,0 @@ -Tests that ImageData contains a Uint8ClampedArray. - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -PASS imageData.data.constructor is Uint8ClampedArray -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/imagedata-contains-uint8clampedarray.html b/third_party/WebKit/LayoutTests/fast/canvas/imagedata-contains-uint8clampedarray.html index 9d89f1d..39060860 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/imagedata-contains-uint8clampedarray.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/imagedata-contains-uint8clampedarray.html
@@ -1,19 +1,15 @@ -<!DOCTYPE html> -<html> -<head> -<script src="../../resources/js-test.js"></script> -</head> -<body> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> <script> -description("Tests that ImageData contains a Uint8ClampedArray."); +test(function(){ -var canvas = document.createElement("canvas"); -canvas.width = 10; -canvas.height = 10; -var context = canvas.getContext("2d"); + var canvas = document.createElement("canvas"); + canvas.width = 10; + canvas.height = 10; + var context = canvas.getContext("2d"); -var imageData = context.getImageData(0, 0, 1, 1); -shouldBe('imageData.data.constructor', 'Uint8ClampedArray'); + var imageData = context.getImageData(0, 0, 1, 1); + assert_equals(imageData.data.constructor, Uint8ClampedArray); + +}, "Tests that ImageData contains a Uint8ClampedArray."); </script> -</body> -</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/invalid-set-font-crash-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/invalid-set-font-crash-expected.txt deleted file mode 100644 index d31f6ea..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/invalid-set-font-crash-expected.txt +++ /dev/null
@@ -1,3 +0,0 @@ -This test should not crash. - -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/invalid-set-font-crash.html b/third_party/WebKit/LayoutTests/fast/canvas/invalid-set-font-crash.html index 5bfc970..58067b5 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/invalid-set-font-crash.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/invalid-set-font-crash.html
@@ -1,19 +1,18 @@ -<html> -<head> - <script type="text/javascript"> - if (window.testRunner) - testRunner.dumpAsText(); +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> - function init() - { - var ctx = document.getElementById("canvas").getContext("2d"); - ctx.font = "font-family: Helvetica; font-size: 48pt; font-color: #000000"; - ctx.fillText("Hello world", 10, 200); +<script> +function runTest() +{ + var ctx = document.createElement("canvas").getContext("2d"); + ctx.font = "font-family: Helvetica; font-size: 48pt; font-color: #000000"; + ctx.fillText("Hello world", 10, 200); +} + +async_test(t => { + window.onload = function() { + t.step(runTest); + t.done(); } - </script> -</head> -<body onload="init()"> - <p>This test should not crash.</p> - <canvas id="canvas" height="300" width="300"></canvas> -</body> -</html> +}, 'Verify that setting the font does not crash.'); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/linearGradient-infinite-values-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/linearGradient-infinite-values-expected.txt deleted file mode 100644 index f257fe3..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/linearGradient-infinite-values-expected.txt +++ /dev/null
@@ -1,21 +0,0 @@ -This test checks createLinearGradient with infinite values - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - - -PASS ctx.createLinearGradient(0, 0, 100, NaN) threw exception TypeError: Failed to execute 'createLinearGradient' on 'CanvasRenderingContext2D': The provided double value is non-finite.. -PASS ctx.createLinearGradient(0, 0, 100, Infinity) threw exception TypeError: Failed to execute 'createLinearGradient' on 'CanvasRenderingContext2D': The provided double value is non-finite.. -PASS ctx.createLinearGradient(0, 0, 100, -Infinity) threw exception TypeError: Failed to execute 'createLinearGradient' on 'CanvasRenderingContext2D': The provided double value is non-finite.. -PASS ctx.createLinearGradient(0, 0, NaN, 100) threw exception TypeError: Failed to execute 'createLinearGradient' on 'CanvasRenderingContext2D': The provided double value is non-finite.. -PASS ctx.createLinearGradient(0, 0, Infinity, 100) threw exception TypeError: Failed to execute 'createLinearGradient' on 'CanvasRenderingContext2D': The provided double value is non-finite.. -PASS ctx.createLinearGradient(0, 0, -Infinity, 100) threw exception TypeError: Failed to execute 'createLinearGradient' on 'CanvasRenderingContext2D': The provided double value is non-finite.. -PASS ctx.createLinearGradient(0, NaN, 100, 100) threw exception TypeError: Failed to execute 'createLinearGradient' on 'CanvasRenderingContext2D': The provided double value is non-finite.. -PASS ctx.createLinearGradient(0, Infinity, 100, 100) threw exception TypeError: Failed to execute 'createLinearGradient' on 'CanvasRenderingContext2D': The provided double value is non-finite.. -PASS ctx.createLinearGradient(0, -Infinity, 100, 100) threw exception TypeError: Failed to execute 'createLinearGradient' on 'CanvasRenderingContext2D': The provided double value is non-finite.. -PASS ctx.createLinearGradient(NaN, 0, 100, 100) threw exception TypeError: Failed to execute 'createLinearGradient' on 'CanvasRenderingContext2D': The provided double value is non-finite.. -PASS ctx.createLinearGradient(Infinity, 0, 100, 100) threw exception TypeError: Failed to execute 'createLinearGradient' on 'CanvasRenderingContext2D': The provided double value is non-finite.. -PASS ctx.createLinearGradient(-Infinity, 0, 100, 100) threw exception TypeError: Failed to execute 'createLinearGradient' on 'CanvasRenderingContext2D': The provided double value is non-finite.. -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/linearGradient-infinite-values.html b/third_party/WebKit/LayoutTests/fast/canvas/linearGradient-infinite-values.html index 3e4694a..97c6eb9 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/linearGradient-infinite-values.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/linearGradient-infinite-values.html
@@ -1,9 +1,30 @@ -<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> -<html> -<head> -<script src="../../resources/js-test.js"></script> -</head> -<body> -<script src="script-tests/linearGradient-infinite-values.js"></script> -</body> -</html> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> + +<script> +// This test checks createLinearGradient with infinite values +var ctx = document.createElement('canvas').getContext('2d'); + +function testCreateLinearGradient(params) +{ + x0 = params[0]; y0 = params[1]; x1 = params[2]; y1 = params[3]; + assert_throws(null, function(){ctx.createLinearGradient(x0, y0, x1, y1);}); +} + +var testScenarios = [ + ['Test createLinearGradient(0, 0, 100, NaN)' , [0, 0, 100, NaN]], + ['Test createLinearGradient(0, 0, 100, Infinity)' , [0, 0, 100, Infinity]], + ['Test createLinearGradient(0, 0, 100, -Infinity)' , [0, 0, 100, -Infinity]], + ['Test createLinearGradient(0, 0, NaN, 100)' , [0, 0, NaN, 100]], + ['Test createLinearGradient(0, 0, Infinity, 100)' , [0, 0, Infinity, 100]], + ['Test createLinearGradient(0, 0, -Infinity, 100)' , [0, 0, -Infinity, 100]], + ['Test createLinearGradient(0, NaN, 100, 100)' , [0, NaN, 100, 100]], + ['Test createLinearGradient(0, Infinity, 100, 100)' , [0, Infinity, 100, 100]], + ['Test createLinearGradient(0, -Infinity, 100, 100)' , [0, -Infinity, 100, 100]], + ['Test createLinearGradient(NaN, 0, 100, 100)' , [NaN, 0, 100, 100]], + ['Test createLinearGradient(Infinity, 0, 100, 100)' , [Infinity, 0, 100, 100]], + ['Test createLinearGradient(-Infinity, 0, 100, 100)' , [-Infinity, 0, 100, 100]], +]; + +generate_tests(testCreateLinearGradient, testScenarios); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/gradient-addColorStop-with-invalid-color.js b/third_party/WebKit/LayoutTests/fast/canvas/script-tests/gradient-addColorStop-with-invalid-color.js deleted file mode 100644 index 07dae37f..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/gradient-addColorStop-with-invalid-color.js +++ /dev/null
@@ -1,10 +0,0 @@ -description( -'This test checks invalid colors on gradients.' -); - -var gradient = document.createElement('canvas').getContext('2d').createLinearGradient(0, 0, 150, 0); - -shouldThrow("gradient.addColorStop(0, '')", '"SyntaxError: Failed to execute \'addColorStop\' on \'CanvasGradient\': The value provided (\'\') could not be parsed as a color."'); -shouldThrow("gradient.addColorStop(0, '#cc')", '"SyntaxError: Failed to execute \'addColorStop\' on \'CanvasGradient\': The value provided (\'#cc\') could not be parsed as a color."'); -shouldThrow("gradient.addColorStop(0, 'rgb(257, 0)')", '"SyntaxError: Failed to execute \'addColorStop\' on \'CanvasGradient\': The value provided (\'rgb(257, 0)\') could not be parsed as a color."'); -shouldThrow("gradient.addColorStop(0, 'rgb(257, 0, 5, 0)')", '"SyntaxError: Failed to execute \'addColorStop\' on \'CanvasGradient\': The value provided (\'rgb(257, 0, 5, 0)\') could not be parsed as a color."');
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/gradient-addColorStop-with-invalid-offset.js b/third_party/WebKit/LayoutTests/fast/canvas/script-tests/gradient-addColorStop-with-invalid-offset.js deleted file mode 100644 index 493ad9a..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/gradient-addColorStop-with-invalid-offset.js +++ /dev/null
@@ -1,10 +0,0 @@ -description('This test checks invalid offsets on gradients.'); - -var gradient = document.createElement('canvas').getContext('2d').createLinearGradient(0, 0, 150, 0); - -// Check that invalid offset values throw. -shouldThrow("gradient.addColorStop(-1, '#000')"); -shouldThrow("gradient.addColorStop(2, '#000')"); -shouldThrow("gradient.addColorStop(Infinity, '#000')"); -shouldThrow("gradient.addColorStop(-Infinity, '#000')"); -shouldThrow("gradient.addColorStop(NaN, '#000')");
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/gradient-with-clip.js b/third_party/WebKit/LayoutTests/fast/canvas/script-tests/gradient-with-clip.js deleted file mode 100644 index e8d7929..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/gradient-with-clip.js +++ /dev/null
@@ -1,63 +0,0 @@ -description("Test for canvas regression where gradient clips were not cleared https://bugs.webkit.org/show_bug.cgi?id=21498") - -function pixelValueAt(context, x, y) { - var imageData = context.getImageData(x, y, 1, 1); - return imageData.data; -} - -function pixelToString(p) { - return "[" + p[0] + ", " + p[1] + ", " + p[2] + ", " + p[3] + "]" -} - -function pixelShouldBe(context, x, y, expectedPixelString) { - var pixel = pixelValueAt(context, x, y); - var expectedPixel = eval(expectedPixelString); - - var pixelString = "pixel " + x + ", " + y; - if (areArraysEqual(pixel, expectedPixel)) { - testPassed(pixelString + " is " + pixelToString(pixel)); - } else { - testFailed(pixelString + " should be " + pixelToString(expectedPixel) + " was " + pixelToString(pixel)); - } -} - -function fillWithColor(context, color) { - context.save(); - context.fillStyle = color; - context.fillRect(0, 0, canvas.width, canvas.height); - context.restore(); -} - -var canvas = document.createElement("canvas"); -canvas.height = 100; -canvas.width = 100; -canvas.style.height = "100"; -canvas.style.width = "100"; - -document.body.appendChild(canvas); - -var greenImage = document.createElement("canvas"); -greenImage.height = 10; -greenImage.width = 10; -var greenCtx = greenImage.getContext('2d'); -fillWithColor(greenCtx, "green"); -var greenPixel = pixelValueAt(greenCtx, 0, 0); - - -var ctx = canvas.getContext('2d'); -var gradient = ctx.createLinearGradient(0, 0, 10, 0); -gradient.addColorStop(0, "blue"); -gradient.addColorStop(1, "red"); -ctx.fillStyle = gradient; -ctx.beginPath(); -ctx.moveTo(0, 0); -ctx.lineTo(10, 5); -ctx.lineTo(10, 10); -ctx.lineTo(5, 10); -ctx.closePath(); -ctx.fill(); - -ctx.fillStyle = "green"; -ctx.fillRect(20, 20, 10, 10); - -pixelShouldBe(ctx, 20, 20, "greenPixel");
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/linearGradient-infinite-values.js b/third_party/WebKit/LayoutTests/fast/canvas/script-tests/linearGradient-infinite-values.js deleted file mode 100644 index a3f886a..0000000 --- a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/linearGradient-infinite-values.js +++ /dev/null
@@ -1,18 +0,0 @@ -description( -'This test checks createLinearGradient with infinite values' -); - -var ctx = document.createElement('canvas').getContext('2d'); - -shouldThrow("ctx.createLinearGradient(0, 0, 100, NaN)"); -shouldThrow("ctx.createLinearGradient(0, 0, 100, Infinity)"); -shouldThrow("ctx.createLinearGradient(0, 0, 100, -Infinity)"); -shouldThrow("ctx.createLinearGradient(0, 0, NaN, 100)"); -shouldThrow("ctx.createLinearGradient(0, 0, Infinity, 100)"); -shouldThrow("ctx.createLinearGradient(0, 0, -Infinity, 100)"); -shouldThrow("ctx.createLinearGradient(0, NaN, 100, 100)"); -shouldThrow("ctx.createLinearGradient(0, Infinity, 100, 100)"); -shouldThrow("ctx.createLinearGradient(0, -Infinity, 100, 100)"); -shouldThrow("ctx.createLinearGradient(NaN, 0, 100, 100)"); -shouldThrow("ctx.createLinearGradient(Infinity, 0, 100, 100)"); -shouldThrow("ctx.createLinearGradient(-Infinity, 0, 100, 100)");
diff --git a/third_party/WebKit/Source/core/frame/UseCounter.h b/third_party/WebKit/Source/core/frame/UseCounter.h index e23782d..14eb5f0 100644 --- a/third_party/WebKit/Source/core/frame/UseCounter.h +++ b/third_party/WebKit/Source/core/frame/UseCounter.h
@@ -1209,23 +1209,6 @@ VRGetDisplays = 1558, VRPresent = 1559, VRDeprecatedGetPose = 1560, - WebAudioAnalyserNode = 1561, - WebAudioAudioBuffer = 1562, - WebAudioAudioBufferSourceNode = 1563, - WebAudioBiquadFilterNode = 1564, - WebAudioChannelMergerNode = 1565, - WebAudioChannelSplitterNode = 1566, - WebAudioConvolverNode = 1567, - WebAudioDelayNode = 1568, - WebAudioDynamicsCompressorNode = 1569, - WebAudioGainNode = 1570, - WebAudioIIRFilterNode = 1571, - WebAudioMediaElementAudioSourceNode = 1572, - WebAudioOscillatorNode = 1573, - WebAudioPannerNode = 1574, - WebAudioPeriodicWave = 1575, - WebAudioStereoPannerNode = 1576, - WebAudioWaveShaperNode = 1577, CSSZoomReset = 1578, CSSZoomDocument = 1579, XSSAuditorBlockedScript = 1581,
diff --git a/third_party/WebKit/Source/core/svg/SVGAnimationElement.cpp b/third_party/WebKit/Source/core/svg/SVGAnimationElement.cpp index a93258a..3f48d92 100644 --- a/third_party/WebKit/Source/core/svg/SVGAnimationElement.cpp +++ b/third_party/WebKit/Source/core/svg/SVGAnimationElement.cpp
@@ -253,24 +253,14 @@ return clampTo<float>(duration.value()); } -void SVGAnimationElement::beginElement() { - beginElementAt(0); -} - void SVGAnimationElement::beginElementAt(float offset) { - ASSERT(std::isfinite(offset)); - SMILTime elapsed = this->elapsed(); - addBeginTime(elapsed, elapsed + offset, SMILTimeWithOrigin::ScriptOrigin); -} - -void SVGAnimationElement::endElement() { - endElementAt(0); + DCHECK(std::isfinite(offset)); + addInstanceTime(Begin, elapsed() + offset, SMILTimeWithOrigin::ScriptOrigin); } void SVGAnimationElement::endElementAt(float offset) { - ASSERT(std::isfinite(offset)); - SMILTime elapsed = this->elapsed(); - addEndTime(elapsed, elapsed + offset, SMILTimeWithOrigin::ScriptOrigin); + DCHECK(std::isfinite(offset)); + addInstanceTime(End, elapsed() + offset, SMILTimeWithOrigin::ScriptOrigin); } void SVGAnimationElement::updateAnimationMode() {
diff --git a/third_party/WebKit/Source/core/svg/SVGAnimationElement.h b/third_party/WebKit/Source/core/svg/SVGAnimationElement.h index 2aa9411d..50e62db4 100644 --- a/third_party/WebKit/Source/core/svg/SVGAnimationElement.h +++ b/third_party/WebKit/Source/core/svg/SVGAnimationElement.h
@@ -60,9 +60,9 @@ float getCurrentTime() const; float getSimpleDuration(ExceptionState&) const; - void beginElement(); + void beginElement() { beginElementAt(0); } void beginElementAt(float offset); - void endElement(); + void endElement() { endElementAt(0); } void endElementAt(float offset); DEFINE_MAPPED_ATTRIBUTE_EVENT_LISTENER(begin, beginEvent);
diff --git a/third_party/WebKit/Source/core/svg/animation/SVGSMILElement.cpp b/third_party/WebKit/Source/core/svg/animation/SVGSMILElement.cpp index cbf3a6d..9a0ab683 100644 --- a/third_party/WebKit/Source/core/svg/animation/SVGSMILElement.cpp +++ b/third_party/WebKit/Source/core/svg/animation/SVGSMILElement.cpp
@@ -121,7 +121,11 @@ void ConditionEventListener::handleEvent(ExecutionContext*, Event* event) { if (!m_animation) return; - m_animation->handleConditionEvent(event, m_condition); + if (event->type() == "repeatn" && + toRepeatEvent(event)->repeat() != m_condition->repeat()) + return; + m_animation->addInstanceTime(m_condition->getBeginOrEnd(), + m_animation->elapsed() + m_condition->offset()); } SVGSMILElement::Condition::Condition(Type type, @@ -720,20 +724,20 @@ return std::min(dur(), SMILTime::indefinite()); } -void SVGSMILElement::addBeginTime(SMILTime eventTime, - SMILTime beginTime, - SMILTimeWithOrigin::Origin origin) { - m_beginTimes.push_back(SMILTimeWithOrigin(beginTime, origin)); - sortTimeList(m_beginTimes); - beginListChanged(eventTime); -} - -void SVGSMILElement::addEndTime(SMILTime eventTime, - SMILTime endTime, - SMILTimeWithOrigin::Origin origin) { - m_endTimes.push_back(SMILTimeWithOrigin(endTime, origin)); - sortTimeList(m_endTimes); - endListChanged(eventTime); +void SVGSMILElement::addInstanceTime(BeginOrEnd beginOrEnd, + SMILTime time, + SMILTimeWithOrigin::Origin origin) { + SMILTime elapsed = this->elapsed(); + if (elapsed.isUnresolved()) + return; + Vector<SMILTimeWithOrigin>& list = + beginOrEnd == Begin ? m_beginTimes : m_endTimes; + list.push_back(SMILTimeWithOrigin(time, origin)); + sortTimeList(list); + if (beginOrEnd == Begin) + beginListChanged(elapsed); + else + endListChanged(elapsed); } inline bool compareTimes(const SMILTimeWithOrigin& left, @@ -1210,13 +1214,7 @@ time = syncBase.m_interval.end + condition->offset(); if (!time.isFinite()) continue; - SMILTime elapsed = this->elapsed(); - if (elapsed.isUnresolved()) - continue; - if (condition->getBeginOrEnd() == Begin) - addBeginTime(elapsed, time); - else - addEndTime(elapsed, time); + addInstanceTime(condition->getBeginOrEnd(), time); } } } @@ -1231,25 +1229,8 @@ m_syncBaseDependents.erase(&animation); } -void SVGSMILElement::handleConditionEvent(Event* event, Condition* condition) { - if (event->type() == "repeatn" && - toRepeatEvent(event)->repeat() != condition->repeat()) - return; - - SMILTime elapsed = this->elapsed(); - if (elapsed.isUnresolved()) - return; - if (condition->getBeginOrEnd() == Begin) - addBeginTime(elapsed, elapsed + condition->offset()); - else - addEndTime(elapsed, elapsed + condition->offset()); -} - void SVGSMILElement::beginByLinkActivation() { - SMILTime elapsed = this->elapsed(); - if (elapsed.isUnresolved()) - return; - addBeginTime(elapsed, elapsed); + addInstanceTime(Begin, elapsed()); } void SVGSMILElement::endedActiveInterval() {
diff --git a/third_party/WebKit/Source/core/svg/animation/SVGSMILElement.h b/third_party/WebKit/Source/core/svg/animation/SVGSMILElement.h index b89f404..773552c 100644 --- a/third_party/WebKit/Source/core/svg/animation/SVGSMILElement.h +++ b/third_party/WebKit/Source/core/svg/animation/SVGSMILElement.h
@@ -127,13 +127,11 @@ DECLARE_VIRTUAL_TRACE(); protected: - void addBeginTime( - SMILTime eventTime, - SMILTime endTime, - SMILTimeWithOrigin::Origin = SMILTimeWithOrigin::ParserOrigin); - void addEndTime( - SMILTime eventTime, - SMILTime endTime, + enum BeginOrEnd { Begin, End }; + + void addInstanceTime( + BeginOrEnd, + SMILTime, SMILTimeWithOrigin::Origin = SMILTimeWithOrigin::ParserOrigin); void setInactive() { m_activeState = Inactive; } @@ -159,8 +157,6 @@ bool layoutObjectIsNeeded(const ComputedStyle&) override { return false; } - enum BeginOrEnd { Begin, End }; - SMILTime findInstanceTime(BeginOrEnd, SMILTime minimumTime, bool equalsMinimumOK) const; @@ -237,9 +233,6 @@ void disconnectSyncBaseConditions(); void disconnectEventBaseConditions(); - // Event base timing - void handleConditionEvent(Event*, Condition*); - void notifyDependentsIntervalChanged(); void createInstanceTimesFromSyncbase(SVGSMILElement& syncbase); void addSyncBaseDependent(SVGSMILElement&);
diff --git a/third_party/WebKit/Source/modules/modules_idl_files.gni b/third_party/WebKit/Source/modules/modules_idl_files.gni index 8dec1f3..94ed5f68 100644 --- a/third_party/WebKit/Source/modules/modules_idl_files.gni +++ b/third_party/WebKit/Source/modules/modules_idl_files.gni
@@ -628,7 +628,6 @@ "vibration/NavigatorVibration.idl", "vr/NavigatorVR.idl", "wake_lock/ScreenWakeLock.idl", - "webaudio/WindowWebAudio.idl", "webaudio/WindowAudioWorklet.idl", "webauth/NavigatorAuth.idl", "webdatabase/WindowWebDatabase.idl",
diff --git a/third_party/WebKit/Source/modules/webaudio/DOMWindowWebAudio.h b/third_party/WebKit/Source/modules/webaudio/DOMWindowWebAudio.h deleted file mode 100644 index 2725e65..0000000 --- a/third_party/WebKit/Source/modules/webaudio/DOMWindowWebAudio.h +++ /dev/null
@@ -1,6 +0,0 @@ -// Copyright (c) 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. - -// TODO: This is a dummy header file required by the generated binding code. -// This file should be removed after fixing the code generator.
diff --git a/third_party/WebKit/Source/modules/webaudio/WindowWebAudio.idl b/third_party/WebKit/Source/modules/webaudio/WindowWebAudio.idl deleted file mode 100644 index 4cc737d..0000000 --- a/third_party/WebKit/Source/modules/webaudio/WindowWebAudio.idl +++ /dev/null
@@ -1,27 +0,0 @@ -// Copyright (c) 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. - -[ - ImplementedAs=DOMWindowWebAudio, -] partial interface Window { - // The individual constructible AudioNodes. - [MeasureAs=WebAudioAnalyserNode] attribute AnalyserNodeConstructor AnalyserNode; - [MeasureAs=WebAudioAudioBuffer] attribute AudioBufferConstructor AudioBuffer; - [MeasureAs=WebAudioAudioBufferSourceNode] attribute AudioBufferSourceNodeConstructor AudioBufferSourceNode; - [MeasureAs=WebAudioBiquadFilterNode] attribute BiquadFilterNodeConstructor BiquadFilterNode; - [MeasureAs=WebAudioChannelMergerNode] attribute ChannelMergerNodeConstructor ChannelMergerNode; - [MeasureAs=WebAudioChannelSplitterNode] attribute ChannelSplitterNodeConstructor ChannelSplitterNode; - [MeasureAs=WebAudioConstantSourceNode] attribute ConstantSourceNodeConstructor ConstantSourceNode; - [MeasureAs=WebAudioConvolverNode] attribute ConvolverNodeConstructor ConvolverNode; - [MeasureAs=WebAudioDelayNode] attribute DelayNodeConstructor DelayNode; - [MeasureAs=WebAudioDynamicsCompressorNode] attribute DynamicsCompressorNodeConstructor DynamicsCompressorNode; - [MeasureAs=WebAudioGainNode] attribute GainNodeConstructor GainNode; - [MeasureAs=WebAudioIIRFilterNode] attribute IIRFilterNodeConstructor IIRFilterNode; - [MeasureAs=WebAudioMediaElementAudioSourceNode] attribute MediaElementAudioSourceNodeConstructor MediaElementAudioSourceNode; - [MeasureAs=WebAudioOscillatorNode] attribute OscillatorNodeConstructor OscillatorNode; - [MeasureAs=WebAudioPannerNode] attribute PannerNodeConstructor PannerNode; - [MeasureAs=WebAudioPeriodicWave] attribute PeriodicWaveConstructor PeriodicWave; - [MeasureAs=WebAudioStereoPannerNode] attribute StereoPannerNodeConstructor StereoPannerNode; - [MeasureAs=WebAudioWaveShaperNode] attribute WaveShaperNodeConstructor WaveShaperNode; -};
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLDrawBuffers.cpp b/third_party/WebKit/Source/modules/webgl/WebGLDrawBuffers.cpp index dd50473..07eff840 100644 --- a/third_party/WebKit/Source/modules/webgl/WebGLDrawBuffers.cpp +++ b/third_party/WebKit/Source/modules/webgl/WebGLDrawBuffers.cpp
@@ -45,8 +45,7 @@ // static bool WebGLDrawBuffers::supported(WebGLRenderingContextBase* context) { - return (context->extensionsUtil()->supportsExtension("GL_EXT_draw_buffers") && - satisfiesWebGLRequirements(context)); + return context->extensionsUtil()->supportsExtension("GL_EXT_draw_buffers"); } // static @@ -96,101 +95,4 @@ } } -// static -bool WebGLDrawBuffers::satisfiesWebGLRequirements( - WebGLRenderingContextBase* webglContext) { - gpu::gles2::GLES2Interface* gl = webglContext->contextGL(); - Extensions3DUtil* extensionsUtil = webglContext->extensionsUtil(); - - // This is called after we make sure GL_EXT_draw_buffers is supported. - GLint maxDrawBuffers = 0; - GLint maxColorAttachments = 0; - gl->GetIntegerv(GL_MAX_DRAW_BUFFERS_EXT, &maxDrawBuffers); - gl->GetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &maxColorAttachments); - if (maxDrawBuffers < 4 || maxColorAttachments < 4) - return false; - - GLuint fbo; - gl->GenFramebuffers(1, &fbo); - gl->BindFramebuffer(GL_FRAMEBUFFER, fbo); - - const unsigned char* buffer = - 0; // Chromium doesn't allow init data for depth/stencil tetxures. - bool supportsDepth = - (extensionsUtil->supportsExtension("GL_CHROMIUM_depth_texture") || - extensionsUtil->supportsExtension("GL_OES_depth_texture") || - extensionsUtil->supportsExtension("GL_ARB_depth_texture")); - bool supportsDepthStencil = - (extensionsUtil->supportsExtension("GL_EXT_packed_depth_stencil") || - extensionsUtil->supportsExtension("GL_OES_packed_depth_stencil")); - GLuint depthStencil = 0; - if (supportsDepthStencil) { - gl->GenTextures(1, &depthStencil); - gl->BindTexture(GL_TEXTURE_2D, depthStencil); - gl->TexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_STENCIL_OES, 1, 1, 0, - GL_DEPTH_STENCIL_OES, GL_UNSIGNED_INT_24_8_OES, buffer); - } - GLuint depth = 0; - if (supportsDepth) { - gl->GenTextures(1, &depth); - gl->BindTexture(GL_TEXTURE_2D, depth); - gl->TexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 1, 1, 0, - GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, buffer); - } - - Vector<GLuint> colors; - bool ok = true; - GLint maxAllowedBuffers = std::min(maxDrawBuffers, maxColorAttachments); - for (GLint i = 0; i < maxAllowedBuffers; ++i) { - GLuint color; - - gl->GenTextures(1, &color); - colors.push_back(color); - gl->BindTexture(GL_TEXTURE_2D, color); - gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, - GL_UNSIGNED_BYTE, buffer); - gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, - GL_TEXTURE_2D, color, 0); - if (gl->CheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { - ok = false; - break; - } - if (supportsDepth) { - gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, - GL_TEXTURE_2D, depth, 0); - if (gl->CheckFramebufferStatus(GL_FRAMEBUFFER) != - GL_FRAMEBUFFER_COMPLETE) { - ok = false; - break; - } - gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, - GL_TEXTURE_2D, 0, 0); - } - if (supportsDepthStencil) { - // For ES 2.0 contexts DEPTH_STENCIL is not available natively, so we - // emulate it at the command buffer level for WebGL contexts. - gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, - GL_TEXTURE_2D, depthStencil, 0); - if (gl->CheckFramebufferStatus(GL_FRAMEBUFFER) != - GL_FRAMEBUFFER_COMPLETE) { - ok = false; - break; - } - gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, - GL_TEXTURE_2D, 0, 0); - } - } - - webglContext->restoreCurrentFramebuffer(); - gl->DeleteFramebuffers(1, &fbo); - webglContext->restoreCurrentTexture2D(); - if (supportsDepth) - gl->DeleteTextures(1, &depth); - if (supportsDepthStencil) - gl->DeleteTextures(1, &depthStencil); - gl->DeleteTextures(colors.size(), colors.data()); - - return ok; -} - } // namespace blink
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLDrawBuffers.h b/third_party/WebKit/Source/modules/webgl/WebGLDrawBuffers.h index 500caa90..4bf6b217 100644 --- a/third_party/WebKit/Source/modules/webgl/WebGLDrawBuffers.h +++ b/third_party/WebKit/Source/modules/webgl/WebGLDrawBuffers.h
@@ -45,8 +45,6 @@ private: explicit WebGLDrawBuffers(WebGLRenderingContextBase*); - - static bool satisfiesWebGLRequirements(WebGLRenderingContextBase*); }; } // namespace blink
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzFace.cpp b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzFace.cpp index b0603181..75436bf8 100644 --- a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzFace.cpp +++ b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzFace.cpp
@@ -387,11 +387,29 @@ m_harfBuzzFontData->m_rangeSet = rangeSet; m_harfBuzzFontData->updateSimpleFontData(m_platformData); - // TODO crbug.com/674879 - Connect variation axis parameters to future - // HarfBuzz API here. ASSERT(m_harfBuzzFontData->m_simpleFontData); int scale = SkiaScalarToHarfBuzzPosition(m_platformData->size()); hb_font_set_scale(m_unscaledFont, scale, scale); + +// TODO: crbug.com/696570 Remove this conditional +// once HarfBuzz on CrOS is updated. +#if HB_VERSION_ATLEAST(1, 4, 2) + SkTypeface* typeface = m_harfBuzzFontData->m_paint.getTypeface(); + int axisCount = typeface->getVariationDesignPosition(nullptr, 0); + if (axisCount > 0) { + Vector<SkFontArguments::VariationPosition::Coordinate> axisValues; + axisValues.resize(axisCount); + typeface->getVariationDesignPosition(axisValues.data(), axisValues.size()); + Vector<float> axisValuesFloat; + axisValuesFloat.resize(axisCount); + for (size_t i = 0; i < axisValues.size(); i++) { + axisValuesFloat[i] = axisValues[i].value; + } + hb_font_set_var_coords_design(m_unscaledFont, axisValuesFloat.data(), + axisValuesFloat.size()); + } +#endif + return m_unscaledFont; }
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/git.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/git.py index f50d7d8..1024d14 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/git.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/git.py
@@ -163,7 +163,7 @@ """ # `git status -z` is a version of `git status -s`, that's recommended # for machine parsing. Lines are terminated with NUL rather than LF. - change_lines = self._run_git(['status', '-z']).rstrip('\x00') + change_lines = self._run_git(['status', '-z', '--untracked-files=all']).rstrip('\x00') if not change_lines: return {} # No changes. unstaged_changes = {}
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/net/git_cl.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/net/git_cl.py index 34b80cd..1c7ac25 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/common/net/git_cl.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/net/git_cl.py
@@ -16,16 +16,23 @@ _log = logging.getLogger(__name__) +# A refresh token may be needed for some commands, such as git cl try, +# in order to authenticate with buildbucket. +_COMMANDS_THAT_TAKE_REFRESH_TOKEN = ('try',) + class GitCL(object): - def __init__(self, host, cwd=None): + def __init__(self, host, auth_refresh_token_json=None, cwd=None): self._host = host + self._auth_refresh_token_json = auth_refresh_token_json self._cwd = cwd def run(self, args): """Runs git-cl with the given arguments and returns the output.""" command = ['git', 'cl'] + args + if self._auth_refresh_token_json and args[0] in _COMMANDS_THAT_TAKE_REFRESH_TOKEN: + command += ['--auth-refresh-token-json', self._auth_refresh_token_json] return self._host.executive.run_command(command, cwd=self._cwd) def get_issue_number(self):
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/net/git_cl_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/net/git_cl_unittest.py index b30bccdc..f2ddfb5 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/common/net/git_cl_unittest.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/net/git_cl_unittest.py
@@ -20,12 +20,21 @@ self.assertEqual(output, 'mock-output') self.assertEqual(host.executive.calls, [['git', 'cl', 'command']]) - def test_run_basic(self): + def test_run_with_auth(self): host = MockHost() host.executive = MockExecutive(output='mock-output') - git_cl = GitCL(host) - git_cl.run(['upload']) - self.assertEqual(host.executive.calls, [['git', 'cl', 'upload']]) + git_cl = GitCL(host, auth_refresh_token_json='token.json') + git_cl.run(['try', '-b', 'win10_blink_rel']) + self.assertEqual( + host.executive.calls, + [['git', 'cl', 'try', '-b', 'win10_blink_rel', '--auth-refresh-token-json', 'token.json']]) + + def test_some_commands_not_run_with_auth(self): + host = MockHost() + host.executive = MockExecutive(output='mock-output') + git_cl = GitCL(host, auth_refresh_token_json='token.json') + git_cl.run(['issue']) + self.assertEqual(host.executive.calls, [['git', 'cl', 'issue']]) def test_get_issue_number(self): host = MockHost()
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py index 4bb5a936..2ef4840 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py
@@ -55,7 +55,7 @@ if not self.checkout_is_okay(options.allow_local_commits): return 1 - self.git_cl = GitCL(self.host) + self.git_cl = GitCL(self.host, auth_refresh_token_json=options.auth_refresh_token_json) _log.debug('Noting the current Chromium commit.') _, show_ref_output = self.run(['git', 'show-ref', 'HEAD']) @@ -124,7 +124,9 @@ parser.add_argument('--auto-update', action='store_true', help='uploads CL and initiates commit queue.') parser.add_argument('--auth-refresh-token-json', - help='Auth refresh JSON token (ignored, deprecated)') + help='authentication refresh token JSON file, ' + 'used for authentication for try jobs, ' + 'generally not necessary on developer machines') parser.add_argument('--ignore-exportable-commits', action='store_true', help='Continue even if there are exportable commits that may be overwritten.') return parser.parse_args(argv)
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index a54cd2d0..df0613d 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -97880,6 +97880,7 @@ <int value="-138773929" label="PassiveDocumentEventListeners:enabled"/> <int value="-122492389" label="enable-browser-task-scheduler"/> <int value="-119055644" label="GenericSensor:enabled"/> + <int value="-108881882" label="NTPCondensedTileLayout:enabled"/> <int value="-102537270" label="extension-content-verification"/> <int value="-99781021" label="disable-roboto-font-ui"/> <int value="-89690053" label="MaterialDesignUserManager:enabled"/> @@ -98060,6 +98061,7 @@ <int value="684806628" label="TranslateLanguageByULP:disabled"/> <int value="689489984" label="disable-zero-suggest"/> <int value="690185633" label="NonValidatingReloadOnNormalReload:disabled"/> + <int value="691020108" label="NTPCondensedTileLayout:disabled"/> <int value="693012666" label="QuickUnlockPin:disabled"/> <int value="709850261" label="disable-touch-editing"/> <int value="711424932" label="enable-cloud-print-xps"/>
diff --git a/ui/app_list/search/mixer.cc b/ui/app_list/search/mixer.cc index 0e8cdb33..78db4de 100644 --- a/ui/app_list/search/mixer.cc +++ b/ui/app_list/search/mixer.cc
@@ -28,8 +28,7 @@ } // namespace -Mixer::SortData::SortData() : result(NULL), score(0.0) { -} +Mixer::SortData::SortData() : result(nullptr), score(0.0) {} Mixer::SortData::SortData(SearchResult* result, double score) : result(result), score(score) { @@ -47,21 +46,22 @@ : max_results_(max_results), multiplier_(multiplier) {} ~Group() {} - void AddProvider(SearchProvider* provider) { providers_.push_back(provider); } + void AddProvider(SearchProvider* provider) { + providers_.emplace_back(provider); + } void FetchResults(bool is_voice_query, const KnownResults& known_results) { results_.clear(); for (const SearchProvider* provider : providers_) { - for (SearchResult* result : provider->results()) { + for (const auto& result : provider->results()) { DCHECK(!result->id().empty()); // We cannot rely on providers to give relevance scores in the range // [0.0, 1.0] (e.g., PeopleProvider directly gives values from the // Google+ API). Clamp to that range. - double relevance = std::min(std::max(result->relevance(), 0.0), 1.0); - - double multiplier = multiplier_; + const double relevance = + std::min(std::max(result->relevance(), 0.0), 1.0); double boost = 0.0; // Recommendations should not be affected by query-to-launch correlation @@ -97,7 +97,7 @@ boost += 4.0; } - results_.push_back(SortData(result, relevance * multiplier + boost)); + results_.emplace_back(result.get(), relevance * multiplier_ + boost); } } @@ -145,7 +145,7 @@ // Add results from each group. Limit to the maximum number of results in each // group. for (const Group* group : groups_) { - size_t num_results = + const size_t num_results = std::min(group->results().size(), group->max_results()); results.insert(results.end(), group->results().begin(), group->results().begin() + num_results); @@ -157,8 +157,8 @@ RemoveDuplicates(&results); std::sort(results.begin(), results.end()); - if (results.size() < num_max_results) { - size_t original_size = results.size(); + const size_t original_size = results.size(); + if (original_size < num_max_results) { // We didn't get enough results. Insert all the results again, and this // time, do not limit the maximum number of results from each group. (This // will result in duplicates, which will be removed by RemoveDuplicates.) @@ -192,7 +192,7 @@ // meaningful indexes. auto current_results = ui_results->RemoveAll(); std::map<std::string, std::unique_ptr<SearchResult>> ui_results_map; - for (std::unique_ptr<SearchResult>& ui_result : current_results) + for (auto& ui_result : current_results) ui_results_map[ui_result->id()] = std::move(ui_result); // Add items back to |ui_results| in the order of |new_results|. @@ -227,12 +227,10 @@ std::set<std::string> id_set; for (const SortData& sort_data : *results) { - const std::string& id = sort_data.result->id(); - if (id_set.find(id) != id_set.end()) + if (!id_set.insert(sort_data.result->id()).second) continue; - id_set.insert(id); - final.push_back(sort_data); + final.emplace_back(sort_data); } results->swap(final);
diff --git a/ui/app_list/search/tokenized_string.cc b/ui/app_list/search/tokenized_string.cc index 232b3e1..887fe86 100644 --- a/ui/app_list/search/tokenized_string.cc +++ b/ui/app_list/search/tokenized_string.cc
@@ -38,9 +38,9 @@ const size_t word_start = break_iter.prev(); TermBreakIterator term_iter(word); while (term_iter.Advance()) { - tokens_.push_back(base::i18n::ToLower(term_iter.GetCurrentTerm())); - mappings_.push_back(gfx::Range(word_start + term_iter.prev(), - word_start + term_iter.pos())); + tokens_.emplace_back(base::i18n::ToLower(term_iter.GetCurrentTerm())); + mappings_.emplace_back(word_start + term_iter.prev(), + word_start + term_iter.pos()); } } }
diff --git a/ui/app_list/search_controller.cc b/ui/app_list/search_controller.cc index 64ea6b3..83cca8d 100644 --- a/ui/app_list/search_controller.cc +++ b/ui/app_list/search_controller.cc
@@ -23,7 +23,7 @@ namespace { // Maximum time (in milliseconds) to wait to the search providers to finish. -const int kStopTimeMS = 1500; +constexpr int kStopTimeMS = 1500; } namespace app_list { @@ -43,11 +43,9 @@ base::TrimWhitespace(search_box_->text(), base::TRIM_ALL, &query); dispatching_query_ = true; - for (Providers::iterator it = providers_.begin(); - it != providers_.end(); - ++it) { - (*it)->Start(is_voice_query, query); - } + for (const auto& provider : providers_) + provider->Start(is_voice_query, query); + dispatching_query_ = false; query_for_recommendation_ = query.empty() ? true : false; @@ -64,11 +62,8 @@ void SearchController::Stop() { stop_timer_.Stop(); - for (Providers::iterator it = providers_.begin(); - it != providers_.end(); - ++it) { - (*it)->Stop(); - } + for (const auto& provider : providers_) + provider->Stop(); } void SearchController::OpenResult(SearchResult* result, int event_flags) { @@ -117,7 +112,7 @@ provider->set_result_changed_callback( base::Bind(&SearchController::OnResultsChanged, base::Unretained(this))); mixer_->AddProviderToGroup(group_id, provider.get()); - providers_.push_back(std::move(provider)); + providers_.emplace_back(std::move(provider)); } void SearchController::OnResultsChanged() {
diff --git a/ui/app_list/search_controller.h b/ui/app_list/search_controller.h index 3fd9427..f8f69583 100644 --- a/ui/app_list/search_controller.h +++ b/ui/app_list/search_controller.h
@@ -10,7 +10,6 @@ #include <memory> #include "base/macros.h" -#include "base/memory/scoped_vector.h" #include "base/timer/timer.h" #include "ui/app_list/app_list_export.h" #include "ui/app_list/app_list_model.h" @@ -49,8 +48,6 @@ void AddProvider(size_t group_id, std::unique_ptr<SearchProvider> provider); private: - typedef ScopedVector<SearchProvider> Providers; - // Invoked when the search results are changed. void OnResultsChanged(); @@ -60,6 +57,8 @@ // If true, the search results are shown on the launcher start page. bool query_for_recommendation_ = false; + + using Providers = std::vector<std::unique_ptr<SearchProvider>>; Providers providers_; std::unique_ptr<Mixer> mixer_; History* history_; // KeyedService, not owned.
diff --git a/ui/app_list/search_provider.cc b/ui/app_list/search_provider.cc index 6d7bea8..a8887ee 100644 --- a/ui/app_list/search_provider.cc +++ b/ui/app_list/search_provider.cc
@@ -16,7 +16,12 @@ } void SearchProvider::Add(std::unique_ptr<SearchResult> result) { - results_.push_back(std::move(result)); + results_.emplace_back(std::move(result)); + FireResultChanged(); +} + +void SearchProvider::SwapResults(Results* new_results) { + results_.swap(*new_results); FireResultChanged(); }
diff --git a/ui/app_list/search_provider.h b/ui/app_list/search_provider.h index 22f0f2c1..406b4cf 100644 --- a/ui/app_list/search_provider.h +++ b/ui/app_list/search_provider.h
@@ -6,10 +6,10 @@ #define UI_APP_LIST_SEARCH_PROVIDER_H_ #include <memory> +#include <vector> #include "base/callback.h" #include "base/macros.h" -#include "base/memory/scoped_vector.h" #include "base/strings/string16.h" #include "ui/app_list/app_list_export.h" @@ -19,8 +19,8 @@ class APP_LIST_EXPORT SearchProvider { public: - typedef ScopedVector<SearchResult> Results; - typedef base::Closure ResultChangedCallback; + using Results = std::vector<std::unique_ptr<SearchResult>>; + using ResultChangedCallback = base::Closure; SearchProvider(); virtual ~SearchProvider(); @@ -40,6 +40,12 @@ protected: // Interface for the derived class to generate search results. void Add(std::unique_ptr<SearchResult> result); + + // Swaps the internal results with |new_results|. + // This is useful when multiple results will be added, and the notification is + // desired to be done only once when all results are added. + void SwapResults(Results* new_results); + void ClearResults(); private:
diff --git a/ui/app_list/views/start_page_view.cc b/ui/app_list/views/start_page_view.cc index fb19777..f7a48f5c 100644 --- a/ui/app_list/views/start_page_view.cc +++ b/ui/app_list/views/start_page_view.cc
@@ -202,7 +202,6 @@ search_result_tile_views_[i]->SetEnabled(true); } - Layout(); parent()->Layout(); // Add 1 to the results size to account for the all apps button. return display_results.size() + 1; @@ -249,6 +248,7 @@ // Add SearchResultTileItemViews to the container. int i = 0; + search_result_tile_views_.reserve(apps_num); for (; i < apps_num; ++i) { SearchResultTileItemView* tile_item = new SearchResultTileItemView(this, view_delegate_); @@ -258,7 +258,7 @@ AddChildView(tile_item); tile_item->SetParentBackgroundColor(kLabelBackgroundColor); tile_item->SetHoverStyle(TileItemView::HOVER_STYLE_ANIMATE_SHADOW); - search_result_tile_views_.push_back(tile_item); + search_result_tile_views_.emplace_back(tile_item); } // Also add a special "all apps" button to the end of the container. @@ -294,7 +294,6 @@ AddChildView(custom_launcher_page_background_); tiles_container_->SetResults(view_delegate_->GetModel()->results()); - Reset(); } StartPageView::~StartPageView() {
diff --git a/ui/display/manager/chromeos/display_change_observer.cc b/ui/display/manager/chromeos/display_change_observer.cc index 95a1e57..f4206c7e83 100644 --- a/ui/display/manager/chromeos/display_change_observer.cc +++ b/ui/display/manager/chromeos/display_change_observer.cc
@@ -293,8 +293,6 @@ const auto& cached_displays = display_configurator_->cached_displays(); if (!cached_displays.empty()) OnDisplayModeChanged(cached_displays); - else - VLOG(1) << "Not updating touchscreen associations"; } // static
diff --git a/ui/display/manager/chromeos/touchscreen_util.cc b/ui/display/manager/chromeos/touchscreen_util.cc index 31dbf2f6..aaa0996 100644 --- a/ui/display/manager/chromeos/touchscreen_util.cc +++ b/ui/display/manager/chromeos/touchscreen_util.cc
@@ -276,7 +276,7 @@ AssociateToSingleDisplay(&displays, &devices); for (const ManagedDisplayInfo* display : displays) - LOG(WARNING) << "Unmatched display " << display->name(); + VLOG(2) << "Unmatched display " << display->name(); for (const ui::TouchscreenDevice* device : devices) LOG(WARNING) << "Unmatched device " << device->name; }
diff --git a/ui/views/controls/slider.cc b/ui/views/controls/slider.cc index 219ebf6c..eacd6aa2 100644 --- a/ui/views/controls/slider.cc +++ b/ui/views/controls/slider.cc
@@ -243,14 +243,26 @@ } bool Slider::OnKeyPressed(const ui::KeyEvent& event) { - float new_value = value_; - if (event.key_code() == ui::VKEY_LEFT) - new_value -= keyboard_increment_; - else if (event.key_code() == ui::VKEY_RIGHT) - new_value += keyboard_increment_; - else - return false; - SetValueInternal(new_value, VALUE_CHANGED_BY_USER); + int direction = 1; + switch (event.key_code()) { + case ui::VKEY_LEFT: + direction = base::i18n::IsRTL() ? 1 : -1; + break; + case ui::VKEY_RIGHT: + direction = base::i18n::IsRTL() ? -1 : 1; + break; + case ui::VKEY_UP: + direction = 1; + break; + case ui::VKEY_DOWN: + direction = -1; + break; + + default: + return false; + } + SetValueInternal(value_ + direction * keyboard_increment_, + VALUE_CHANGED_BY_USER); return true; }
diff --git a/ui/views/controls/slider_unittest.cc b/ui/views/controls/slider_unittest.cc index 44893c9..6bd6706 100644 --- a/ui/views/controls/slider_unittest.cc +++ b/ui/views/controls/slider_unittest.cc
@@ -262,10 +262,8 @@ // Scroll below the minimum. slider()->SetValue(0.5); event_generator()->GestureScrollSequence( - gfx::Point(0.5 * max_x(), 0.5 * max_y()), - gfx::Point(0, 0), - base::TimeDelta::FromMilliseconds(10), - 5 /* steps */); + gfx::Point(0.5 * max_x(), 0.5 * max_y()), gfx::Point(0, 0), + base::TimeDelta::FromMilliseconds(10), 5 /* steps */); EXPECT_EQ(0, slider()->value()); // Scroll above the maximum. @@ -278,10 +276,9 @@ // Scroll somewhere in the middle. slider()->SetValue(0.25); event_generator()->GestureScrollSequence( - gfx::Point(0.25 * max_x(), 0.25 * max_y()), - gfx::Point(0.75 * max_x(), 0.75 * max_y()), - base::TimeDelta::FromMilliseconds(10), - 5 /* steps */); + gfx::Point(0.25 * max_x(), 0.25 * max_y()), + gfx::Point(0.75 * max_x(), 0.75 * max_y()), + base::TimeDelta::FromMilliseconds(10), 5 /* steps */); EXPECT_NEAR(0.75, slider()->value(), 0.03); } @@ -296,6 +293,33 @@ slider()->SetValue(value); event_generator()->PressKey(ui::VKEY_LEFT, 0); EXPECT_LT(slider()->value(), value); + + slider()->SetValue(value); + event_generator()->PressKey(ui::VKEY_UP, 0); + EXPECT_GT(slider()->value(), value); + + slider()->SetValue(value); + event_generator()->PressKey(ui::VKEY_DOWN, 0); + EXPECT_LT(slider()->value(), value); + + // RTL reverse left/right but not up/down. + base::i18n::SetICUDefaultLocale("he"); + EXPECT_TRUE(base::i18n::IsRTL()); + + event_generator()->PressKey(ui::VKEY_RIGHT, 0); + EXPECT_LT(slider()->value(), value); + + slider()->SetValue(value); + event_generator()->PressKey(ui::VKEY_LEFT, 0); + EXPECT_GT(slider()->value(), value); + + slider()->SetValue(value); + event_generator()->PressKey(ui::VKEY_UP, 0); + EXPECT_GT(slider()->value(), value); + + slider()->SetValue(value); + event_generator()->PressKey(ui::VKEY_DOWN, 0); + EXPECT_LT(slider()->value(), value); } // Verifies the correct SliderListener events are raised for a tap gesture.