diff --git a/.clang-format b/.clang-format index cd49686..6fdf1dc 100644 --- a/.clang-format +++ b/.clang-format
@@ -6,8 +6,3 @@ # 'vector<vector<int>>'. ('Auto' means that clang-format will only use # 'int>>' if the file already contains at least one such instance.) Standard: Cpp11 - ---- -Language: Java -# See http://crbug.com/429372 for information about this section. -Cpp11BracedListStyle: false # but see http://llvm.org/PR21457
diff --git a/.gitignore b/.gitignore index 541d44e..1020344 100644 --- a/.gitignore +++ b/.gitignore
@@ -365,6 +365,7 @@ /third_party/skia /third_party/smhasher/src /third_party/snappy/src +/third_party/stp/src /third_party/swiftshader/include/ /third_party/swig /third_party/syzygy
diff --git a/AUTHORS b/AUTHORS index ffb1d7fb..97f7c6fc 100644 --- a/AUTHORS +++ b/AUTHORS
@@ -75,6 +75,7 @@ Bruno Calvignac <bruno@flock.com> Bruno de Oliveira Abinader <bruno.d@partner.samsung.com> Bryan Donlan <bdonlan@gmail.com> +Byoungkwon Ko <gogag2@gmail.com> Byungwoo Lee <bw80.lee@samsung.com> Caio Marcelo de Oliveira Filho <caio.de.oliveira.filho@intel.com> Caitlin Potter <caitpotter88@gmail.com> @@ -378,6 +379,7 @@ Raman Tenneti <raman.tenneti@gmail.com> Ramkumar Gokarnesan <ramkumar.gokarnesan@gmail.com> Ramkumar Ramachandra <artagnon@gmail.com> +Ramya Vadlamudi <ramya.v@samsung.com> Randy Posynick <randy.posynick@gmail.com> Raphael Kubo da Costa <raphael.kubo.da.costa@intel.com> Ravi Phaneendra Kasibhatla <r.kasibhatla@samsung.com>
diff --git a/BUILD.gn b/BUILD.gn index 1e2070c..4a7b704 100644 --- a/BUILD.gn +++ b/BUILD.gn
@@ -192,7 +192,6 @@ "//third_party/android_tools:android_support_v13_java", "//third_party/android_tools:android_support_v7_appcompat_java", "//third_party/android_tools:android_support_v7_mediarouter_java", - "//third_party/eyesfree:eyesfree_java", ] if (has_chrome_android_internal) {
diff --git a/DEPS b/DEPS index 1d4f395..da0489c 100644 --- a/DEPS +++ b/DEPS
@@ -36,20 +36,20 @@ 'libcxx_revision': '48198f9110397fff47fe7c37cbfa296be7d44d3d', 'libcxxabi_revision': '4ad1009ab3a59fa7a6896d74d5e4de5885697f95', 'webkit_trunk': 'http://src.chromium.org/blink/trunk', - 'webkit_revision': '497bc655a8a7eafc9de934e6d785f8c101315722', # from svn revision 186207 + 'webkit_revision': 'da23095a0f46cf39a4613189675be3a92d560e19', # from svn revision 186353 'chromium_git': 'https://chromium.googlesource.com', 'chromiumos_git': 'https://chromium.googlesource.com/chromiumos', 'pdfium_git': 'https://pdfium.googlesource.com', 'skia_git': 'https://skia.googlesource.com', 'boringssl_git': 'https://boringssl.googlesource.com', - 'libvpx_revision': '429874c73d11608785ebcb5c2197461a9fc48306', + 'libvpx_revision': '64bec311643752b040741ef8b2d293e75c31218a', 'sfntly_revision': '1bdaae8fc788a5ac8936d68bf24f37d977a13dac', - 'skia_revision': '1dbd816ea6fa5027c922c1df3a09889baed3a31b', + 'skia_revision': 'd476a176b774c387b242fa8fb2a9296d722c34aa', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and V8 without interference from each other. 'v8_branch': 'trunk', - 'v8_revision': '470c87fca260551fc2aec6ffa9cc38bef286de69', + 'v8_revision': '3979878445f3617748da7d6e5f818b3a4f73853c', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling WebRTC # and V8 without interference from each other. @@ -64,7 +64,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling build tools # and whatever else without interference from each other. - 'buildtools_revision': '6ea835db27479b9a5742e48b5e4466af7c2534ff', + 'buildtools_revision': 'ded32942a1ebfddff0ba1231898fc4f6c7faacec', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. @@ -76,7 +76,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling BoringSSL # and whatever else without interference from each other. - 'boringssl_revision': '69a01608f33ab6fe2c3485d94aef1fe9eacf5364', + 'boringssl_revision': '00505ec2e1e4c3047b4f61a306f2ac1372fa7640', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling nss # and whatever else without interference from each other. @@ -109,7 +109,7 @@ deps = { 'src/breakpad/src': - Var('chromium_git') + '/external/google-breakpad/src.git' + '@' + '3ea146d00576294887aed86e25c5a5f105216a35', # from svn revision 1405 + Var('chromium_git') + '/external/google-breakpad/src.git' + '@' + '57c3d7c9f1f86525f120337b47d6ebd586215e1e', # from svn revision 1407 'src/buildtools': Var('chromium_git') + '/chromium/buildtools.git' + '@' + Var('buildtools_revision'), @@ -130,7 +130,7 @@ Var('chromium_git') + '/external/colorama.git' + '@' + '799604a1041e9b3bc5d2789ecbd7e8db2e18e6b8', 'src/third_party/trace-viewer': - Var('chromium_git') + '/external/trace-viewer.git' + '@' + '0b1ceb837137901b6f5ae55be61c29d28b2c13a4', + Var('chromium_git') + '/external/trace-viewer.git' + '@' + 'e323952e58bcc288b754ca8453229f0c0a141622', 'src/third_party/WebKit': Var('chromium_git') + '/chromium/blink.git' + '@' + Var('webkit_revision'), @@ -445,6 +445,9 @@ # Used for embedded builds. CrOS & Linux use the system version. 'src/third_party/fontconfig/src': Var('chromium_git') + '/external/fontconfig.git' + '@' + 'f16c3118e25546c1b749f9823c51827a60aeb5c1', + + 'src/third_party/stp/src': + Var('chromium_git') + '/external/github.com/stp/stp.git' + '@' + 'fc94a599207752ab4d64048204f0c88494811b62', }, 'android': { 'src/third_party/android_protobuf/src': @@ -456,7 +459,7 @@ Var('chromium_git') + '/external/android_webview_glue.git' + '@' + '4e0495ed16a0da2afa1d16bc34a71345172a258f', 'src/third_party/android_tools': - Var('chromium_git') + '/android_tools.git' + '@' + '4c47ef63519d579b9ac029fcb6dcc81e38d82984', + Var('chromium_git') + '/android_tools.git' + '@' + '4f723e2a5fa5b7b8a198072ac19b92344be2b271', 'src/third_party/apache-mime4j': Var('chromium_git') + '/chromium/deps/apache-mime4j.git' + '@' + '28cb1108bff4b6cf0a2e86ff58b3d025934ebe3a', @@ -491,8 +494,6 @@ 'src/third_party/lss': Var('chromium_git') + '/external/linux-syscall-support/lss.git' + '@' + Var('lss_revision'), - 'src/third_party/eyesfree/src/android/java/src/com/googlecode/eyesfree/braille': - Var('chromium_git') + '/external/eyes-free/braille/client/src/com/googlecode/eyesfree/braille.git' + '@' + '77bf6edb0138e3a38a2772248696f130dab45e34', }, }
diff --git a/PRESUBMIT.py b/PRESUBMIT.py index 90d1df4..6762e27 100644 --- a/PRESUBMIT.py +++ b/PRESUBMIT.py
@@ -357,6 +357,53 @@ return [output_api.PresubmitPromptWarning('UNIT_TEST is only for headers.\n' + '\n'.join(problems))] +def _CheckUmaHistogramChanges(input_api, output_api): + """Check that UMA histogram names in touched lines can still be found in other + lines of the patch or in histograms.xml. Note that this check would not catch + the reverse: changes in histograms.xml not matched in the code itself.""" + + touched_histograms = [] + histograms_xml_modifications = [] + pattern = input_api.re.compile('UMA_HISTOGRAM.*\("(.*)"') + for f in input_api.AffectedFiles(): + # If histograms.xml itself is modified, keep the modified lines for later. + if (f.LocalPath().endswith(('histograms.xml'))): + histograms_xml_modifications = f.ChangedContents() + continue + if (not f.LocalPath().endswith(('cc', 'mm', 'cpp'))): + continue + for line_num, line in f.ChangedContents(): + found = pattern.search(line) + if found: + touched_histograms.append([found.group(1), f, line_num]) + + # Search for the touched histogram names in the local modifications to + # histograms.xml, and if not found on the base file. + problems = [] + for histogram_name, f, line_num in touched_histograms: + histogram_name_found = False + for line_num, line in histograms_xml_modifications: + if histogram_name in line: + histogram_name_found = True; + break; + if histogram_name_found: + continue + + with open('tools/metrics/histograms/histograms.xml') as histograms_xml: + for line in histograms_xml: + if histogram_name in line: + histogram_name_found = True; + break; + if histogram_name_found: + continue + problems.append(' [%s:%d] %s' % (f.LocalPath(), line_num, histogram_name)) + + if not problems: + return [] + return [output_api.PresubmitPromptWarning('Some UMA_HISTOGRAM lines have ' + 'been modified and the associated histogram name has no match in either ' + 'metrics/histograms.xml or the modifications of it:', problems)] + def _CheckNoNewWStrings(input_api, output_api): """Checks to make sure we don't introduce use of wstrings.""" @@ -1520,6 +1567,7 @@ results.extend(_CommonChecks(input_api, output_api)) results.extend(_CheckValidHostsInDEPS(input_api, output_api)) results.extend(_CheckJavaStyle(input_api, output_api)) + results.extend(_CheckUmaHistogramChanges(input_api, output_api)) return results
diff --git a/PRESUBMIT_test.py b/PRESUBMIT_test.py index 2f37708..1c971917 100755 --- a/PRESUBMIT_test.py +++ b/PRESUBMIT_test.py
@@ -346,6 +346,28 @@ self.assertTrue('3' in errors[1]) self.assertTrue('5' in errors[2]) +class UmaHistogramChangeMatchedOrNotTest(unittest.TestCase): + def testTypicalNotMatchedChange(self): + diff = ['UMA_HISTOGRAM_BOOL("Bla.Foo.Dummy", true)'] + mock_input_api = MockInputApi() + mock_input_api.files = [MockFile('some/path/foo.cc', diff)] + warnings = PRESUBMIT._CheckUmaHistogramChanges(mock_input_api, + MockOutputApi()) + self.assertEqual(1, len(warnings)) + self.assertEqual('warning', warnings[0].type) + + def testTypicalCorrectlyMatchedChange(self): + diff_cc = ['UMA_HISTOGRAM_BOOL("Bla.Foo.Dummy", true)'] + diff_xml = ['<histogram name="Bla.Foo.Dummy"> </histogram>'] + mock_input_api = MockInputApi() + mock_input_api.files = [ + MockFile('some/path/foo.cc', diff_cc), + MockFile('tools/metrics/histograms/histograms.xml', diff_xml), + ] + warnings = [] + warnings = PRESUBMIT._CheckUmaHistogramChanges(mock_input_api, + MockOutputApi()) + self.assertEqual(0, len(warnings)) class BadExtensionsTest(unittest.TestCase): def testBadRejFile(self):
diff --git a/WATCHLISTS b/WATCHLISTS index 89a4b43..b260893 100644 --- a/WATCHLISTS +++ b/WATCHLISTS
@@ -561,9 +561,6 @@ 'filepath': 'chrome/browser/plugin|chrome/plugin/|'\ 'chrome/common/plugin|webkit/glue/webplugin|webkit/glue/plugins/', }, - 'policy_templates': { - 'filepath': 'components/policy/resources/policy_templates.json', - }, 'predictors': { 'filepath': 'predictors', }, @@ -891,7 +888,7 @@ 'drive_resource_metadata': ['hashimoto+watch@chromium.org'], 'eme': ['eme-reviews@chromium.org'], 'enhanced_bookmarks': ['noyau+watch@chromium.org'], - 'events': ['tdresser+watch@chromium.org'], + 'events': ['tdresser+watch@chromium.org', 'jdduke+watch@chromium.org'], 'extension': ['chromium-apps-reviews@chromium.org', 'extensions-reviews@chromium.org'], 'fileapi': ['kinuko+fileapi@chromium.org', @@ -972,7 +969,6 @@ 'tzik@chromium.org'], 'plugin': ['jam@chromium.org', 'stuartmorgan+watch@chromium.org'], - 'policy_templates': ['joaodasilva+watch@chromium.org'], 'predictors': ['shishir+watch@chromium.org'], 'prepopulated_engines': ['vasilii+watch@chromium.org'], 'prerender': ['cbentzel+watch@chromium.org', 'tburkard+watch@chromium.org',
diff --git a/android_webview/common/aw_crash_handler.cc b/android_webview/common/aw_crash_handler.cc index a637298..fbd4285 100644 --- a/android_webview/common/aw_crash_handler.cc +++ b/android_webview/common/aw_crash_handler.cc
@@ -6,6 +6,9 @@ #include <android/log.h> #include <signal.h> +#include <sys/prctl.h> +#include <sys/syscall.h> +#include <unistd.h> #include "base/logging.h" @@ -27,6 +30,14 @@ if (g_crash_msg_ptr != NULL) __android_log_write(ANDROID_LOG_ERROR, "chromium", g_crash_msg_ptr); + // Detect if some buggy code in the embedder did reinstall the handler using + // signal() instead of sigaction() (which would cause |info| to be invalid). + struct sigaction cur_handler; + if (sigaction(sig, NULL, &cur_handler) != 0 || + (cur_handler.sa_flags & SA_SIGINFO) == 0) { + info = NULL; + } + // We served our purpose. Now restore the old crash handlers. If the embedder // did register a custom crash handler, it will be invoked by the kernel after // this function returns. Otherwise, this will end up invoking the default @@ -36,6 +47,17 @@ signal(kExceptionSignals[i], SIG_DFL); } } + + if ((info != NULL && info->si_pid) || sig == SIGABRT) { + // This signal was triggered by somebody sending us the signal with kill(). + // In order to retrigger it, we have to queue a new signal by calling + // kill() ourselves. The special case (si_pid == 0 && sig == SIGABRT) is + // due to the kernel sending a SIGABRT from a user request via SysRQ. + if (syscall(__NR_tgkill, getpid(), syscall(__NR_gettid), sig) < 0) { + // If we failed to kill ourselves resort to terminating uncleanly. + exit(1); + } + } } } // namespace @@ -65,6 +87,7 @@ memset(&sa, 0, sizeof(sa)); sigemptyset(&sa.sa_mask); + // Mask all exception signals when we're handling one of them. for (uint32_t i = 0; i < arraysize(kExceptionSignals); ++i) sigaddset(&sa.sa_mask, kExceptionSignals[i]);
diff --git a/android_webview/java_library_common.mk b/android_webview/java_library_common.mk index b73a12f9..56f36ac2 100644 --- a/android_webview/java_library_common.mk +++ b/android_webview/java_library_common.mk
@@ -47,6 +47,8 @@ $(call intermediates-dir-for,GYP,shared)/enums/bitmap_format_java/org/chromium/ui/gfx/BitmapFormat.java \ $(call intermediates-dir-for,GYP,shared)/enums/cert_verify_status_android_java/org/chromium/net/CertVerifyStatusAndroid.java \ $(call intermediates-dir-for,GYP,shared)/enums/certificate_mime_types_java/org/chromium/net/CertificateMimeType.java \ +$(call intermediates-dir-for,GYP,shared)/enums/network_change_notifier_types_java/org/chromium/net/ConnectionSubtype.java \ +$(call intermediates-dir-for,GYP,shared)/enums/network_change_notifier_types_java/org/chromium/net/ConnectionType.java \ $(call intermediates-dir-for,GYP,shared)/enums/content_gamepad_mapping/org/chromium/content/browser/input/CanonicalAxisIndex.java \ $(call intermediates-dir-for,GYP,shared)/enums/content_gamepad_mapping/org/chromium/content/browser/input/CanonicalButtonIndex.java \ $(call intermediates-dir-for,GYP,shared)/enums/gesture_event_type_java/org/chromium/content/browser/GestureEventType.java \
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/PostMessageTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/PostMessageTest.java index 7d5b0ae..5d7df38 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/PostMessageTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/PostMessageTest.java
@@ -12,23 +12,15 @@ import org.chromium.android_webview.AwContents; import org.chromium.android_webview.MessageChannel; +import org.chromium.android_webview.test.util.CommonResources; import org.chromium.base.test.util.Feature; +import org.chromium.net.test.util.TestWebServer; /** * The tests for content postMessage API. */ public class PostMessageTest extends AwTestBase { - private static final String TEST_PAGE = - "<!DOCTYPE html><html><body>" - + " <script type=\"text/javascript\">" - + " onmessage = function (e) {" - + " messageObject.setMessageParams(e.data, e.origin, e.ports);" - + " }" - + " </script>" - + "</body></html>"; - - private static final String MESSAGE = "Foo"; private static final String SOURCE_ORIGIN = "android_webview"; // Inject to the page to verify received messages. @@ -75,6 +67,7 @@ private TestAwContentsClient mContentsClient; private AwTestContainerView mTestContainerView; private AwContents mAwContents; + private TestWebServer mWebServer; @Override protected void setUp() throws Exception { @@ -96,25 +89,48 @@ } catch (Throwable t) { throw new RuntimeException(t); } + mWebServer = TestWebServer.start(); + } + + @Override + protected void tearDown() throws Exception { + mWebServer.shutdown(); + super.tearDown(); + } + + private static final String WEBVIEW_MESSAGE = "from_webview"; + + private static final String TEST_PAGE = + "<!DOCTYPE html><html><body>" + + " <script type=\"text/javascript\">" + + " onmessage = function (e) {" + + " messageObject.setMessageParams(e.data, e.origin, e.ports);" + + " }" + + " </script>" + + "</body></html>"; + + private void loadPage(String page) throws Throwable { + final String url = mWebServer.setResponse("/test.html", page, + CommonResources.getTextHtmlHeaders(true)); OnPageFinishedHelper onPageFinishedHelper = mContentsClient.getOnPageFinishedHelper(); int currentCallCount = onPageFinishedHelper.getCallCount(); - // Load test page - loadDataSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), - TEST_PAGE, "text/html", false); + loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), url); onPageFinishedHelper.waitForCallback(currentCallCount); } @SmallTest @Feature({"AndroidWebView", "Android-PostMessage"}) public void testPostMessageToMainFrame() throws Throwable { + loadPage(TEST_PAGE); runTestOnUiThread(new Runnable() { @Override public void run() { - mAwContents.postMessageToFrame(null, MESSAGE, SOURCE_ORIGIN, "*", null); + mAwContents.postMessageToFrame(null, WEBVIEW_MESSAGE, SOURCE_ORIGIN, + mWebServer.getBaseUrl(), null); } }); mMessageObject.waitForMessage(); - assertEquals(MESSAGE, mMessageObject.getData()); + assertEquals(WEBVIEW_MESSAGE, mMessageObject.getData()); assertEquals(SOURCE_ORIGIN, mMessageObject.getOrigin()); } @@ -125,23 +141,80 @@ @SmallTest @Feature({"AndroidWebView", "Android-PostMessage"}) public void testCreateChannel() throws Throwable { + loadPage(TEST_PAGE); runTestOnUiThread(new Runnable() { @Override public void run() { ValueCallback<MessageChannel> callback = new ValueCallback<MessageChannel>() { @Override public void onReceiveValue(MessageChannel channel) { - mAwContents.postMessageToFrame(null, MESSAGE, SOURCE_ORIGIN, "*", - new int[]{channel.port2()}); + mAwContents.postMessageToFrame(null, WEBVIEW_MESSAGE, SOURCE_ORIGIN, + mWebServer.getBaseUrl(), new int[]{channel.port2()}); } }; mAwContents.createMessageChannel(callback); } }); mMessageObject.waitForMessage(); - assertEquals(MESSAGE, mMessageObject.getData()); + assertEquals(WEBVIEW_MESSAGE, mMessageObject.getData()); assertEquals(SOURCE_ORIGIN, mMessageObject.getOrigin()); // verify that one message port is received. assertEquals(1, mMessageObject.getPorts().length); } + + private static final String WORKER_MESSAGE = "from_worker"; + + // Listen for messages. Pass port 1 to worker and use port 2 to receive messages from + // from worker. + private static final String TEST_PAGE_FOR_PORT_TRANSFER = + "<!DOCTYPE html><html><body>" + + " <script type=\"text/javascript\">" + + " var worker = new Worker(\"worker.js\");" + + " onmessage = function (e) {" + + " if (e.data == \"" + WEBVIEW_MESSAGE + "\") {" + + " worker.postMessage(\"worker_port\", [e.ports[0]]);" + + " var messageChannelPort = e.ports[1];" + + " messageChannelPort.onmessage = receiveWorkerMessage;" + + " }" + + " };" + + " function receiveWorkerMessage(e) {" + + " if (e.data == \"" + WORKER_MESSAGE + "\") {" + + " messageObject.setMessageParams(e.data, e.origin, e.ports);" + + " }" + + " };" + + " </script>" + + "</body></html>"; + + private static final String WORKER_SCRIPT = + "onmessage = function(e) {" + + " if (e.data == \"worker_port\") {" + + " var toWindow = e.ports[0];" + + " toWindow.postMessage(\"" + WORKER_MESSAGE + "\");" + + " toWindow.start();" + + " }" + + "}"; + + @SmallTest + @Feature({"AndroidWebView", "Android-PostMessage"}) + public void testTransferPortsToWorker() throws Throwable { + mWebServer.setResponse("/worker.js", WORKER_SCRIPT, + CommonResources.getTextJavascriptHeaders(true)); + loadPage(TEST_PAGE_FOR_PORT_TRANSFER); + runTestOnUiThread(new Runnable() { + @Override + public void run() { + ValueCallback<MessageChannel> callback = new ValueCallback<MessageChannel>() { + @Override + public void onReceiveValue(MessageChannel channel) { + mAwContents.postMessageToFrame(null, WEBVIEW_MESSAGE, SOURCE_ORIGIN, + mWebServer.getBaseUrl(), + new int[]{channel.port1(), channel.port2()}); + } + }; + mAwContents.createMessageChannel(callback); + } + }); + mMessageObject.waitForMessage(); + assertEquals(WORKER_MESSAGE, mMessageObject.getData()); + } }
diff --git a/android_webview/lib/main/aw_main_delegate.cc b/android_webview/lib/main/aw_main_delegate.cc index c28e3d5a..8fc7ff5f 100644 --- a/android_webview/lib/main/aw_main_delegate.cc +++ b/android_webview/lib/main/aw_main_delegate.cc
@@ -82,9 +82,6 @@ // This is needed for sharing textures across the different GL threads. cl->AppendSwitch(switches::kEnableThreadedTextureMailboxes); - // We need to support input event handling for the scheduler. crbug.com/431598 - cl->AppendSwitch(switches::kDisableBlinkScheduler); - return false; }
diff --git a/android_webview/libwebviewchromium.gypi b/android_webview/libwebviewchromium.gypi index dfaf508..099ca4b 100644 --- a/android_webview/libwebviewchromium.gypi +++ b/android_webview/libwebviewchromium.gypi
@@ -27,6 +27,7 @@ '../media/media.gyp:media_android_imageformat', '../net/net.gyp:cert_verify_status_android_java', '../net/net.gyp:certificate_mime_types_java', + '../net/net.gyp:network_change_notifier_types_java', '../net/net.gyp:net_errors_java', '../net/net.gyp:private_key_types_java', '../ui/android/ui_android.gyp:bitmap_format_java',
diff --git a/android_webview/native/aw_autofill_client.cc b/android_webview/native/aw_autofill_client.cc index 31c21a8e..95f3fd5d 100644 --- a/android_webview/native/aw_autofill_client.cc +++ b/android_webview/native/aw_autofill_client.cc
@@ -158,7 +158,9 @@ } void AwAutofillClient::DetectAccountCreationForms( + content::RenderFrameHost* rfh, const std::vector<autofill::FormStructure*>& forms) { + } void AwAutofillClient::DidFillOrPreviewField( @@ -166,6 +168,10 @@ const base::string16& profile_full_name) { } +void AwAutofillClient::OnFirstUserGestureObserved() { + NOTIMPLEMENTED(); +} + void AwAutofillClient::SuggestionSelected(JNIEnv* env, jobject object, jint position) {
diff --git a/android_webview/native/aw_autofill_client.h b/android_webview/native/aw_autofill_client.h index 10a2310..c328d56 100644 --- a/android_webview/native/aw_autofill_client.h +++ b/android_webview/native/aw_autofill_client.h
@@ -84,10 +84,12 @@ virtual void HideAutofillPopup() override; virtual bool IsAutocompleteEnabled() override; virtual void DetectAccountCreationForms( + content::RenderFrameHost* rfh, const std::vector<autofill::FormStructure*>& forms) override; virtual void DidFillOrPreviewField( const base::string16& autofilled_value, const base::string16& profile_full_name) override; + virtual void OnFirstUserGestureObserved() override; void SuggestionSelected(JNIEnv* env, jobject obj, jint position);
diff --git a/android_webview/native/aw_contents.cc b/android_webview/native/aw_contents.cc index 969b2af..50c6b36 100644 --- a/android_webview/native/aw_contents.cc +++ b/android_webview/native/aw_contents.cc
@@ -43,7 +43,7 @@ #include "base/pickle.h" #include "base/strings/string16.h" #include "base/supports_user_data.h" -#include "components/autofill/content/browser/content_autofill_driver.h" +#include "components/autofill/content/browser/content_autofill_driver_factory.h" #include "components/autofill/core/browser/autofill_manager.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h" @@ -72,7 +72,7 @@ struct AwDrawSWFunctionTable; -using autofill::ContentAutofillDriver; +using autofill::ContentAutofillDriverFactory; using autofill::AutofillManager; using base::android::AttachCurrentThread; using base::android::ConvertJavaStringToUTF16; @@ -241,7 +241,7 @@ InitAutofillIfNecessary(enabled); // We need to check for the existence, since autofill_manager_delegate // may not be created when the setting is false. - if (ContentAutofillDriver::FromWebContents(web_contents_.get())) { + if (AwAutofillClient::FromWebContents(web_contents_.get())) { AwAutofillClient::FromWebContents(web_contents_.get())-> SetSaveFormData(enabled); } @@ -257,17 +257,16 @@ // Do not initialize if the feature is not enabled. if (!enabled) return; - // Check if the autofill driver already exists. + // Check if the autofill driver factory already exists. content::WebContents* web_contents = web_contents_.get(); - if (ContentAutofillDriver::FromWebContents(web_contents)) + if (ContentAutofillDriverFactory::FromWebContents(web_contents)) return; AwBrowserContext::FromWebContents(web_contents)-> CreateUserPrefServiceIfNecessary(); AwAutofillClient::CreateForWebContents(web_contents); - ContentAutofillDriver::CreateForWebContentsAndDelegate( - web_contents, - AwAutofillClient::FromWebContents(web_contents), + ContentAutofillDriverFactory::CreateForWebContentsAndDelegate( + web_contents, AwAutofillClient::FromWebContents(web_contents), base::android::GetDefaultLocale(), AutofillManager::DISABLE_AUTOFILL_DOWNLOAD_MANAGER); }
diff --git a/android_webview/renderer/aw_content_renderer_client.cc b/android_webview/renderer/aw_content_renderer_client.cc index 5114d0f..24349cd 100644 --- a/android_webview/renderer/aw_content_renderer_client.cc +++ b/android_webview/renderer/aw_content_renderer_client.cc
@@ -133,6 +133,12 @@ RenderThread::Get()->Send(new AwViewHostMsg_SubFrameCreated( parent_frame->GetRoutingID(), render_frame->GetRoutingID())); } + + // TODO(sgurun) do not create a password autofill agent (change + // autofill agent to store a weakptr). + autofill::PasswordAutofillAgent* password_autofill_agent = + new autofill::PasswordAutofillAgent(render_frame); + new autofill::AutofillAgent(render_frame, password_autofill_agent, NULL); } void AwContentRendererClient::RenderViewCreated( @@ -140,11 +146,6 @@ AwRenderViewExt::RenderViewCreated(render_view); new printing::PrintWebViewHelper(render_view); - // TODO(sgurun) do not create a password autofill agent (change - // autofill agent to store a weakptr). - autofill::PasswordAutofillAgent* password_autofill_agent = - new autofill::PasswordAutofillAgent(render_view); - new autofill::AutofillAgent(render_view, password_autofill_agent, NULL); } bool AwContentRendererClient::HasErrorPage(int http_status_code,
diff --git a/ash/display/display_change_observer_chromeos.cc b/ash/display/display_change_observer_chromeos.cc index ca05008..0c73b14e 100644 --- a/ash/display/display_change_observer_chromeos.cc +++ b/ash/display/display_change_observer_chromeos.cc
@@ -44,7 +44,7 @@ }; const DeviceScaleFactorDPIThreshold kThresholdTable[] = { - {180.0f, 2.0f}, + {200.0f, 2.0f}, {150.0f, 1.25f}, {0.0f, 1.0f}, };
diff --git a/ash/display/display_change_observer_chromeos_unittest.cc b/ash/display/display_change_observer_chromeos_unittest.cc index 10ba54b..ad52e2e5 100644 --- a/ash/display/display_change_observer_chromeos_unittest.cc +++ b/ash/display/display_change_observer_chromeos_unittest.cc
@@ -319,24 +319,39 @@ EXPECT_EQ(0u, display_modes.size()); } +namespace { + +float ComputeDeviceScaleFactor(float diagonal_inch, + const gfx::Rect& resolution) { + // We assume that displays have square pixel. + float diagonal_pixel = std::sqrt(std::pow(resolution.width(), 2) + + std::pow(resolution.height(), 2)); + float dpi = diagonal_pixel / diagonal_inch; + return DisplayChangeObserver::FindDeviceScaleFactor(dpi); +} + +} // namespace + TEST_F(DisplayChangeObserverTest, FindDeviceScaleFactor) { - // 19.5" 1600x900 - EXPECT_EQ(1.0f, DisplayChangeObserver::FindDeviceScaleFactor(94.14f)); + EXPECT_EQ(1.0f, ComputeDeviceScaleFactor(19.5f, gfx::Rect(1600, 900))); // 21.5" 1920x1080 - EXPECT_EQ(1.0f, DisplayChangeObserver::FindDeviceScaleFactor(102.46f)); + EXPECT_EQ(1.0f, ComputeDeviceScaleFactor(21.5f, gfx::Rect(1920, 1080))); // 12.1" 1280x800 - EXPECT_EQ(1.0f, DisplayChangeObserver::FindDeviceScaleFactor(124.75f)); + EXPECT_EQ(1.0f, ComputeDeviceScaleFactor(12.1f, gfx::Rect(1280, 800))); + + // 11.6" 1920x1080 + EXPECT_EQ(1.25f, ComputeDeviceScaleFactor(11.6f, gfx::Rect(1920, 1080))); // 13.3" 1920x1080 - EXPECT_EQ(1.25f, DisplayChangeObserver::FindDeviceScaleFactor(157.35f)); + EXPECT_EQ(1.25f, ComputeDeviceScaleFactor(13.3f, gfx::Rect(1920, 1080))); // 14" 1920x1080 - EXPECT_EQ(1.25f, DisplayChangeObserver::FindDeviceScaleFactor(165.63f)); + EXPECT_EQ(1.25f, ComputeDeviceScaleFactor(14.0f, gfx::Rect(1920, 1080))); // 12.85" 2560x1700 - EXPECT_EQ(2.0f, DisplayChangeObserver::FindDeviceScaleFactor(239.15f)); + EXPECT_EQ(2.0f, ComputeDeviceScaleFactor(12.85f, gfx::Rect(2560, 1700))); // Erroneous values should still work. EXPECT_EQ(1.0f, DisplayChangeObserver::FindDeviceScaleFactor(-100.0f));
diff --git a/ash/shelf/shelf_view_unittest.cc b/ash/shelf/shelf_view_unittest.cc index bf7f21d9..c09acb4 100644 --- a/ash/shelf/shelf_view_unittest.cc +++ b/ash/shelf/shelf_view_unittest.cc
@@ -30,7 +30,6 @@ #include "ash/test/test_shelf_delegate.h" #include "ash/test/test_shelf_item_delegate.h" #include "base/basictypes.h" -#include "base/command_line.h" #include "base/compiler_specific.h" #include "base/memory/scoped_ptr.h" #include "base/strings/string_number_conversions.h" @@ -38,7 +37,6 @@ #include "ui/aura/window.h" #include "ui/aura/window_event_dispatcher.h" #include "ui/base/l10n/l10n_util.h" -#include "ui/base/ui_base_switches.h" #include "ui/compositor/layer.h" #include "ui/events/event.h" #include "ui/events/event_constants.h" @@ -290,8 +288,6 @@ ~ShelfViewTest() override {} void SetUp() override { - base::CommandLine::ForCurrentProcess()->AppendSwitch( - switches::kEnableTouchFeedback); AshTestBase::SetUp(); test::ShellTestApi test_api(Shell::GetInstance()); model_ = test_api.shelf_model(); @@ -1441,6 +1437,9 @@ ReplaceShelfDelegateForRipOffTest(); AddButtonsUntilOverflow(); + // Add one more button to prevent the overflow bubble to disappear upon + // dragging an item out on windows (flakiness, see crbug.com/436131). + AddAppShortcut(); // Show overflow bubble. test_api_->ShowOverflowBubble(); @@ -1658,6 +1657,9 @@ ReplaceShelfDelegateForRipOffTest(); AddButtonsUntilOverflow(); + // Add one more button to prevent the overflow bubble to disappear upon + // dragging an item out on windows (flakiness, see crbug.com/425097). + AddAppShortcut(); TestDraggingAnItemFromOverflowToShelf(false); TestDraggingAnItemFromOverflowToShelf(true);
diff --git a/ash/system/tray/system_tray_unittest.cc b/ash/system/tray/system_tray_unittest.cc index 5de14ea8..987d39b4 100644 --- a/ash/system/tray/system_tray_unittest.cc +++ b/ash/system/tray/system_tray_unittest.cc
@@ -18,11 +18,9 @@ #include "ash/system/tray/tray_popup_item_container.h" #include "ash/test/ash_test_base.h" #include "ash/wm/window_util.h" -#include "base/command_line.h" #include "base/run_loop.h" #include "base/strings/utf_string_conversions.h" #include "ui/aura/window.h" -#include "ui/base/ui_base_switches.h" #include "ui/base/ui_base_types.h" #include "ui/compositor/scoped_animation_duration_scale_mode.h" #include "ui/events/test/event_generator.h" @@ -146,20 +144,7 @@ } // namespace -class SystemTrayTest : public AshTestBase { - public: - SystemTrayTest() {} - ~SystemTrayTest() override {} - - void SetUp() override { - base::CommandLine::ForCurrentProcess()->AppendSwitch( - switches::kEnableTouchFeedback); - test::AshTestBase::SetUp(); - } - - private: - DISALLOW_COPY_AND_ASSIGN(SystemTrayTest); -}; +typedef AshTestBase SystemTrayTest; TEST_F(SystemTrayTest, SystemTrayDefaultView) { SystemTray* tray = GetSystemTray();
diff --git a/ash/system/tray/tray_details_view_unittest.cc b/ash/system/tray/tray_details_view_unittest.cc index 48f58ae4..da8f2f9 100644 --- a/ash/system/tray/tray_details_view_unittest.cc +++ b/ash/system/tray/tray_details_view_unittest.cc
@@ -15,11 +15,9 @@ #include "ash/system/tray/tray_details_view.h" #include "ash/system/tray/view_click_listener.h" #include "ash/test/ash_test_base.h" -#include "base/command_line.h" #include "base/run_loop.h" #include "grit/ash_strings.h" #include "ui/aura/window.h" -#include "ui/base/ui_base_switches.h" #include "ui/events/test/event_generator.h" #include "ui/views/view.h" #include "ui/views/widget/widget.h" @@ -110,12 +108,6 @@ footer()->content()); } - void SetUp() override { - base::CommandLine::ForCurrentProcess()->AppendSwitch( - switches::kEnableTouchFeedback); - test::AshTestBase::SetUp(); - } - private: DISALLOW_COPY_AND_ASSIGN(TrayDetailsViewTest); };
diff --git a/ash/system/web_notification/web_notification_tray_unittest.cc b/ash/system/web_notification/web_notification_tray_unittest.cc index 113ed21..03e693e 100644 --- a/ash/system/web_notification/web_notification_tray_unittest.cc +++ b/ash/system/web_notification/web_notification_tray_unittest.cc
@@ -19,12 +19,10 @@ #include "ash/test/status_area_widget_test_helper.h" #include "ash/test/test_system_tray_delegate.h" #include "ash/wm/window_state.h" -#include "base/command_line.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/window.h" -#include "ui/base/ui_base_switches.h" #include "ui/events/event.h" #include "ui/events/test/event_generator.h" #include "ui/gfx/display.h" @@ -94,12 +92,6 @@ WebNotificationTrayTest() {} ~WebNotificationTrayTest() override {} - void SetUp() override { - base::CommandLine::ForCurrentProcess()->AppendSwitch( - switches::kEnableTouchFeedback); - test::AshTestBase::SetUp(); - } - void TearDown() override { GetMessageCenter()->RemoveAllNotifications(false); test::AshTestBase::TearDown();
diff --git a/ash/touch/touch_transformer_controller.cc b/ash/touch/touch_transformer_controller.cc index 1a99505..c70ea85 100644 --- a/ash/touch/touch_transformer_controller.cc +++ b/ash/touch/touch_transformer_controller.cc
@@ -25,7 +25,7 @@ ui::TouchscreenDevice FindTouchscreenById(unsigned int id) { const std::vector<ui::TouchscreenDevice>& touchscreens = ui::DeviceDataManager::GetInstance()->touchscreen_devices(); - for (auto touchscreen : touchscreens) { + for (const auto& touchscreen : touchscreens) { if (touchscreen.id == id) return touchscreen; }
diff --git a/ash/wm/app_list_controller_unittest.cc b/ash/wm/app_list_controller_unittest.cc index d08a0f2f..39f2b77 100644 --- a/ash/wm/app_list_controller_unittest.cc +++ b/ash/wm/app_list_controller_unittest.cc
@@ -47,6 +47,9 @@ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); command_line->AppendSwitch(app_list::switches::kEnableCenteredAppList); } + + // Make the display big enough to hold the experimental app list. + UpdateDisplay("1024x768"); } bool AppListControllerTest::IsCentered() const { @@ -132,18 +135,19 @@ return; // Set up a screen with two displays (horizontally adjacent). - UpdateDisplay("800x600,800x600"); + UpdateDisplay("1024x768,1024x768"); aura::Window::Windows root_windows = Shell::GetAllRootWindows(); ASSERT_EQ(2u, root_windows.size()); aura::Window* secondary_window = root_windows[1]; - EXPECT_EQ("800,0 800x600", secondary_window->GetBoundsInScreen().ToString()); + EXPECT_EQ("1024,0 1024x768", + secondary_window->GetBoundsInScreen().ToString()); Shell::GetInstance()->ShowAppList(secondary_window); EXPECT_TRUE(Shell::GetInstance()->GetAppListTargetVisibility()); // Remove the secondary display. Shouldn't crash (http://crbug.com/368990). - UpdateDisplay("800x600"); + UpdateDisplay("1024x768"); // Updating the displays should close the app list. EXPECT_FALSE(Shell::GetInstance()->GetAppListTargetVisibility());
diff --git a/athena/extensions/chrome/extensions_delegate_impl.cc b/athena/extensions/chrome/extensions_delegate_impl.cc index feedc8e..47f9e89 100644 --- a/athena/extensions/chrome/extensions_delegate_impl.cc +++ b/athena/extensions/chrome/extensions_delegate_impl.cc
@@ -11,6 +11,7 @@ #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_util.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/extensions/app_launch_params.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" #include "extensions/browser/extension_registry.h" @@ -19,6 +20,7 @@ #include "extensions/common/extension_set.h" #include "extensions/common/extension_urls.h" #include "net/base/url_util.h" +#include "ui/base/window_open_disposition.h" namespace athena { namespace { @@ -58,11 +60,9 @@ if (!extensions::util::IsAppLaunchableWithoutEnabling(app_id, context)) return false; - int event_flags = 0; - AppLaunchParams params(Profile::FromBrowserContext(context), - extension, - event_flags, - chrome::HOST_DESKTOP_TYPE_ASH); + AppLaunchParams params(Profile::FromBrowserContext(context), extension, + CURRENT_TAB, chrome::HOST_DESKTOP_TYPE_ASH, + extensions::SOURCE_APP_LAUNCHER); // TODO(oshima): rename HOST_DESTOP_TYPE_ASH to non native desktop. if (app_id == extensions::kWebStoreAppId) {
diff --git a/athena/home/home_card_view.cc b/athena/home/home_card_view.cc index 48a02cf..133ad5c 100644 --- a/athena/home/home_card_view.cc +++ b/athena/home/home_card_view.cc
@@ -180,7 +180,6 @@ search_box_view_->SetBoundsRect(main_bounds); } - main_view_->UpdateSearchBoxVisibility(); if (state == HomeCard::VISIBLE_BOTTOM) { app_list::ContentsView* contents_view = main_view_->contents_view(); contents_view->SetActivePage(contents_view->GetPageIndexForState(
diff --git a/base/debug/proc_maps_linux_unittest.cc b/base/debug/proc_maps_linux_unittest.cc index c9f2267..cbc0dd0 100644 --- a/base/debug/proc_maps_linux_unittest.cc +++ b/base/debug/proc_maps_linux_unittest.cc
@@ -181,20 +181,19 @@ } } -TEST(ProcMapsTest, ReadProcMaps) { - std::string proc_maps; - ASSERT_TRUE(ReadProcMaps(&proc_maps)); - - std::vector<MappedMemoryRegion> regions; - ASSERT_TRUE(ParseProcMaps(proc_maps, ®ions)); - ASSERT_FALSE(regions.empty()); - +#if defined(ADDRESS_SANITIZER) +// AddressSanitizer may move local variables to a dedicated "fake stack" which +// is outside the stack region listed in /proc/self/maps. We disable ASan +// instrumentation for this function to force the variable to be local. +__attribute__((no_sanitize_address)) +#endif +void CheckProcMapsRegions(const std::vector<MappedMemoryRegion> ®ions) { // We should be able to find both the current executable as well as the stack - // mapped into memory. Use the address of |proc_maps| as a way of finding the + // mapped into memory. Use the address of |exe_path| as a way of finding the // stack. FilePath exe_path; EXPECT_TRUE(PathService::Get(FILE_EXE, &exe_path)); - uintptr_t address = reinterpret_cast<uintptr_t>(&proc_maps); + uintptr_t address = reinterpret_cast<uintptr_t>(&exe_path); bool found_exe = false; bool found_stack = false; bool found_address = false; @@ -246,6 +245,17 @@ } } +TEST(ProcMapsTest, ReadProcMaps) { + std::string proc_maps; + ASSERT_TRUE(ReadProcMaps(&proc_maps)); + + std::vector<MappedMemoryRegion> regions; + ASSERT_TRUE(ParseProcMaps(proc_maps, ®ions)); + ASSERT_FALSE(regions.empty()); + + CheckProcMapsRegions(regions); +} + TEST(ProcMapsTest, ReadProcMapsNonEmptyString) { std::string old_string("I forgot to clear the string"); std::string proc_maps(old_string);
diff --git a/base/prefs/mock_pref_change_callback.h b/base/prefs/mock_pref_change_callback.h index 422754a..3030fab1 100644 --- a/base/prefs/mock_pref_change_callback.h +++ b/base/prefs/mock_pref_change_callback.h
@@ -19,8 +19,7 @@ // |pref_name| in |prefs| matches |value|. If |value| is NULL, the matcher // checks that the value is not set. MATCHER_P3(PrefValueMatches, prefs, pref_name, value, "") { - const PrefService::Preference* pref = - prefs->FindPreference(pref_name.c_str()); + const PrefService::Preference* pref = prefs->FindPreference(pref_name); if (!pref) return false;
diff --git a/base/prefs/pref_change_registrar.cc b/base/prefs/pref_change_registrar.cc index 28ac3740..13193484 100644 --- a/base/prefs/pref_change_registrar.cc +++ b/base/prefs/pref_change_registrar.cc
@@ -23,12 +23,12 @@ service_ = service; } -void PrefChangeRegistrar::Add(const char* path, +void PrefChangeRegistrar::Add(const std::string& path, const base::Closure& obs) { Add(path, base::Bind(&PrefChangeRegistrar::InvokeUnnamedCallback, obs)); } -void PrefChangeRegistrar::Add(const char* path, +void PrefChangeRegistrar::Add(const std::string& path, const NamedChangeCallback& obs) { if (!service_) { NOTREACHED(); @@ -40,7 +40,7 @@ observers_[path] = obs; } -void PrefChangeRegistrar::Remove(const char* path) { +void PrefChangeRegistrar::Remove(const std::string& path) { DCHECK(IsObserved(path)); observers_.erase(path); @@ -50,7 +50,7 @@ void PrefChangeRegistrar::RemoveAll() { for (ObserverMap::const_iterator it = observers_.begin(); it != observers_.end(); ++it) { - service_->RemovePrefObserver(it->first.c_str(), this); + service_->RemovePrefObserver(it->first, this); } observers_.clear(); @@ -67,8 +67,7 @@ bool PrefChangeRegistrar::IsManaged() { for (ObserverMap::const_iterator it = observers_.begin(); it != observers_.end(); ++it) { - const PrefService::Preference* pref = - service_->FindPreference(it->first.c_str()); + const PrefService::Preference* pref = service_->FindPreference(it->first); if (pref && pref->IsManaged()) return true; }
diff --git a/base/prefs/pref_change_registrar.h b/base/prefs/pref_change_registrar.h index 70c22fe..acf0a684 100644 --- a/base/prefs/pref_change_registrar.h +++ b/base/prefs/pref_change_registrar.h
@@ -40,11 +40,11 @@ // the preference that is changing as its parameter. // // Only one observer may be registered per path. - void Add(const char* path, const base::Closure& obs); - void Add(const char* path, const NamedChangeCallback& obs); + void Add(const std::string& path, const base::Closure& obs); + void Add(const std::string& path, const NamedChangeCallback& obs); // Removes the pref observer registered for |path|. - void Remove(const char* path); + void Remove(const std::string& path); // Removes all observers that have been previously added with a call to Add. void RemoveAll();
diff --git a/base/prefs/pref_change_registrar_unittest.cc b/base/prefs/pref_change_registrar_unittest.cc index e9255a0..e449084 100644 --- a/base/prefs/pref_change_registrar_unittest.cc +++ b/base/prefs/pref_change_registrar_unittest.cc
@@ -27,10 +27,8 @@ MockPrefService() {} virtual ~MockPrefService() {} - MOCK_METHOD2(AddPrefObserver, - void(const char*, PrefObserver*)); - MOCK_METHOD2(RemovePrefObserver, - void(const char*, PrefObserver*)); + MOCK_METHOD2(AddPrefObserver, void(const std::string&, PrefObserver*)); + MOCK_METHOD2(RemovePrefObserver, void(const std::string&, PrefObserver*)); }; } // namespace
diff --git a/base/prefs/pref_member.cc b/base/prefs/pref_member.cc index 4fa616f4..8d80dd0 100644 --- a/base/prefs/pref_member.cc +++ b/base/prefs/pref_member.cc
@@ -25,23 +25,20 @@ Destroy(); } -void PrefMemberBase::Init(const char* pref_name, +void PrefMemberBase::Init(const std::string& pref_name, PrefService* prefs, const NamedChangeCallback& observer) { observer_ = observer; Init(pref_name, prefs); } -void PrefMemberBase::Init(const char* pref_name, - PrefService* prefs) { - DCHECK(pref_name); +void PrefMemberBase::Init(const std::string& pref_name, PrefService* prefs) { DCHECK(prefs); DCHECK(pref_name_.empty()); // Check that Init is only called once. prefs_ = prefs; pref_name_ = pref_name; // Check that the preference is registered. - DCHECK(prefs_->FindPreference(pref_name_.c_str())) - << pref_name << " not registered."; + DCHECK(prefs_->FindPreference(pref_name_)) << pref_name << " not registered."; // Add ourselves as a pref observer so we can keep our local value in sync. prefs_->AddPrefObserver(pref_name, this); @@ -49,7 +46,7 @@ void PrefMemberBase::Destroy() { if (prefs_ && !pref_name_.empty()) { - prefs_->RemovePrefObserver(pref_name_.c_str(), this); + prefs_->RemovePrefObserver(pref_name_, this); prefs_ = NULL; } } @@ -72,8 +69,7 @@ void PrefMemberBase::UpdateValueFromPref(const base::Closure& callback) const { VerifyValuePrefName(); - const PrefService::Preference* pref = - prefs_->FindPreference(pref_name_.c_str()); + const PrefService::Preference* pref = prefs_->FindPreference(pref_name_); DCHECK(pref); if (!internal()) CreateInternal(); @@ -158,7 +154,7 @@ template <> void PrefMember<bool>::UpdatePref(const bool& value) { - prefs()->SetBoolean(pref_name().c_str(), value); + prefs()->SetBoolean(pref_name(), value); } template <> @@ -169,7 +165,7 @@ template <> void PrefMember<int>::UpdatePref(const int& value) { - prefs()->SetInteger(pref_name().c_str(), value); + prefs()->SetInteger(pref_name(), value); } template <> @@ -180,7 +176,7 @@ template <> void PrefMember<double>::UpdatePref(const double& value) { - prefs()->SetDouble(pref_name().c_str(), value); + prefs()->SetDouble(pref_name(), value); } template <> @@ -191,7 +187,7 @@ template <> void PrefMember<std::string>::UpdatePref(const std::string& value) { - prefs()->SetString(pref_name().c_str(), value); + prefs()->SetString(pref_name(), value); } template <> @@ -203,7 +199,7 @@ template <> void PrefMember<base::FilePath>::UpdatePref(const base::FilePath& value) { - prefs()->SetFilePath(pref_name().c_str(), value); + prefs()->SetFilePath(pref_name(), value); } template <> @@ -218,7 +214,7 @@ const std::vector<std::string>& value) { base::ListValue list_value; list_value.AppendStrings(value); - prefs()->Set(pref_name().c_str(), list_value); + prefs()->Set(pref_name(), list_value); } template <>
diff --git a/base/prefs/pref_member.h b/base/prefs/pref_member.h index a05d60e..b47cae2 100644 --- a/base/prefs/pref_member.h +++ b/base/prefs/pref_member.h
@@ -103,9 +103,10 @@ virtual ~PrefMemberBase(); // See PrefMember<> for description. - void Init(const char* pref_name, PrefService* prefs, + void Init(const std::string& pref_name, + PrefService* prefs, const NamedChangeCallback& observer); - void Init(const char* pref_name, PrefService* prefs); + void Init(const std::string& pref_name, PrefService* prefs); virtual void CreateInternal() const = 0; @@ -169,17 +170,19 @@ // Do the actual initialization of the class. Use the two-parameter // version if you don't want any notifications of changes. This // method should only be called on the UI thread. - void Init(const char* pref_name, PrefService* prefs, + void Init(const std::string& pref_name, + PrefService* prefs, const NamedChangeCallback& observer) { subtle::PrefMemberBase::Init(pref_name, prefs, observer); } - void Init(const char* pref_name, PrefService* prefs, + void Init(const std::string& pref_name, + PrefService* prefs, const base::Closure& observer) { subtle::PrefMemberBase::Init( pref_name, prefs, base::Bind(&PrefMemberBase::InvokeUnnamedCallback, observer)); } - void Init(const char* pref_name, PrefService* prefs) { + void Init(const std::string& pref_name, PrefService* prefs) { subtle::PrefMemberBase::Init(pref_name, prefs); }
diff --git a/base/prefs/pref_member_unittest.cc b/base/prefs/pref_member_unittest.cc index d4d7e02..435122b 100644 --- a/base/prefs/pref_member_unittest.cc +++ b/base/prefs/pref_member_unittest.cc
@@ -35,7 +35,7 @@ pref_thread_.Start(); } - void Init(const char* pref_name, PrefService* prefs) { + void Init(const std::string& pref_name, PrefService* prefs) { pref_.Init(pref_name, prefs); pref_.MoveToThread(pref_thread_.message_loop_proxy()); }
diff --git a/base/prefs/pref_notifier_impl.cc b/base/prefs/pref_notifier_impl.cc index c02a7b3..6bf9603 100644 --- a/base/prefs/pref_notifier_impl.cc +++ b/base/prefs/pref_notifier_impl.cc
@@ -38,7 +38,7 @@ init_observers_.clear(); } -void PrefNotifierImpl::AddPrefObserver(const char* path, +void PrefNotifierImpl::AddPrefObserver(const std::string& path, PrefObserver* obs) { // Get the pref observer list associated with the path. PrefObserverList* observer_list = NULL; @@ -56,7 +56,7 @@ observer_list->AddObserver(obs); } -void PrefNotifierImpl::RemovePrefObserver(const char* path, +void PrefNotifierImpl::RemovePrefObserver(const std::string& path, PrefObserver* obs) { DCHECK(thread_checker_.CalledOnValidThread()); @@ -98,7 +98,7 @@ DCHECK(thread_checker_.CalledOnValidThread()); // Only send notifications for registered preferences. - if (!pref_service_->FindPreference(path.c_str())) + if (!pref_service_->FindPreference(path)) return; const PrefObserverMap::iterator observer_iterator =
diff --git a/base/prefs/pref_notifier_impl.h b/base/prefs/pref_notifier_impl.h index 3f4c254..cfd46ff4 100644 --- a/base/prefs/pref_notifier_impl.h +++ b/base/prefs/pref_notifier_impl.h
@@ -29,8 +29,8 @@ // If the pref at the given path changes, we call the observer's // OnPreferenceChanged method. - void AddPrefObserver(const char* path, PrefObserver* observer); - void RemovePrefObserver(const char* path, PrefObserver* observer); + void AddPrefObserver(const std::string& path, PrefObserver* observer); + void RemovePrefObserver(const std::string& path, PrefObserver* observer); // We run the callback once, when initialization completes. The bool // parameter will be set to true for successful initialization,
diff --git a/base/prefs/pref_notifier_impl_unittest.cc b/base/prefs/pref_notifier_impl_unittest.cc index 8482c028..04564c8 100644 --- a/base/prefs/pref_notifier_impl_unittest.cc +++ b/base/prefs/pref_notifier_impl_unittest.cc
@@ -51,7 +51,7 @@ MOCK_METHOD1(FireObservers, void(const std::string& path)); - size_t CountObserver(const char* path, PrefObserver* obs) { + size_t CountObserver(const std::string& path, PrefObserver* obs) { PrefObserverMap::const_iterator observer_iterator = pref_observers()->find(path); if (observer_iterator == pref_observers()->end())
diff --git a/base/prefs/pref_registry.cc b/base/prefs/pref_registry.cc index 1349961..69f0494 100644 --- a/base/prefs/pref_registry.cc +++ b/base/prefs/pref_registry.cc
@@ -28,7 +28,7 @@ return defaults_->end(); } -void PrefRegistry::SetDefaultPrefValue(const char* pref_name, +void PrefRegistry::SetDefaultPrefValue(const std::string& pref_name, base::Value* value) { DCHECK(value); const base::Value* current_value = NULL; @@ -40,7 +40,7 @@ defaults_->ReplaceDefaultValue(pref_name, make_scoped_ptr(value)); } -void PrefRegistry::RegisterPreference(const char* path, +void PrefRegistry::RegisterPreference(const std::string& path, base::Value* default_value) { base::Value::Type orig_type = default_value->GetType(); DCHECK(orig_type != base::Value::TYPE_NULL &&
diff --git a/base/prefs/pref_registry.h b/base/prefs/pref_registry.h index 896db3f..a500b6e 100644 --- a/base/prefs/pref_registry.h +++ b/base/prefs/pref_registry.h
@@ -41,14 +41,14 @@ // Changes the default value for a preference. Takes ownership of |value|. // // |pref_name| must be a previously registered preference. - void SetDefaultPrefValue(const char* pref_name, base::Value* value); + void SetDefaultPrefValue(const std::string& pref_name, base::Value* value); protected: friend class base::RefCounted<PrefRegistry>; virtual ~PrefRegistry(); // Used by subclasses to register a default value for a preference. - void RegisterPreference(const char* path, base::Value* default_value); + void RegisterPreference(const std::string& path, base::Value* default_value); scoped_refptr<DefaultPrefStore> defaults_;
diff --git a/base/prefs/pref_registry_simple.cc b/base/prefs/pref_registry_simple.cc index 7453016..fa679dc9 100644 --- a/base/prefs/pref_registry_simple.cc +++ b/base/prefs/pref_registry_simple.cc
@@ -14,52 +14,52 @@ PrefRegistrySimple::~PrefRegistrySimple() { } -void PrefRegistrySimple::RegisterBooleanPref(const char* path, +void PrefRegistrySimple::RegisterBooleanPref(const std::string& path, bool default_value) { RegisterPreference(path, new base::FundamentalValue(default_value)); } -void PrefRegistrySimple::RegisterIntegerPref(const char* path, +void PrefRegistrySimple::RegisterIntegerPref(const std::string& path, int default_value) { RegisterPreference(path, new base::FundamentalValue(default_value)); } -void PrefRegistrySimple::RegisterDoublePref(const char* path, +void PrefRegistrySimple::RegisterDoublePref(const std::string& path, double default_value) { RegisterPreference(path, new base::FundamentalValue(default_value)); } -void PrefRegistrySimple::RegisterStringPref(const char* path, +void PrefRegistrySimple::RegisterStringPref(const std::string& path, const std::string& default_value) { RegisterPreference(path, new base::StringValue(default_value)); } void PrefRegistrySimple::RegisterFilePathPref( - const char* path, + const std::string& path, const base::FilePath& default_value) { RegisterPreference(path, new base::StringValue(default_value.value())); } -void PrefRegistrySimple::RegisterListPref(const char* path) { +void PrefRegistrySimple::RegisterListPref(const std::string& path) { RegisterPreference(path, new base::ListValue()); } -void PrefRegistrySimple::RegisterListPref(const char* path, +void PrefRegistrySimple::RegisterListPref(const std::string& path, base::ListValue* default_value) { RegisterPreference(path, default_value); } -void PrefRegistrySimple::RegisterDictionaryPref(const char* path) { +void PrefRegistrySimple::RegisterDictionaryPref(const std::string& path) { RegisterPreference(path, new base::DictionaryValue()); } void PrefRegistrySimple::RegisterDictionaryPref( - const char* path, + const std::string& path, base::DictionaryValue* default_value) { RegisterPreference(path, default_value); } -void PrefRegistrySimple::RegisterInt64Pref(const char* path, +void PrefRegistrySimple::RegisterInt64Pref(const std::string& path, int64 default_value) { RegisterPreference( path, new base::StringValue(base::Int64ToString(default_value)));
diff --git a/base/prefs/pref_registry_simple.h b/base/prefs/pref_registry_simple.h index 41fe590..73ae216 100644 --- a/base/prefs/pref_registry_simple.h +++ b/base/prefs/pref_registry_simple.h
@@ -21,19 +21,20 @@ public: PrefRegistrySimple(); - void RegisterBooleanPref(const char* path, bool default_value); - void RegisterIntegerPref(const char* path, int default_value); - void RegisterDoublePref(const char* path, double default_value); - void RegisterStringPref(const char* path, const std::string& default_value); - void RegisterFilePathPref(const char* path, + void RegisterBooleanPref(const std::string& path, bool default_value); + void RegisterIntegerPref(const std::string& path, int default_value); + void RegisterDoublePref(const std::string& path, double default_value); + void RegisterStringPref(const std::string& path, + const std::string& default_value); + void RegisterFilePathPref(const std::string& path, const base::FilePath& default_value); - void RegisterListPref(const char* path); - void RegisterDictionaryPref(const char* path); - void RegisterListPref(const char* path, base::ListValue* default_value); - void RegisterDictionaryPref(const char* path, + void RegisterListPref(const std::string& path); + void RegisterDictionaryPref(const std::string& path); + void RegisterListPref(const std::string& path, + base::ListValue* default_value); + void RegisterDictionaryPref(const std::string& path, base::DictionaryValue* default_value); - void RegisterInt64Pref(const char* path, - int64 default_value); + void RegisterInt64Pref(const std::string& path, int64 default_value); private: ~PrefRegistrySimple() override;
diff --git a/base/prefs/pref_service.cc b/base/prefs/pref_service.cc index 88fe938..66323a1 100644 --- a/base/prefs/pref_service.cc +++ b/base/prefs/pref_service.cc
@@ -86,7 +86,7 @@ user_pref_store_->CommitPendingWrite(); } -bool PrefService::GetBoolean(const char* path) const { +bool PrefService::GetBoolean(const std::string& path) const { DCHECK(CalledOnValidThread()); bool result = false; @@ -101,7 +101,7 @@ return result; } -int PrefService::GetInteger(const char* path) const { +int PrefService::GetInteger(const std::string& path) const { DCHECK(CalledOnValidThread()); int result = 0; @@ -116,7 +116,7 @@ return result; } -double PrefService::GetDouble(const char* path) const { +double PrefService::GetDouble(const std::string& path) const { DCHECK(CalledOnValidThread()); double result = 0.0; @@ -131,7 +131,7 @@ return result; } -std::string PrefService::GetString(const char* path) const { +std::string PrefService::GetString(const std::string& path) const { DCHECK(CalledOnValidThread()); std::string result; @@ -146,7 +146,7 @@ return result; } -base::FilePath PrefService::GetFilePath(const char* path) const { +base::FilePath PrefService::GetFilePath(const std::string& path) const { DCHECK(CalledOnValidThread()); base::FilePath result; @@ -161,7 +161,7 @@ return result; } -bool PrefService::HasPrefPath(const char* path) const { +bool PrefService::HasPrefPath(const std::string& path) const { const Preference* pref = FindPreference(path); return pref && !pref->IsDefaultValue(); } @@ -181,7 +181,7 @@ DCHECK(CalledOnValidThread()); scoped_ptr<base::DictionaryValue> out(new base::DictionaryValue); for (const auto& it : *pref_registry_) { - const Preference* pref = FindPreference(it.first.c_str()); + const Preference* pref = FindPreference(it.first); if (pref->IsDefaultValue()) continue; out->Set(it.first, pref->GetValue()->DeepCopy()); @@ -202,7 +202,7 @@ } const PrefService::Preference* PrefService::FindPreference( - const char* pref_name) const { + const std::string& pref_name) const { DCHECK(CalledOnValidThread()); PreferenceMap::iterator it = prefs_map_.find(pref_name); if (it != prefs_map_.end()) @@ -235,18 +235,19 @@ } } -bool PrefService::IsManagedPreference(const char* pref_name) const { +bool PrefService::IsManagedPreference(const std::string& pref_name) const { const Preference* pref = FindPreference(pref_name); return pref && pref->IsManaged(); } -bool PrefService::IsUserModifiablePreference(const char* pref_name) const { +bool PrefService::IsUserModifiablePreference( + const std::string& pref_name) const { const Preference* pref = FindPreference(pref_name); return pref && pref->IsUserModifiable(); } const base::DictionaryValue* PrefService::GetDictionary( - const char* path) const { + const std::string& path) const { DCHECK(CalledOnValidThread()); const base::Value* value = GetPreferenceValue(path); @@ -261,7 +262,8 @@ return static_cast<const base::DictionaryValue*>(value); } -const base::Value* PrefService::GetUserPrefValue(const char* path) const { +const base::Value* PrefService::GetUserPrefValue( + const std::string& path) const { DCHECK(CalledOnValidThread()); const Preference* pref = FindPreference(path); @@ -284,13 +286,14 @@ return value; } -void PrefService::SetDefaultPrefValue(const char* path, +void PrefService::SetDefaultPrefValue(const std::string& path, base::Value* value) { DCHECK(CalledOnValidThread()); pref_registry_->SetDefaultPrefValue(path, value); } -const base::Value* PrefService::GetDefaultPrefValue(const char* path) const { +const base::Value* PrefService::GetDefaultPrefValue( + const std::string& path) const { DCHECK(CalledOnValidThread()); // Lookup the preference in the default store. const base::Value* value = NULL; @@ -301,7 +304,7 @@ return value; } -const base::ListValue* PrefService::GetList(const char* path) const { +const base::ListValue* PrefService::GetList(const std::string& path) const { DCHECK(CalledOnValidThread()); const base::Value* value = GetPreferenceValue(path); @@ -316,11 +319,12 @@ return static_cast<const base::ListValue*>(value); } -void PrefService::AddPrefObserver(const char* path, PrefObserver* obs) { +void PrefService::AddPrefObserver(const std::string& path, PrefObserver* obs) { pref_notifier_->AddPrefObserver(path, obs); } -void PrefService::RemovePrefObserver(const char* path, PrefObserver* obs) { +void PrefService::RemovePrefObserver(const std::string& path, + PrefObserver* obs) { pref_notifier_->RemovePrefObserver(path, obs); } @@ -332,7 +336,7 @@ return pref_registry_.get(); } -void PrefService::ClearPref(const char* path) { +void PrefService::ClearPref(const std::string& path) { DCHECK(CalledOnValidThread()); const Preference* pref = FindPreference(path); @@ -343,35 +347,36 @@ user_pref_store_->RemoveValue(path); } -void PrefService::Set(const char* path, const base::Value& value) { +void PrefService::Set(const std::string& path, const base::Value& value) { SetUserPrefValue(path, value.DeepCopy()); } -void PrefService::SetBoolean(const char* path, bool value) { +void PrefService::SetBoolean(const std::string& path, bool value) { SetUserPrefValue(path, new base::FundamentalValue(value)); } -void PrefService::SetInteger(const char* path, int value) { +void PrefService::SetInteger(const std::string& path, int value) { SetUserPrefValue(path, new base::FundamentalValue(value)); } -void PrefService::SetDouble(const char* path, double value) { +void PrefService::SetDouble(const std::string& path, double value) { SetUserPrefValue(path, new base::FundamentalValue(value)); } -void PrefService::SetString(const char* path, const std::string& value) { +void PrefService::SetString(const std::string& path, const std::string& value) { SetUserPrefValue(path, new base::StringValue(value)); } -void PrefService::SetFilePath(const char* path, const base::FilePath& value) { +void PrefService::SetFilePath(const std::string& path, + const base::FilePath& value) { SetUserPrefValue(path, base::CreateFilePathValue(value)); } -void PrefService::SetInt64(const char* path, int64 value) { +void PrefService::SetInt64(const std::string& path, int64 value) { SetUserPrefValue(path, new base::StringValue(base::Int64ToString(value))); } -int64 PrefService::GetInt64(const char* path) const { +int64 PrefService::GetInt64(const std::string& path) const { DCHECK(CalledOnValidThread()); const base::Value* value = GetPreferenceValue(path); @@ -388,11 +393,11 @@ return val; } -void PrefService::SetUint64(const char* path, uint64 value) { +void PrefService::SetUint64(const std::string& path, uint64 value) { SetUserPrefValue(path, new base::StringValue(base::Uint64ToString(value))); } -uint64 PrefService::GetUint64(const char* path) const { +uint64 PrefService::GetUint64(const std::string& path) const { DCHECK(CalledOnValidThread()); const base::Value* value = GetPreferenceValue(path); @@ -409,7 +414,7 @@ return val; } -base::Value* PrefService::GetMutableUserPref(const char* path, +base::Value* PrefService::GetMutableUserPref(const std::string& path, base::Value::Type type) { CHECK(type == base::Value::TYPE_DICTIONARY || type == base::Value::TYPE_LIST); DCHECK(CalledOnValidThread()); @@ -446,7 +451,8 @@ user_pref_store_->ReportValueChanged(key); } -void PrefService::SetUserPrefValue(const char* path, base::Value* new_value) { +void PrefService::SetUserPrefValue(const std::string& path, + base::Value* new_value) { scoped_ptr<base::Value> owned_value(new_value); DCHECK(CalledOnValidThread()); @@ -473,12 +479,9 @@ // PrefService::Preference PrefService::Preference::Preference(const PrefService* service, - const char* name, + const std::string& name, base::Value::Type type) - : name_(name), - type_(type), - pref_service_(service) { - DCHECK(name); + : name_(name), type_(type), pref_service_(service) { DCHECK(service); } @@ -497,8 +500,8 @@ } const base::Value* PrefService::Preference::GetRecommendedValue() const { - DCHECK(pref_service_->FindPreference(name_.c_str())) << - "Must register pref before getting its value"; + DCHECK(pref_service_->FindPreference(name_)) + << "Must register pref before getting its value"; const base::Value* found_value = NULL; if (pref_value_store()->GetRecommendedValue(name_, type_, &found_value)) { @@ -511,39 +514,39 @@ } bool PrefService::Preference::IsManaged() const { - return pref_value_store()->PrefValueInManagedStore(name_.c_str()); + return pref_value_store()->PrefValueInManagedStore(name_); } bool PrefService::Preference::IsRecommended() const { - return pref_value_store()->PrefValueFromRecommendedStore(name_.c_str()); + return pref_value_store()->PrefValueFromRecommendedStore(name_); } bool PrefService::Preference::HasExtensionSetting() const { - return pref_value_store()->PrefValueInExtensionStore(name_.c_str()); + return pref_value_store()->PrefValueInExtensionStore(name_); } bool PrefService::Preference::HasUserSetting() const { - return pref_value_store()->PrefValueInUserStore(name_.c_str()); + return pref_value_store()->PrefValueInUserStore(name_); } bool PrefService::Preference::IsExtensionControlled() const { - return pref_value_store()->PrefValueFromExtensionStore(name_.c_str()); + return pref_value_store()->PrefValueFromExtensionStore(name_); } bool PrefService::Preference::IsUserControlled() const { - return pref_value_store()->PrefValueFromUserStore(name_.c_str()); + return pref_value_store()->PrefValueFromUserStore(name_); } bool PrefService::Preference::IsDefaultValue() const { - return pref_value_store()->PrefValueFromDefaultStore(name_.c_str()); + return pref_value_store()->PrefValueFromDefaultStore(name_); } bool PrefService::Preference::IsUserModifiable() const { - return pref_value_store()->PrefValueUserModifiable(name_.c_str()); + return pref_value_store()->PrefValueUserModifiable(name_); } bool PrefService::Preference::IsExtensionModifiable() const { - return pref_value_store()->PrefValueExtensionModifiable(name_.c_str()); + return pref_value_store()->PrefValueExtensionModifiable(name_); } const base::Value* PrefService::GetPreferenceValue(
diff --git a/base/prefs/pref_service.h b/base/prefs/pref_service.h index fec6906..734cc2b3 100644 --- a/base/prefs/pref_service.h +++ b/base/prefs/pref_service.h
@@ -65,7 +65,7 @@ // dictionary (a branch), or list. You shouldn't need to construct this on // your own; use the PrefService::Register*Pref methods instead. Preference(const PrefService* service, - const char* name, + const std::string& name, base::Value::Type type); ~Preference() {} @@ -156,76 +156,75 @@ // Returns true if the preference for the given preference name is available // and is managed. - bool IsManagedPreference(const char* pref_name) const; + bool IsManagedPreference(const std::string& pref_name) const; // Returns |true| if a preference with the given name is available and its // value can be changed by the user. - bool IsUserModifiablePreference(const char* pref_name) const; + bool IsUserModifiablePreference(const std::string& pref_name) const; // Look up a preference. Returns NULL if the preference is not // registered. - const PrefService::Preference* FindPreference(const char* path) const; + const PrefService::Preference* FindPreference(const std::string& path) const; // If the path is valid and the value at the end of the path matches the type // specified, it will return the specified value. Otherwise, the default // value (set when the pref was registered) will be returned. - bool GetBoolean(const char* path) const; - int GetInteger(const char* path) const; - double GetDouble(const char* path) const; - std::string GetString(const char* path) const; - base::FilePath GetFilePath(const char* path) const; + bool GetBoolean(const std::string& path) const; + int GetInteger(const std::string& path) const; + double GetDouble(const std::string& path) const; + std::string GetString(const std::string& path) const; + base::FilePath GetFilePath(const std::string& path) const; // Returns the branch if it exists, or the registered default value otherwise. // Note that |path| must point to a registered preference. In that case, these // functions will never return NULL. - const base::DictionaryValue* GetDictionary( - const char* path) const; - const base::ListValue* GetList(const char* path) const; + const base::DictionaryValue* GetDictionary(const std::string& path) const; + const base::ListValue* GetList(const std::string& path) const; // Removes a user pref and restores the pref to its default value. - void ClearPref(const char* path); + void ClearPref(const std::string& path); // If the path is valid (i.e., registered), update the pref value in the user // prefs. // To set the value of dictionary or list values in the pref tree use // Set(), but to modify the value of a dictionary or list use either // ListPrefUpdate or DictionaryPrefUpdate from scoped_user_pref_update.h. - void Set(const char* path, const base::Value& value); - void SetBoolean(const char* path, bool value); - void SetInteger(const char* path, int value); - void SetDouble(const char* path, double value); - void SetString(const char* path, const std::string& value); - void SetFilePath(const char* path, const base::FilePath& value); + void Set(const std::string& path, const base::Value& value); + void SetBoolean(const std::string& path, bool value); + void SetInteger(const std::string& path, int value); + void SetDouble(const std::string& path, double value); + void SetString(const std::string& path, const std::string& value); + void SetFilePath(const std::string& path, const base::FilePath& value); // Int64 helper methods that actually store the given value as a string. // Note that if obtaining the named value via GetDictionary or GetList, the // Value type will be TYPE_STRING. - void SetInt64(const char* path, int64 value); - int64 GetInt64(const char* path) const; + void SetInt64(const std::string& path, int64 value); + int64 GetInt64(const std::string& path) const; // As above, but for unsigned values. - void SetUint64(const char* path, uint64 value); - uint64 GetUint64(const char* path) const; + void SetUint64(const std::string& path, uint64 value); + uint64 GetUint64(const std::string& path) const; // Returns the value of the given preference, from the user pref store. If // the preference is not set in the user pref store, returns NULL. - const base::Value* GetUserPrefValue(const char* path) const; + const base::Value* GetUserPrefValue(const std::string& path) const; // Changes the default value for a preference. Takes ownership of |value|. // // Will cause a pref change notification to be fired if this causes // the effective value to change. - void SetDefaultPrefValue(const char* path, base::Value* value); + void SetDefaultPrefValue(const std::string& path, base::Value* value); // Returns the default value of the given preference. |path| must point to a // registered preference. In that case, will never return NULL. - const base::Value* GetDefaultPrefValue(const char* path) const; + const base::Value* GetDefaultPrefValue(const std::string& path) const; // Returns true if a value has been set for the specified path. // NOTE: this is NOT the same as FindPreference. In particular // FindPreference returns whether RegisterXXX has been invoked, where as // this checks if a value exists for the path. - bool HasPrefPath(const char* path) const; + bool HasPrefPath(const std::string& path) const; // Returns a dictionary with effective preference values. scoped_ptr<base::DictionaryValue> GetPreferenceValues() const; @@ -318,8 +317,8 @@ // make sure the observer gets cleaned up properly. // // Virtual for testing. - virtual void AddPrefObserver(const char* path, PrefObserver* obs); - virtual void RemovePrefObserver(const char* path, PrefObserver* obs); + virtual void AddPrefObserver(const std::string& path, PrefObserver* obs); + virtual void RemovePrefObserver(const std::string& path, PrefObserver* obs); // Sends notification of a changed preference. This needs to be called by // a ScopedUserPrefUpdate if a DictionaryValue or ListValue is changed. @@ -327,7 +326,7 @@ // Sets the value for this pref path in the user pref store and informs the // PrefNotifier of the change. - void SetUserPrefValue(const char* path, base::Value* new_value); + void SetUserPrefValue(const std::string& path, base::Value* new_value); // Load preferences from storage, attempting to diagnose and handle errors. // This should only be called from the constructor. @@ -340,7 +339,7 @@ // |type| may only be Values::TYPE_DICTIONARY or Values::TYPE_LIST and // |path| must point to a registered preference of type |type|. // Ownership of the returned value remains at the user pref store. - base::Value* GetMutableUserPref(const char* path, + base::Value* GetMutableUserPref(const std::string& path, base::Value::Type type); // GetPreferenceValue is the equivalent of FindPreference(path)->GetValue(),
diff --git a/base/prefs/pref_value_store.cc b/base/prefs/pref_value_store.cc index 2c22f17..4b7aab9 100644 --- a/base/prefs/pref_value_store.cc +++ b/base/prefs/pref_value_store.cc
@@ -109,8 +109,8 @@ // Check the |PrefStore|s in order of their priority from highest to lowest, // looking for the first preference value with the given |name| and |type|. for (size_t i = 0; i <= PREF_STORE_TYPE_MAX; ++i) { - if (GetValueFromStoreWithType(name.c_str(), type, - static_cast<PrefStoreType>(i), out_value)) + if (GetValueFromStoreWithType(name, type, static_cast<PrefStoreType>(i), + out_value)) return true; } return false; @@ -119,12 +119,11 @@ bool PrefValueStore::GetRecommendedValue(const std::string& name, base::Value::Type type, const base::Value** out_value) const { - return GetValueFromStoreWithType(name.c_str(), type, RECOMMENDED_STORE, - out_value); + return GetValueFromStoreWithType(name, type, RECOMMENDED_STORE, out_value); } void PrefValueStore::NotifyPrefChanged( - const char* path, + const std::string& path, PrefValueStore::PrefStoreType new_store) { DCHECK(new_store != INVALID_STORE); // A notification is sent when the pref value in any store changes. If this @@ -135,41 +134,44 @@ pref_changed_callback_.Run(path); } -bool PrefValueStore::PrefValueInManagedStore(const char* name) const { +bool PrefValueStore::PrefValueInManagedStore(const std::string& name) const { return PrefValueInStore(name, MANAGED_STORE); } -bool PrefValueStore::PrefValueInExtensionStore(const char* name) const { +bool PrefValueStore::PrefValueInExtensionStore(const std::string& name) const { return PrefValueInStore(name, EXTENSION_STORE); } -bool PrefValueStore::PrefValueInUserStore(const char* name) const { +bool PrefValueStore::PrefValueInUserStore(const std::string& name) const { return PrefValueInStore(name, USER_STORE); } -bool PrefValueStore::PrefValueFromExtensionStore(const char* name) const { +bool PrefValueStore::PrefValueFromExtensionStore( + const std::string& name) const { return ControllingPrefStoreForPref(name) == EXTENSION_STORE; } -bool PrefValueStore::PrefValueFromUserStore(const char* name) const { +bool PrefValueStore::PrefValueFromUserStore(const std::string& name) const { return ControllingPrefStoreForPref(name) == USER_STORE; } -bool PrefValueStore::PrefValueFromRecommendedStore(const char* name) const { +bool PrefValueStore::PrefValueFromRecommendedStore( + const std::string& name) const { return ControllingPrefStoreForPref(name) == RECOMMENDED_STORE; } -bool PrefValueStore::PrefValueFromDefaultStore(const char* name) const { +bool PrefValueStore::PrefValueFromDefaultStore(const std::string& name) const { return ControllingPrefStoreForPref(name) == DEFAULT_STORE; } -bool PrefValueStore::PrefValueUserModifiable(const char* name) const { +bool PrefValueStore::PrefValueUserModifiable(const std::string& name) const { PrefStoreType effective_store = ControllingPrefStoreForPref(name); return effective_store >= USER_STORE || effective_store == INVALID_STORE; } -bool PrefValueStore::PrefValueExtensionModifiable(const char* name) const { +bool PrefValueStore::PrefValueExtensionModifiable( + const std::string& name) const { PrefStoreType effective_store = ControllingPrefStoreForPref(name); return effective_store >= EXTENSION_STORE || effective_store == INVALID_STORE; @@ -180,7 +182,7 @@ } bool PrefValueStore::PrefValueInStore( - const char* name, + const std::string& name, PrefValueStore::PrefStoreType store) const { // Declare a temp Value* and call GetValueFromStore, // ignoring the output value. @@ -189,7 +191,7 @@ } bool PrefValueStore::PrefValueInStoreRange( - const char* name, + const std::string& name, PrefValueStore::PrefStoreType first_checked_store, PrefValueStore::PrefStoreType last_checked_store) const { if (first_checked_store > last_checked_store) { @@ -206,7 +208,7 @@ } PrefValueStore::PrefStoreType PrefValueStore::ControllingPrefStoreForPref( - const char* name) const { + const std::string& name) const { for (size_t i = 0; i <= PREF_STORE_TYPE_MAX; ++i) { if (PrefValueInStore(name, static_cast<PrefStoreType>(i))) return static_cast<PrefStoreType>(i); @@ -214,7 +216,7 @@ return INVALID_STORE; } -bool PrefValueStore::GetValueFromStore(const char* name, +bool PrefValueStore::GetValueFromStore(const std::string& name, PrefValueStore::PrefStoreType store_type, const base::Value** out_value) const { // Only return true if we find a value and it is the correct type, so stale @@ -230,7 +232,7 @@ } bool PrefValueStore::GetValueFromStoreWithType( - const char* name, + const std::string& name, base::Value::Type type, PrefStoreType store, const base::Value** out_value) const { @@ -249,7 +251,7 @@ void PrefValueStore::OnPrefValueChanged(PrefValueStore::PrefStoreType type, const std::string& key) { - NotifyPrefChanged(key.c_str(), type); + NotifyPrefChanged(key, type); } void PrefValueStore::OnInitializationCompleted(
diff --git a/base/prefs/pref_value_store.h b/base/prefs/pref_value_store.h index db82a82..33203bd 100644 --- a/base/prefs/pref_value_store.h +++ b/base/prefs/pref_value_store.h
@@ -94,25 +94,25 @@ // These methods return true if a preference with the given name is in the // indicated pref store, even if that value is currently being overridden by // a higher-priority source. - bool PrefValueInManagedStore(const char* name) const; - bool PrefValueInExtensionStore(const char* name) const; - bool PrefValueInUserStore(const char* name) const; + bool PrefValueInManagedStore(const std::string& name) const; + bool PrefValueInExtensionStore(const std::string& name) const; + bool PrefValueInUserStore(const std::string& name) const; // These methods return true if a preference with the given name is actually // being controlled by the indicated pref store and not being overridden by // a higher-priority source. - bool PrefValueFromExtensionStore(const char* name) const; - bool PrefValueFromUserStore(const char* name) const; - bool PrefValueFromRecommendedStore(const char* name) const; - bool PrefValueFromDefaultStore(const char* name) const; + bool PrefValueFromExtensionStore(const std::string& name) const; + bool PrefValueFromUserStore(const std::string& name) const; + bool PrefValueFromRecommendedStore(const std::string& name) const; + bool PrefValueFromDefaultStore(const std::string& name) const; // Check whether a Preference value is modifiable by the user, i.e. whether // there is no higher-priority source controlling it. - bool PrefValueUserModifiable(const char* name) const; + bool PrefValueUserModifiable(const std::string& name) const; // Check whether a Preference value is modifiable by an extension, i.e. // whether there is no higher-priority source controlling it. - bool PrefValueExtensionModifiable(const char* name) const; + bool PrefValueExtensionModifiable(const std::string& name) const; // Update the command line PrefStore with |command_line_prefs|. void UpdateCommandLinePrefStore(PrefStore* command_line_prefs); @@ -188,13 +188,13 @@ // Returns true if the preference with the given name has a value in the // given PrefStoreType, of the same value type as the preference was // registered with. - bool PrefValueInStore(const char* name, PrefStoreType store) const; + bool PrefValueInStore(const std::string& name, PrefStoreType store) const; // Returns true if a preference has an explicit value in any of the // stores in the range specified by |first_checked_store| and // |last_checked_store|, even if that value is currently being // overridden by a higher-priority store. - bool PrefValueInStoreRange(const char* name, + bool PrefValueInStoreRange(const std::string& name, PrefStoreType first_checked_store, PrefStoreType last_checked_store) const; @@ -203,15 +203,15 @@ // INVALID_STORE is returned. In practice, the default PrefStore // should always have a value for any registered preferencem, so INVALID_STORE // indicates an error. - PrefStoreType ControllingPrefStoreForPref(const char* name) const; + PrefStoreType ControllingPrefStoreForPref(const std::string& name) const; // Get a value from the specified |store|. - bool GetValueFromStore(const char* name, + bool GetValueFromStore(const std::string& name, PrefStoreType store, const base::Value** out_value) const; // Get a value from the specified |store| if its |type| matches. - bool GetValueFromStoreWithType(const char* name, + bool GetValueFromStoreWithType(const std::string& name, base::Value::Type type, PrefStoreType store, const base::Value** out_value) const; @@ -220,7 +220,7 @@ // the user-visible pref value has changed. Triggers the change notification // if the effective value of the preference has changed, or if the store // controlling the pref has changed. - void NotifyPrefChanged(const char* path, PrefStoreType new_store); + void NotifyPrefChanged(const std::string& path, PrefStoreType new_store); // Called from the PrefStoreKeeper implementation when a pref value for |key| // changed in the pref store for |type|.
diff --git a/base/prefs/pref_value_store_unittest.cc b/base/prefs/pref_value_store_unittest.cc index 3afe9dce..9194b22 100644 --- a/base/prefs/pref_value_store_unittest.cc +++ b/base/prefs/pref_value_store_unittest.cc
@@ -237,7 +237,7 @@ default_pref::kDefaultValue); } - void ExpectValueChangeNotifications(const char* name) { + void ExpectValueChangeNotifications(const std::string& name) { EXPECT_CALL(pref_notifier_, OnPreferenceChanged(name)); EXPECT_CALL(*sync_associator_, ProcessPrefChange(name)); }
diff --git a/base/prefs/scoped_user_pref_update.cc b/base/prefs/scoped_user_pref_update.cc index 7871c75..1440a571 100644 --- a/base/prefs/scoped_user_pref_update.cc +++ b/base/prefs/scoped_user_pref_update.cc
@@ -11,10 +11,8 @@ namespace subtle { ScopedUserPrefUpdateBase::ScopedUserPrefUpdateBase(PrefService* service, - const char* path) - : service_(service), - path_(path), - value_(NULL) { + const std::string& path) + : service_(service), path_(path), value_(NULL) { DCHECK(service_->CalledOnValidThread()); } @@ -25,7 +23,7 @@ base::Value* ScopedUserPrefUpdateBase::GetValueOfType(base::Value::Type type) { DCHECK(CalledOnValidThread()); if (!value_) - value_ = service_->GetMutableUserPref(path_.c_str(), type); + value_ = service_->GetMutableUserPref(path_, type); return value_; }
diff --git a/base/prefs/scoped_user_pref_update.h b/base/prefs/scoped_user_pref_update.h index 82d6739d..f8bebfe4 100644 --- a/base/prefs/scoped_user_pref_update.h +++ b/base/prefs/scoped_user_pref_update.h
@@ -33,7 +33,7 @@ // PrefService::ReportUserPrefChanged. class BASE_PREFS_EXPORT ScopedUserPrefUpdateBase : public base::NonThreadSafe { protected: - ScopedUserPrefUpdateBase(PrefService* service, const char* path); + ScopedUserPrefUpdateBase(PrefService* service, const std::string& path); // Calls Notify(). ~ScopedUserPrefUpdateBase(); @@ -66,7 +66,7 @@ template <typename T, base::Value::Type type_enum_value> class ScopedUserPrefUpdate : public subtle::ScopedUserPrefUpdateBase { public: - ScopedUserPrefUpdate(PrefService* service, const char* path) + ScopedUserPrefUpdate(PrefService* service, const std::string& path) : ScopedUserPrefUpdateBase(service, path) {} // Triggers an update notification if Get() was called.
diff --git a/base/prefs/testing_pref_service.h b/base/prefs/testing_pref_service.h index 2f6d494..40fd66a 100644 --- a/base/prefs/testing_pref_service.h +++ b/base/prefs/testing_pref_service.h
@@ -27,25 +27,25 @@ // Read the value of a preference from the managed layer. Returns NULL if the // preference is not defined at the managed layer. - const base::Value* GetManagedPref(const char* path) const; + const base::Value* GetManagedPref(const std::string& path) const; // Set a preference on the managed layer and fire observers if the preference // changed. Assumes ownership of |value|. - void SetManagedPref(const char* path, base::Value* value); + void SetManagedPref(const std::string& path, base::Value* value); // Clear the preference on the managed layer and fire observers if the // preference has been defined previously. - void RemoveManagedPref(const char* path); + void RemoveManagedPref(const std::string& path); // Similar to the above, but for user preferences. - const base::Value* GetUserPref(const char* path) const; - void SetUserPref(const char* path, base::Value* value); - void RemoveUserPref(const char* path); + const base::Value* GetUserPref(const std::string& path) const; + void SetUserPref(const std::string& path, base::Value* value); + void RemoveUserPref(const std::string& path); // Similar to the above, but for recommended policy preferences. - const base::Value* GetRecommendedPref(const char* path) const; - void SetRecommendedPref(const char* path, base::Value* value); - void RemoveRecommendedPref(const char* path); + const base::Value* GetRecommendedPref(const std::string& path) const; + void SetRecommendedPref(const std::string& path, base::Value* value); + void RemoveRecommendedPref(const std::string& path); // Do-nothing implementation for TestingPrefService. static void HandleReadError(PersistentPrefStore::PrefReadError error) {} @@ -62,14 +62,15 @@ // Reads the value of the preference indicated by |path| from |pref_store|. // Returns NULL if the preference was not found. const base::Value* GetPref(TestingPrefStore* pref_store, - const char* path) const; + const std::string& path) const; // Sets the value for |path| in |pref_store|. - void SetPref(TestingPrefStore* pref_store, const char* path, + void SetPref(TestingPrefStore* pref_store, + const std::string& path, base::Value* value); // Removes the preference identified by |path| from |pref_store|. - void RemovePref(TestingPrefStore* pref_store, const char* path); + void RemovePref(TestingPrefStore* pref_store, const std::string& path); // Pointers to the pref stores our value store uses. scoped_refptr<TestingPrefStore> managed_prefs_; @@ -110,88 +111,83 @@ SuperPrefService, ConstructionPrefRegistry>::~TestingPrefServiceBase() { } -template<class SuperPrefService, class ConstructionPrefRegistry> +template <class SuperPrefService, class ConstructionPrefRegistry> const base::Value* TestingPrefServiceBase< - SuperPrefService, ConstructionPrefRegistry>::GetManagedPref( - const char* path) const { + SuperPrefService, + ConstructionPrefRegistry>::GetManagedPref(const std::string& path) const { return GetPref(managed_prefs_.get(), path); } -template<class SuperPrefService, class ConstructionPrefRegistry> -void TestingPrefServiceBase< - SuperPrefService, ConstructionPrefRegistry>::SetManagedPref( - const char* path, base::Value* value) { +template <class SuperPrefService, class ConstructionPrefRegistry> +void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>:: + SetManagedPref(const std::string& path, base::Value* value) { SetPref(managed_prefs_.get(), path, value); } -template<class SuperPrefService, class ConstructionPrefRegistry> -void TestingPrefServiceBase< - SuperPrefService, ConstructionPrefRegistry>::RemoveManagedPref( - const char* path) { +template <class SuperPrefService, class ConstructionPrefRegistry> +void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>:: + RemoveManagedPref(const std::string& path) { RemovePref(managed_prefs_.get(), path); } -template<class SuperPrefService, class ConstructionPrefRegistry> -const base::Value* TestingPrefServiceBase< - SuperPrefService, ConstructionPrefRegistry>::GetUserPref( - const char* path) const { +template <class SuperPrefService, class ConstructionPrefRegistry> +const base::Value* +TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::GetUserPref( + const std::string& path) const { return GetPref(user_prefs_.get(), path); } -template<class SuperPrefService, class ConstructionPrefRegistry> -void TestingPrefServiceBase< - SuperPrefService, ConstructionPrefRegistry>::SetUserPref( - const char* path, base::Value* value) { +template <class SuperPrefService, class ConstructionPrefRegistry> +void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>:: + SetUserPref(const std::string& path, base::Value* value) { SetPref(user_prefs_.get(), path, value); } -template<class SuperPrefService, class ConstructionPrefRegistry> -void TestingPrefServiceBase< - SuperPrefService, ConstructionPrefRegistry>::RemoveUserPref( - const char* path) { +template <class SuperPrefService, class ConstructionPrefRegistry> +void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>:: + RemoveUserPref(const std::string& path) { RemovePref(user_prefs_.get(), path); } -template<class SuperPrefService, class ConstructionPrefRegistry> -const base::Value* TestingPrefServiceBase< - SuperPrefService, ConstructionPrefRegistry>::GetRecommendedPref( - const char* path) const { +template <class SuperPrefService, class ConstructionPrefRegistry> +const base::Value* +TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>:: + GetRecommendedPref(const std::string& path) const { return GetPref(recommended_prefs_, path); } -template<class SuperPrefService, class ConstructionPrefRegistry> -void TestingPrefServiceBase< - SuperPrefService, ConstructionPrefRegistry>::SetRecommendedPref( - const char* path, base::Value* value) { +template <class SuperPrefService, class ConstructionPrefRegistry> +void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>:: + SetRecommendedPref(const std::string& path, base::Value* value) { SetPref(recommended_prefs_.get(), path, value); } -template<class SuperPrefService, class ConstructionPrefRegistry> -void TestingPrefServiceBase< - SuperPrefService, ConstructionPrefRegistry>::RemoveRecommendedPref( - const char* path) { +template <class SuperPrefService, class ConstructionPrefRegistry> +void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>:: + RemoveRecommendedPref(const std::string& path) { RemovePref(recommended_prefs_.get(), path); } -template<class SuperPrefService, class ConstructionPrefRegistry> -const base::Value* TestingPrefServiceBase< - SuperPrefService, ConstructionPrefRegistry>::GetPref( - TestingPrefStore* pref_store, const char* path) const { +template <class SuperPrefService, class ConstructionPrefRegistry> +const base::Value* +TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::GetPref( + TestingPrefStore* pref_store, + const std::string& path) const { const base::Value* res; return pref_store->GetValue(path, &res) ? res : NULL; } -template<class SuperPrefService, class ConstructionPrefRegistry> -void TestingPrefServiceBase< - SuperPrefService, ConstructionPrefRegistry>::SetPref( - TestingPrefStore* pref_store, const char* path, base::Value* value) { +template <class SuperPrefService, class ConstructionPrefRegistry> +void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>:: + SetPref(TestingPrefStore* pref_store, + const std::string& path, + base::Value* value) { pref_store->SetValue(path, value); } -template<class SuperPrefService, class ConstructionPrefRegistry> -void TestingPrefServiceBase< - SuperPrefService, ConstructionPrefRegistry>::RemovePref( - TestingPrefStore* pref_store, const char* path) { +template <class SuperPrefService, class ConstructionPrefRegistry> +void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>:: + RemovePref(TestingPrefStore* pref_store, const std::string& path) { pref_store->RemoveValue(path); }
diff --git a/base/process/launch.h b/base/process/launch.h index 261019b..06abb29 100644 --- a/base/process/launch.h +++ b/base/process/launch.h
@@ -14,6 +14,7 @@ #include "base/base_export.h" #include "base/basictypes.h" #include "base/environment.h" +#include "base/process/process.h" #include "base/process/process_handle.h" #include "base/strings/string_piece.h" @@ -143,12 +144,7 @@ // Launch a process via the command line |cmdline|. // See the documentation of LaunchOptions for details on |options|. // -// Returns true upon success. -// -// Upon success, if |process_handle| is non-null, it will be filled in with the -// handle of the launched process. NOTE: In this case, the caller is -// responsible for closing the handle so that it doesn't leak! -// Otherwise, the process handle will be implicitly closed. +// Returns a valid Process upon success. // // Unix-specific notes: // - All file descriptors open in the parent process will be closed in the @@ -158,6 +154,11 @@ // parent's stdout and stderr. // - If the first argument on the command line does not contain a slash, // PATH will be searched. (See man execvp.) +BASE_EXPORT Process LaunchProcess(const CommandLine& cmdline, + const LaunchOptions& options); + +// Deprecated version. +// TODO(rvargas) crbug.com/417532: Remove this after migrating all consumers. BASE_EXPORT bool LaunchProcess(const CommandLine& cmdline, const LaunchOptions& options, ProcessHandle* process_handle); @@ -180,12 +181,10 @@ // Launches a process with elevated privileges. This does not behave exactly // like LaunchProcess as it uses ShellExecuteEx instead of CreateProcess to // create the process. This means the process will have elevated privileges -// and thus some common operations like OpenProcess will fail. The process will -// be available through the |process_handle| argument. Currently the only -// supported LaunchOptions are |start_hidden| and |wait|. -BASE_EXPORT bool LaunchElevatedProcess(const CommandLine& cmdline, - const LaunchOptions& options, - ProcessHandle* process_handle); +// and thus some common operations like OpenProcess will fail. Currently the +// only supported LaunchOptions are |start_hidden| and |wait|. +BASE_EXPORT Process LaunchElevatedProcess(const CommandLine& cmdline, + const LaunchOptions& options); #elif defined(OS_POSIX) // A POSIX-specific version of LaunchProcess that takes an argv array
diff --git a/base/process/launch_posix.cc b/base/process/launch_posix.cc index bc6294b..3322d265 100644 --- a/base/process/launch_posix.cc +++ b/base/process/launch_posix.cc
@@ -480,6 +480,15 @@ return LaunchProcess(cmdline.argv(), options, process_handle); } +Process LaunchProcess(const CommandLine& cmdline, + const LaunchOptions& options) { + ProcessHandle process_handle; + if (LaunchProcess(cmdline, options, &process_handle)) + return Process(process_handle); + + return Process(); +} + void RaiseProcessToHighPriority() { // On POSIX, we don't actually do anything here. We could try to nice() or // setpriority() or sched_getscheduler, but these all require extra rights.
diff --git a/base/process/launch_win.cc b/base/process/launch_win.cc index a3303a5..3c787fe 100644 --- a/base/process/launch_win.cc +++ b/base/process/launch_win.cc
@@ -244,9 +244,17 @@ return rv; } -bool LaunchElevatedProcess(const CommandLine& cmdline, - const LaunchOptions& options, - ProcessHandle* process_handle) { +Process LaunchProcess(const CommandLine& cmdline, + const LaunchOptions& options) { + ProcessHandle process_handle; + if (LaunchProcess(cmdline, options, &process_handle)) + return Process(process_handle); + + return Process(); +} + +Process LaunchElevatedProcess(const CommandLine& cmdline, + const LaunchOptions& options) { const string16 file = cmdline.GetProgram().value(); const string16 arguments = cmdline.GetArgumentsString(); @@ -263,20 +271,13 @@ if (!ShellExecuteEx(&shex_info)) { DPLOG(ERROR); - return false; + return Process(); } if (options.wait) WaitForSingleObject(shex_info.hProcess, INFINITE); - // If the caller wants the process handle give it to them, otherwise just - // close it. Closing it does not terminate the process. - if (process_handle) - *process_handle = shex_info.hProcess; - else - CloseHandle(shex_info.hProcess); - - return true; + return Process(shex_info.hProcess); } bool SetJobObjectLimitFlags(HANDLE job_object, DWORD limit_flags) {
diff --git a/base/process/process_util_unittest.cc b/base/process/process_util_unittest.cc index a5de9fee..c98884d 100644 --- a/base/process/process_util_unittest.cc +++ b/base/process/process_util_unittest.cc
@@ -348,8 +348,8 @@ ASSERT_TRUE(OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token)); base::LaunchOptions options; options.as_user = token; - EXPECT_TRUE(base::LaunchProcess(MakeCmdLine("SimpleChildProcess"), options, - NULL)); + EXPECT_TRUE(base::LaunchProcess(MakeCmdLine("SimpleChildProcess"), + options).IsValid()); } static const char kEventToTriggerHandleSwitch[] = "event-to-trigger-handle"; @@ -393,12 +393,12 @@ // This functionality actually requires Vista or later. Make sure that it // fails properly on XP. if (base::win::GetVersion() < base::win::VERSION_VISTA) { - EXPECT_FALSE(base::LaunchProcess(cmd_line, options, NULL)); + EXPECT_FALSE(base::LaunchProcess(cmd_line, options).IsValid()); return; } // Launch the process and wait for it to trigger the event. - ASSERT_TRUE(base::LaunchProcess(cmd_line, options, NULL)); + ASSERT_TRUE(base::LaunchProcess(cmd_line, options).IsValid()); EXPECT_TRUE(event.TimedWait(TestTimeouts::action_max_timeout())); } #endif // defined(OS_WIN)
diff --git a/build/all.gyp b/build/all.gyp index 5fe54d7..9c325fb4f 100644 --- a/build/all.gyp +++ b/build/all.gyp
@@ -843,6 +843,7 @@ '../chrome/chrome.gyp:chrome_shell_test_apk', '../chrome/chrome.gyp:chrome_sync_shell_test_apk', '../chrome/chrome.gyp:chrome_shell_uiautomator_tests', + '../chrome/chrome.gyp:chromedriver_webview_shell_apk', '../chrome/chrome.gyp:unit_tests_apk', '../components/components_tests.gyp:components_unittests_apk', '../content/content_shell_and_tests.gyp:content_browsertests_apk',
diff --git a/build/android/PRESUBMIT.py b/build/android/PRESUBMIT.py index f226b37e..7bce71b8 100644 --- a/build/android/PRESUBMIT.py +++ b/build/android/PRESUBMIT.py
@@ -64,6 +64,7 @@ J('pylib', 'device', 'device_utils_test.py'), J('pylib', 'gtest', 'test_package_test.py'), J('pylib', 'instrumentation', 'test_runner_test.py'), + J('pylib', 'results', 'json_results_test.py'), J('pylib', 'utils', 'md5sum_test.py'), ], env=pylib_test_env))
diff --git a/build/android/buildbot/bb_run_bot.py b/build/android/buildbot/bb_run_bot.py index abdd2bec..38ff93a 100755 --- a/build/android/buildbot/bb_run_bot.py +++ b/build/android/buildbot/bb_run_bot.py
@@ -158,8 +158,9 @@ T(std_tests, ['--asan', '--asan-symbolize'])), B('blink-try-builder', H(compile_step)), B('chromedriver-fyi-tests-dbg', H(std_test_steps), - T(['chromedriver'], ['--install=ChromeShell', '--skip-wipe', - '--cleanup'])), + T(['chromedriver'], + ['--install=ChromeShell', '--install=ChromeDriverWebViewShell', + '--skip-wipe', '--cleanup'])), B('fyi-x86-builder-dbg', H(compile_step + std_host_tests, experimental, target_arch='ia32')), B('fyi-builder-dbg',
diff --git a/build/android/gyp/test/BUILD.gn b/build/android/gyp/test/BUILD.gn index 6621489..2deac1d 100644 --- a/build/android/gyp/test/BUILD.gn +++ b/build/android/gyp/test/BUILD.gn
@@ -5,7 +5,9 @@ } java_binary("hello_world") { - deps = [ ":hello_world_java" ] + deps = [ + ":hello_world_java", + ] java_files = [ "java/org/chromium/helloworld/HelloWorldMain.java" ] main_class = "org.chromium.helloworld.HelloWorldMain" }
diff --git a/build/android/gyp/write_build_config.py b/build/android/gyp/write_build_config.py index ed68e6c..a14ef77f 100755 --- a/build/android/gyp/write_build_config.py +++ b/build/android/gyp/write_build_config.py
@@ -213,13 +213,17 @@ c['package_name'] for c in all_resources_deps if 'package_name' in c] - if options.type == 'android_apk': - config['apk_dex'] = {} - dex_config = config['apk_dex'] + # Dependencies for the final dex file of an apk or the standalone .dex.jar + # output of a library. + if options.type == 'android_apk' or (options.type == "java_library" + and options.supports_android): + config['final_dex'] = {} + dex_config = config['final_dex'] # TODO(cjhopman): proguard version dex_deps_files = [c['dex_path'] for c in all_library_deps] dex_config['dependency_dex_files'] = dex_deps_files + if options.type == 'android_apk': config['dist_jar'] = { 'dependency_jars': [ c['jar_path'] for c in all_library_deps
diff --git a/build/android/pylib/base/environment_factory.py b/build/android/pylib/base/environment_factory.py index ad2eafd6..c96d19920 100644 --- a/build/android/pylib/base/environment_factory.py +++ b/build/android/pylib/base/environment_factory.py
@@ -3,7 +3,7 @@ # found in the LICENSE file. -def CreateEnvironment(_command, _options, error_func): +def CreateEnvironment(_args, error_func): # TODO(jbudorick) Add local device environment. # TODO(jbudorick) Add local machine environment.
diff --git a/build/android/pylib/base/test_instance_factory.py b/build/android/pylib/base/test_instance_factory.py index fd74b96..9f62278 100644 --- a/build/android/pylib/base/test_instance_factory.py +++ b/build/android/pylib/base/test_instance_factory.py
@@ -3,7 +3,7 @@ # found in the LICENSE file. -def CreateTestInstance(_command, _options, error_func): +def CreateTestInstance(_args, error_func): # TODO(jbudorick) Add gtest test instance. # TODO(jbudorick) Add instrumentation test instance.
diff --git a/build/android/pylib/base/test_run_factory.py b/build/android/pylib/base/test_run_factory.py index 50a9690bc..6ccfb37 100644 --- a/build/android/pylib/base/test_run_factory.py +++ b/build/android/pylib/base/test_run_factory.py
@@ -2,7 +2,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -def CreateTestRun(_options, _env, _test_instance, error_func): +def CreateTestRun(_args, _env, _test_instance, error_func): # TODO(jbudorick) Add local gtest test runs # TODO(jbudorick) Add local instrumentation test runs.
diff --git a/build/android/pylib/constants.py b/build/android/pylib/constants.py index 5cba3af..ac57969 100644 --- a/build/android/pylib/constants.py +++ b/build/android/pylib/constants.py
@@ -188,6 +188,7 @@ 'path': os.path.join(DIR_SOURCE_ROOT, 'build', 'android'), 'test_modules': [ 'pylib.device.device_utils_test', + 'pylib.results.json_results_test', 'pylib.utils.md5sum_test', ] }, @@ -201,6 +202,8 @@ LOCAL_MACHINE_TESTS = ['junit', 'python'] VALID_ENVIRONMENTS = ['local'] +VALID_TEST_TYPES = ['gtest', 'instrumentation', 'junit', 'linker', 'monkey', + 'perf', 'python', 'uiautomator'] def GetBuildType():
diff --git a/build/android/pylib/device/adb_wrapper.py b/build/android/pylib/device/adb_wrapper.py index c03964a..aef9ca32 100644 --- a/build/android/pylib/device/adb_wrapper.py +++ b/build/android/pylib/device/adb_wrapper.py
@@ -9,6 +9,7 @@ """ import errno +import logging import os from pylib import cmd_helper @@ -188,8 +189,7 @@ try: status = int(output[output_end+1:]) except ValueError: - output = '\n'.join([output.rstrip(), - 'adb shell error: exit status missing!']) + logging.warning('exit status of shell command %r missing.', command) raise device_errors.AdbCommandFailedError( args, output, device_serial=self._device_serial) output = output[:output_end]
diff --git a/build/android/pylib/device/device_utils.py b/build/android/pylib/device/device_utils.py index 68298578..9a19fa1 100644 --- a/build/android/pylib/device/device_utils.py +++ b/build/android/pylib/device/device_utils.py
@@ -177,11 +177,13 @@ CommandFailedError if root could not be enabled. CommandTimeoutError on timeout. """ + if self.IsUserBuild(): + raise device_errors.CommandFailedError( + 'Cannot enable root in user builds.', str(self)) if 'needs_su' in self._cache: del self._cache['needs_su'] - if not self.old_interface.EnableAdbRoot(): - raise device_errors.CommandFailedError( - 'Could not enable root.', str(self)) + self.adb.Root() + self.adb.WaitForDevice() @decorators.WithTimeoutAndRetriesFromInstance() def IsUserBuild(self, timeout=None, retries=None):
diff --git a/build/android/pylib/device/device_utils_test.py b/build/android/pylib/device/device_utils_test.py index 2afaedf..a2bbe0d 100755 --- a/build/android/pylib/device/device_utils_test.py +++ b/build/android/pylib/device/device_utils_test.py
@@ -295,29 +295,25 @@ self.assertFalse(self.device.HasRoot()) -class DeviceUtilsEnableRootTest(DeviceUtilsOldImplTest): +class DeviceUtilsEnableRootTest(DeviceUtilsNewImplTest): def testEnableRoot_succeeds(self): - with self.assertCallsSequence([ - ('adb -s 0123456789abcdef shell getprop ro.build.type', - 'userdebug\r\n'), - ('adb -s 0123456789abcdef root', 'restarting adbd as root\r\n'), - ('adb -s 0123456789abcdef wait-for-device', ''), - ('adb -s 0123456789abcdef wait-for-device', '')]): + with self.assertCalls( + (self.call.device.IsUserBuild(), False), + self.call.adb.Root(), + self.call.adb.WaitForDevice()): self.device.EnableRoot() def testEnableRoot_userBuild(self): - with self.assertCallsSequence([ - ('adb -s 0123456789abcdef shell getprop ro.build.type', 'user\r\n')]): + with self.assertCalls( + (self.call.device.IsUserBuild(), True)): with self.assertRaises(device_errors.CommandFailedError): self.device.EnableRoot() def testEnableRoot_rootFails(self): - with self.assertCallsSequence([ - ('adb -s 0123456789abcdef shell getprop ro.build.type', - 'userdebug\r\n'), - ('adb -s 0123456789abcdef root', 'no\r\n'), - ('adb -s 0123456789abcdef wait-for-device', '')]): + with self.assertCalls( + (self.call.device.IsUserBuild(), False), + (self.call.adb.Root(), self.CommandError())): with self.assertRaises(device_errors.CommandFailedError): self.device.EnableRoot()
diff --git a/build/android/pylib/junit/setup.py b/build/android/pylib/junit/setup.py index 6ae0006..94d4277 100644 --- a/build/android/pylib/junit/setup.py +++ b/build/android/pylib/junit/setup.py
@@ -4,15 +4,17 @@ from pylib.junit import test_runner -def Setup(options): +def Setup(args): """Creates a test runner factory for junit tests. + Args: + args: an argparse.Namespace object. Return: A (runner_factory, tests) tuple. """ def TestRunnerFactory(_unused_device, _unused_shard_index): - return test_runner.JavaTestRunner(options) + return test_runner.JavaTestRunner(args) return (TestRunnerFactory, ['JUnit tests'])
diff --git a/build/android/pylib/junit/test_runner.py b/build/android/pylib/junit/test_runner.py index d0803ea..35ac666 100644 --- a/build/android/pylib/junit/test_runner.py +++ b/build/android/pylib/junit/test_runner.py
@@ -10,12 +10,12 @@ class JavaTestRunner(object): """Runs java tests on the host.""" - def __init__(self, options): - self._package_filter = options.package_filter - self._runner_filter = options.runner_filter - self._sdk_version = options.sdk_version - self._test_filter = options.test_filter - self._test_suite = options.test_suite + def __init__(self, args): + self._package_filter = args.package_filter + self._runner_filter = args.runner_filter + self._sdk_version = args.sdk_version + self._test_filter = args.test_filter + self._test_suite = args.test_suite def SetUp(self): pass
diff --git a/build/android/pylib/linker/setup.py b/build/android/pylib/linker/setup.py index ebfac87..ff21f10 100644 --- a/build/android/pylib/linker/setup.py +++ b/build/android/pylib/linker/setup.py
@@ -16,9 +16,11 @@ 'common')) import unittest_util # pylint: disable=F0401 -def Setup(options, _devices): +def Setup(args, _devices): """Creates a list of test cases and a runner factory. + Args: + args: an argparse.Namespace object. Returns: A tuple of (TestRunnerFactory, tests). """ @@ -30,15 +32,15 @@ low_memory_modes = [False, True] all_tests = [t(is_low_memory=m) for t in test_cases for m in low_memory_modes] - if options.test_filter: + if args.test_filter: all_test_names = [test.qualified_name for test in all_tests] filtered_test_names = unittest_util.FilterTestNames(all_test_names, - options.test_filter) + args.test_filter) all_tests = [t for t in all_tests \ if t.qualified_name in filtered_test_names] def TestRunnerFactory(device, _shard_index): return test_runner.LinkerTestRunner( - device, options.tool, options.cleanup_test_files) + device, args.tool, args.cleanup_test_files) return (TestRunnerFactory, all_tests)
diff --git a/build/android/pylib/perf/test_runner.py b/build/android/pylib/perf/test_runner.py index f70358d5..a8048d4 100644 --- a/build/android/pylib/perf/test_runner.py +++ b/build/android/pylib/perf/test_runner.py
@@ -274,6 +274,7 @@ except cmd_helper.TimeoutError as e: exit_code = -1 output = str(e) + json_output = '' finally: self._CleanupOutputDirectory() if self._options.single_step:
diff --git a/build/android/pylib/results/__init__.py b/build/android/pylib/results/__init__.py new file mode 100644 index 0000000..4d6aabb9 --- /dev/null +++ b/build/android/pylib/results/__init__.py
@@ -0,0 +1,3 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file.
diff --git a/build/android/pylib/results/flakiness_dashboard/__init__.py b/build/android/pylib/results/flakiness_dashboard/__init__.py new file mode 100644 index 0000000..4d6aabb9 --- /dev/null +++ b/build/android/pylib/results/flakiness_dashboard/__init__.py
@@ -0,0 +1,3 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file.
diff --git a/build/android/pylib/utils/json_results_generator.py b/build/android/pylib/results/flakiness_dashboard/json_results_generator.py similarity index 100% rename from build/android/pylib/utils/json_results_generator.py rename to build/android/pylib/results/flakiness_dashboard/json_results_generator.py
diff --git a/build/android/pylib/utils/flakiness_dashboard_results_uploader.py b/build/android/pylib/results/flakiness_dashboard/results_uploader.py similarity index 97% rename from build/android/pylib/utils/flakiness_dashboard_results_uploader.py rename to build/android/pylib/results/flakiness_dashboard/results_uploader.py index ff286b63..856fa9c 100644 --- a/build/android/pylib/utils/flakiness_dashboard_results_uploader.py +++ b/build/android/pylib/results/flakiness_dashboard/results_uploader.py
@@ -12,10 +12,9 @@ import xml -#TODO(craigdh): pylib/utils/ should not depend on pylib/. from pylib import cmd_helper from pylib import constants -from pylib.utils import json_results_generator +from pylib.results.flakiness_dashboard import json_results_generator from pylib.utils import repo_utils
diff --git a/build/android/pylib/results/json_results.py b/build/android/pylib/results/json_results.py new file mode 100644 index 0000000..c34244e --- /dev/null +++ b/build/android/pylib/results/json_results.py
@@ -0,0 +1,73 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import json +import logging + +from pylib.base import base_test_result + + +def GenerateResultsDict(test_run_result): + """Create a results dict from |test_run_result| suitable for writing to JSON. + Args: + test_run_result: a base_test_result.TestRunResults object. + Returns: + A results dict that mirrors the one generated by + base/test/launcher/test_results_tracker.cc:SaveSummaryAsJSON. + """ + assert isinstance(test_run_result, base_test_result.TestRunResults) + + def status_as_string(s): + if s == base_test_result.ResultType.PASS: + return 'SUCCESS' + elif s == base_test_result.ResultType.SKIP: + return 'SKIPPED' + elif s == base_test_result.ResultType.FAIL: + return 'FAILURE' + elif s == base_test_result.ResultType.CRASH: + return 'CRASH' + elif s == base_test_result.ResultType.TIMEOUT: + return 'TIMEOUT' + elif s == base_test_result.ResultType.UNKNOWN: + return 'UNKNOWN' + + def generate_iteration_data(t): + return { + t.GetName(): [ + { + 'status': status_as_string(t.GetType()), + 'elapsed_time_ms': t.GetDuration(), + 'output_snippet': '', + 'losless_snippet': '', + 'output_snippet_base64:': '', + } + ] + } + + all_tests_tuple, per_iteration_data_tuple = zip( + *[(t.GetName(), generate_iteration_data(t)) + for t in test_run_result.GetAll()]) + + return { + 'global_tags': [], + 'all_tests': list(all_tests_tuple), + # TODO(jbudorick): Add support for disabled tests within base_test_result. + 'disabled_tests': [], + 'per_iteration_data': list(per_iteration_data_tuple), + } + + +def GenerateJsonResultsFile(test_run_result, file_path): + """Write |test_run_result| to JSON. + + This emulates the format of the JSON emitted by + base/test/launcher/test_results_tracker.cc:SaveSummaryAsJSON. + + Args: + test_run_result: a base_test_result.TestRunResults object. + file_path: The path to the JSON file to write. + """ + with open(file_path, 'w') as json_result_file: + json_result_file.write(json.dumps(GenerateResultsDict(test_run_result))) +
diff --git a/build/android/pylib/results/json_results_test.py b/build/android/pylib/results/json_results_test.py new file mode 100755 index 0000000..1bc730d --- /dev/null +++ b/build/android/pylib/results/json_results_test.py
@@ -0,0 +1,133 @@ +#!/usr/bin/env python +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import unittest + +from pylib.base import base_test_result +from pylib.results import json_results + + +class JsonResultsTest(unittest.TestCase): + + def testGenerateResultsDict_passedResult(self): + result = base_test_result.BaseTestResult( + 'test.package.TestName', base_test_result.ResultType.PASS) + + all_results = base_test_result.TestRunResults() + all_results.AddResult(result) + + results_dict = json_results.GenerateResultsDict(all_results) + self.assertEquals( + ['test.package.TestName'], + results_dict['all_tests']) + self.assertEquals(1, len(results_dict['per_iteration_data'])) + + iteration_result = results_dict['per_iteration_data'][0] + self.assertTrue('test.package.TestName' in iteration_result) + self.assertEquals(1, len(iteration_result['test.package.TestName'])) + + test_iteration_result = iteration_result['test.package.TestName'][0] + self.assertTrue('status' in test_iteration_result) + self.assertEquals('SUCCESS', test_iteration_result['status']) + + def testGenerateResultsDict_skippedResult(self): + result = base_test_result.BaseTestResult( + 'test.package.TestName', base_test_result.ResultType.SKIP) + + all_results = base_test_result.TestRunResults() + all_results.AddResult(result) + + results_dict = json_results.GenerateResultsDict(all_results) + self.assertEquals( + ['test.package.TestName'], + results_dict['all_tests']) + self.assertEquals(1, len(results_dict['per_iteration_data'])) + + iteration_result = results_dict['per_iteration_data'][0] + self.assertTrue('test.package.TestName' in iteration_result) + self.assertEquals(1, len(iteration_result['test.package.TestName'])) + + test_iteration_result = iteration_result['test.package.TestName'][0] + self.assertTrue('status' in test_iteration_result) + self.assertEquals('SKIPPED', test_iteration_result['status']) + + def testGenerateResultsDict_failedResult(self): + result = base_test_result.BaseTestResult( + 'test.package.TestName', base_test_result.ResultType.FAIL) + + all_results = base_test_result.TestRunResults() + all_results.AddResult(result) + + results_dict = json_results.GenerateResultsDict(all_results) + self.assertEquals( + ['test.package.TestName'], + results_dict['all_tests']) + self.assertEquals(1, len(results_dict['per_iteration_data'])) + + iteration_result = results_dict['per_iteration_data'][0] + self.assertTrue('test.package.TestName' in iteration_result) + self.assertEquals(1, len(iteration_result['test.package.TestName'])) + + test_iteration_result = iteration_result['test.package.TestName'][0] + self.assertTrue('status' in test_iteration_result) + self.assertEquals('FAILURE', test_iteration_result['status']) + + def testGenerateResultsDict_duration(self): + result = base_test_result.BaseTestResult( + 'test.package.TestName', base_test_result.ResultType.PASS, duration=123) + + all_results = base_test_result.TestRunResults() + all_results.AddResult(result) + + results_dict = json_results.GenerateResultsDict(all_results) + self.assertEquals( + ['test.package.TestName'], + results_dict['all_tests']) + self.assertEquals(1, len(results_dict['per_iteration_data'])) + + iteration_result = results_dict['per_iteration_data'][0] + self.assertTrue('test.package.TestName' in iteration_result) + self.assertEquals(1, len(iteration_result['test.package.TestName'])) + + test_iteration_result = iteration_result['test.package.TestName'][0] + self.assertTrue('elapsed_time_ms' in test_iteration_result) + self.assertEquals(123, test_iteration_result['elapsed_time_ms']) + + def testGenerateResultsDict_multipleResults(self): + result1 = base_test_result.BaseTestResult( + 'test.package.TestName1', base_test_result.ResultType.PASS) + result2 = base_test_result.BaseTestResult( + 'test.package.TestName2', base_test_result.ResultType.PASS) + + all_results = base_test_result.TestRunResults() + all_results.AddResult(result1) + all_results.AddResult(result2) + + results_dict = json_results.GenerateResultsDict(all_results) + self.assertEquals( + ['test.package.TestName1', 'test.package.TestName2'], + results_dict['all_tests']) + self.assertEquals(2, len(results_dict['per_iteration_data'])) + + expected_tests = set([ + 'test.package.TestName1', + 'test.package.TestName2', + ]) + + for iteration_result in results_dict['per_iteration_data']: + self.assertEquals(1, len(iteration_result)) + name = iteration_result.keys()[0] + self.assertTrue(name in expected_tests) + expected_tests.remove(name) + self.assertEquals(1, len(iteration_result[name])) + + test_iteration_result = iteration_result[name][0] + self.assertTrue('status' in test_iteration_result) + self.assertEquals('SUCCESS', test_iteration_result['status']) + + +if __name__ == '__main__': + unittest.main(verbosity=2) +
diff --git a/build/android/pylib/utils/report_results.py b/build/android/pylib/results/report_results.py similarity index 97% rename from build/android/pylib/utils/report_results.py rename to build/android/pylib/results/report_results.py index 8f81c95..4c9518e5 100644 --- a/build/android/pylib/utils/report_results.py +++ b/build/android/pylib/results/report_results.py
@@ -9,7 +9,7 @@ import re from pylib import constants -from pylib.utils import flakiness_dashboard_results_uploader +from pylib.results.flakiness_dashboard import results_uploader def _LogToFile(results, test_type, suite_name): @@ -58,7 +58,7 @@ logging.warning('Invalid test type') return - flakiness_dashboard_results_uploader.Upload( + results_uploader.Upload( results, flakiness_server, dashboard_test_type) except Exception as e:
diff --git a/build/android/test_runner.py b/build/android/test_runner.py index 7d11e720..e5016e2 100755 --- a/build/android/test_runner.py +++ b/build/android/test_runner.py
@@ -6,9 +6,9 @@ """Runs all types of tests from one unified interface.""" +import argparse import collections import logging -import optparse import os import shutil import signal @@ -39,191 +39,166 @@ from pylib.perf import setup as perf_setup from pylib.perf import test_options as perf_test_options from pylib.perf import test_runner as perf_test_runner +from pylib.results import json_results +from pylib.results import report_results from pylib.uiautomator import setup as uiautomator_setup from pylib.uiautomator import test_options as uiautomator_test_options from pylib.utils import apk_helper -from pylib.utils import command_option_parser -from pylib.utils import report_results from pylib.utils import reraiser_thread from pylib.utils import run_tests_helper -def AddCommonOptions(option_parser): - """Adds all common options to |option_parser|.""" +def AddCommonOptions(parser): + """Adds all common options to |parser|.""" - group = optparse.OptionGroup(option_parser, 'Common Options') + group = parser.add_argument_group('Common Options') + default_build_type = os.environ.get('BUILDTYPE', 'Debug') - group.add_option('--debug', action='store_const', const='Debug', - dest='build_type', default=default_build_type, - help=('If set, run test suites under out/Debug. ' - 'Default is env var BUILDTYPE or Debug.')) - group.add_option('--release', action='store_const', - const='Release', dest='build_type', - help=('If set, run test suites under out/Release.' - ' Default is env var BUILDTYPE or Debug.')) - group.add_option('--build-directory', dest='build_directory', - help=('Path to the directory in which build files are' - ' located (should not include build type)')) - group.add_option('--output-directory', dest='output_directory', - help=('Path to the directory in which build files are' - ' located (must include build type). This will take' - ' precedence over --debug, --release and' - ' --build-directory')) - group.add_option('--num_retries', dest='num_retries', type='int', - default=2, - help=('Number of retries for a test before ' - 'giving up.')) - group.add_option('-v', - '--verbose', - dest='verbose_count', - default=0, - action='count', - help='Verbose level (multiple times for more)') - group.add_option('--flakiness-dashboard-server', - dest='flakiness_dashboard_server', - help=('Address of the server that is hosting the ' - 'Chrome for Android flakiness dashboard.')) - group.add_option('--enable-platform-mode', action='store_true', - help=('Run the test scripts in platform mode, which ' - 'conceptually separates the test runner from the ' - '"device" (local or remote, real or emulated) on ' - 'which the tests are running. [experimental]')) - group.add_option('-e', '--environment', default='local', - help=('Test environment to run in. Must be one of: %s' % - ', '.join(constants.VALID_ENVIRONMENTS))) - group.add_option('--adb-path', - help=('Specify the absolute path of the adb binary that ' - 'should be used.')) - option_parser.add_option_group(group) + + debug_or_release_group = group.add_mutually_exclusive_group() + debug_or_release_group.add_argument( + '--debug', action='store_const', const='Debug', dest='build_type', + default=default_build_type, + help=('If set, run test suites under out/Debug. ' + 'Default is env var BUILDTYPE or Debug.')) + debug_or_release_group.add_argument( + '--release', action='store_const', const='Release', dest='build_type', + help=('If set, run test suites under out/Release. ' + 'Default is env var BUILDTYPE or Debug.')) + + group.add_argument('--build-directory', dest='build_directory', + help=('Path to the directory in which build files are' + ' located (should not include build type)')) + group.add_argument('--output-directory', dest='output_directory', + help=('Path to the directory in which build files are' + ' located (must include build type). This will take' + ' precedence over --debug, --release and' + ' --build-directory')) + group.add_argument('--num_retries', dest='num_retries', type=int, default=2, + help=('Number of retries for a test before ' + 'giving up (default: %(default)s).')) + group.add_argument('-v', + '--verbose', + dest='verbose_count', + default=0, + action='count', + help='Verbose level (multiple times for more)') + group.add_argument('--flakiness-dashboard-server', + dest='flakiness_dashboard_server', + help=('Address of the server that is hosting the ' + 'Chrome for Android flakiness dashboard.')) + group.add_argument('--enable-platform-mode', action='store_true', + help=('Run the test scripts in platform mode, which ' + 'conceptually separates the test runner from the ' + '"device" (local or remote, real or emulated) on ' + 'which the tests are running. [experimental]')) + group.add_argument('-e', '--environment', default='local', + choices=constants.VALID_ENVIRONMENTS, + help='Test environment to run in (default: %(default)s).') + group.add_argument('--adb-path', + help=('Specify the absolute path of the adb binary that ' + 'should be used.')) + group.add_argument('--json-results-file', dest='json_results_file', + help='If set, will dump results in JSON form ' + 'to specified file.') -def ProcessCommonOptions(options, error_func): +def ProcessCommonOptions(args): """Processes and handles all common options.""" - run_tests_helper.SetLogLevel(options.verbose_count) - constants.SetBuildType(options.build_type) - if options.build_directory: - constants.SetBuildDirectory(options.build_directory) - if options.output_directory: - constants.SetOutputDirectort(options.output_directory) - if options.adb_path: - constants.SetAdbPath(options.adb_path) + run_tests_helper.SetLogLevel(args.verbose_count) + constants.SetBuildType(args.build_type) + if args.build_directory: + constants.SetBuildDirectory(args.build_directory) + if args.output_directory: + constants.SetOutputDirectort(args.output_directory) + if args.adb_path: + constants.SetAdbPath(args.adb_path) # Some things such as Forwarder require ADB to be in the environment path. adb_dir = os.path.dirname(constants.GetAdbPath()) if adb_dir and adb_dir not in os.environ['PATH'].split(os.pathsep): os.environ['PATH'] = adb_dir + os.pathsep + os.environ['PATH'] - if options.environment not in constants.VALID_ENVIRONMENTS: - error_func('--environment must be one of: %s' % - ', '.join(constants.VALID_ENVIRONMENTS)) -def AddDeviceOptions(option_parser): - group = optparse.OptionGroup(option_parser, 'Device Options') - group.add_option('-c', dest='cleanup_test_files', - help='Cleanup test files on the device after run', - action='store_true') - group.add_option('--tool', - dest='tool', - help=('Run the test under a tool ' - '(use --tool help to list them)')) - group.add_option('-d', '--device', dest='test_device', - help=('Target device for the test suite ' - 'to run on.')) - option_parser.add_option_group(group) +def AddDeviceOptions(parser): + """Adds device options to |parser|.""" + group = parser.add_argument_group(title='Device Options') + group.add_argument('-c', dest='cleanup_test_files', + help='Cleanup test files on the device after run', + action='store_true') + group.add_argument('--tool', + dest='tool', + help=('Run the test under a tool ' + '(use --tool help to list them)')) + group.add_argument('-d', '--device', dest='test_device', + help=('Target device for the test suite ' + 'to run on.')) -def AddGTestOptions(option_parser): - """Adds gtest options to |option_parser|.""" +def AddGTestOptions(parser): + """Adds gtest options to |parser|.""" - option_parser.usage = '%prog gtest [options]' - option_parser.commands_dict = {} - option_parser.example = '%prog gtest -s base_unittests' + gtest_suites = list(gtest_config.STABLE_TEST_SUITES + + gtest_config.EXPERIMENTAL_TEST_SUITES) - # TODO(gkanwar): Make this option required - option_parser.add_option('-s', '--suite', dest='suite_name', - help=('Executable name of the test suite to run ' - '(use -s help to list them).')) - option_parser.add_option('-f', '--gtest_filter', '--gtest-filter', - dest='test_filter', - help='googletest-style filter string.') - option_parser.add_option('--gtest_also_run_disabled_tests', - '--gtest-also-run-disabled-tests', - dest='run_disabled', action='store_true', - help='Also run disabled tests if applicable.') - option_parser.add_option('-a', '--test-arguments', dest='test_arguments', - default='', - help='Additional arguments to pass to the test.') - option_parser.add_option('-t', dest='timeout', - help='Timeout to wait for each test', - type='int', - default=60) - option_parser.add_option('--isolate_file_path', - '--isolate-file-path', - dest='isolate_file_path', - help='.isolate file path to override the default ' - 'path') - # TODO(gkanwar): Move these to Common Options once we have the plumbing - # in our other test types to handle these commands - AddCommonOptions(option_parser) - AddDeviceOptions(option_parser) + group = parser.add_argument_group('GTest Options') + group.add_argument('-s', '--suite', dest='suite_name', choices=gtest_suites, + nargs='+', metavar='SUITE_NAME', required=True, + help=('Executable name of the test suite to run.')) + group.add_argument('-f', '--gtest_filter', '--gtest-filter', + dest='test_filter', + help='googletest-style filter string.') + group.add_argument('--gtest_also_run_disabled_tests', + '--gtest-also-run-disabled-tests', + dest='run_disabled', action='store_true', + help='Also run disabled tests if applicable.') + group.add_argument('-a', '--test-arguments', dest='test_arguments', + default='', + help='Additional arguments to pass to the test.') + group.add_argument('-t', dest='timeout', type=int, default=60, + help='Timeout to wait for each test ' + '(default: %(default)s).') + group.add_argument('--isolate_file_path', + '--isolate-file-path', + dest='isolate_file_path', + help='.isolate file path to override the default ' + 'path') + AddDeviceOptions(parser) + AddCommonOptions(parser) -def AddLinkerTestOptions(option_parser): - option_parser.usage = '%prog linker' - option_parser.commands_dict = {} - option_parser.example = '%prog linker' - - option_parser.add_option('-f', '--gtest-filter', dest='test_filter', - help='googletest-style filter string.') - AddCommonOptions(option_parser) - AddDeviceOptions(option_parser) +def AddLinkerTestOptions(parser): + group = parser.add_argument_group('Linker Test Options') + group.add_argument('-f', '--gtest-filter', dest='test_filter', + help='googletest-style filter string.') + AddCommonOptions(parser) + AddDeviceOptions(parser) -def ProcessGTestOptions(options): - """Intercept test suite help to list test suites. - - Args: - options: Command line options. - """ - if options.suite_name == 'help': - print 'Available test suites are:' - for test_suite in (gtest_config.STABLE_TEST_SUITES + - gtest_config.EXPERIMENTAL_TEST_SUITES): - print test_suite - sys.exit(0) - - # Convert to a list, assuming all test suites if nothing was specified. - # TODO(gkanwar): Require having a test suite - if options.suite_name: - options.suite_name = [options.suite_name] - else: - options.suite_name = [s for s in gtest_config.STABLE_TEST_SUITES] - - -def AddJavaTestOptions(option_parser): +def AddJavaTestOptions(argument_group): """Adds the Java test options to |option_parser|.""" - option_parser.add_option('-f', '--test-filter', dest='test_filter', - help=('Test filter (if not fully qualified, ' - 'will run all matches).')) - option_parser.add_option( + argument_group.add_argument( + '-f', '--test-filter', dest='test_filter', + help=('Test filter (if not fully qualified, will run all matches).')) + argument_group.add_argument( '-A', '--annotation', dest='annotation_str', help=('Comma-separated list of annotations. Run only tests with any of ' 'the given annotations. An annotation can be either a key or a ' 'key-values pair. A test that has no annotation is considered ' '"SmallTest".')) - option_parser.add_option( + argument_group.add_argument( '-E', '--exclude-annotation', dest='exclude_annotation_str', help=('Comma-separated list of annotations. Exclude tests with these ' 'annotations.')) - option_parser.add_option( + argument_group.add_argument( '--screenshot', dest='screenshot_failures', action='store_true', help='Capture screenshots of test failures') - option_parser.add_option( + argument_group.add_argument( '--save-perf-json', action='store_true', help='Saves the JSON file for each UI Perf test.') - option_parser.add_option( + argument_group.add_argument( '--official-build', action='store_true', help='Run official build tests.') - option_parser.add_option( + argument_group.add_argument( '--test_data', '--test-data', action='append', default=[], help=('Each instance defines a directory of test data that should be ' 'copied to the target(s) before running the tests. The argument ' @@ -232,411 +207,360 @@ 'chromium build directory.')) -def ProcessJavaTestOptions(options): +def ProcessJavaTestOptions(args): """Processes options/arguments and populates |options| with defaults.""" - if options.annotation_str: - options.annotations = options.annotation_str.split(',') - elif options.test_filter: - options.annotations = [] + # TODO(jbudorick): Handle most of this function in argparse. + if args.annotation_str: + args.annotations = args.annotation_str.split(',') + elif args.test_filter: + args.annotations = [] else: - options.annotations = ['Smoke', 'SmallTest', 'MediumTest', 'LargeTest', - 'EnormousTest', 'IntegrationTest'] + args.annotations = ['Smoke', 'SmallTest', 'MediumTest', 'LargeTest', + 'EnormousTest', 'IntegrationTest'] - if options.exclude_annotation_str: - options.exclude_annotations = options.exclude_annotation_str.split(',') + if args.exclude_annotation_str: + args.exclude_annotations = args.exclude_annotation_str.split(',') else: - options.exclude_annotations = [] + args.exclude_annotations = [] -def AddInstrumentationTestOptions(option_parser): - """Adds Instrumentation test options to |option_parser|.""" +def AddInstrumentationTestOptions(parser): + """Adds Instrumentation test options to |parser|.""" - option_parser.usage = '%prog instrumentation [options]' - option_parser.commands_dict = {} - option_parser.example = ('%prog instrumentation ' - '--test-apk=ChromeShellTest') + parser.usage = '%(prog)s [options]' - AddJavaTestOptions(option_parser) - AddCommonOptions(option_parser) - AddDeviceOptions(option_parser) + group = parser.add_argument_group('Instrumentation Test Options') + AddJavaTestOptions(group) - option_parser.add_option('-j', '--java-only', action='store_true', - default=False, help='Run only the Java tests.') - option_parser.add_option('-p', '--python-only', action='store_true', - default=False, - help='Run only the host-driven tests.') - option_parser.add_option('--host-driven-root', - help='Root of the host-driven tests.') - option_parser.add_option('-w', '--wait_debugger', dest='wait_for_debugger', - action='store_true', - help='Wait for debugger.') - option_parser.add_option( - '--test-apk', dest='test_apk', - help=('The name of the apk containing the tests ' - '(without the .apk extension; e.g. "ContentShellTest").')) - option_parser.add_option('--coverage-dir', - help=('Directory in which to place all generated ' - 'EMMA coverage files.')) - option_parser.add_option('--device-flags', dest='device_flags', default='', - help='The relative filepath to a file containing ' - 'command-line flags to set on the device') - option_parser.add_option('--isolate_file_path', - '--isolate-file-path', - dest='isolate_file_path', - help='.isolate file path to override the default ' - 'path') + java_or_python_group = group.add_mutually_exclusive_group() + java_or_python_group.add_argument( + '-j', '--java-only', action='store_false', + dest='run_python_tests', default=True, help='Run only the Java tests.') + java_or_python_group.add_argument( + '-p', '--python-only', action='store_false', + dest='run_java_tests', default=True, + help='Run only the host-driven tests.') + + group.add_argument('--host-driven-root', + help='Root of the host-driven tests.') + group.add_argument('-w', '--wait_debugger', dest='wait_for_debugger', + action='store_true', + help='Wait for debugger.') + group.add_argument('--test-apk', dest='test_apk', required=True, + help=('The name of the apk containing the tests ' + '(without the .apk extension; ' + 'e.g. "ContentShellTest").')) + group.add_argument('--coverage-dir', + help=('Directory in which to place all generated ' + 'EMMA coverage files.')) + group.add_argument('--device-flags', dest='device_flags', default='', + help='The relative filepath to a file containing ' + 'command-line flags to set on the device') + group.add_argument('--isolate_file_path', + '--isolate-file-path', + dest='isolate_file_path', + help='.isolate file path to override the default ' + 'path') + + AddCommonOptions(parser) + AddDeviceOptions(parser) -def ProcessInstrumentationOptions(options, error_func): +def ProcessInstrumentationOptions(args): """Processes options/arguments and populate |options| with defaults. Args: - options: optparse.Options object. - error_func: Function to call with the error message in case of an error. + args: argparse.Namespace object. Returns: An InstrumentationOptions named tuple which contains all options relevant to instrumentation tests. """ - ProcessJavaTestOptions(options) + ProcessJavaTestOptions(args) - if options.java_only and options.python_only: - error_func('Options java_only (-j) and python_only (-p) ' - 'are mutually exclusive.') - options.run_java_tests = True - options.run_python_tests = True - if options.java_only: - options.run_python_tests = False - elif options.python_only: - options.run_java_tests = False + if not args.host_driven_root: + args.run_python_tests = False - if not options.host_driven_root: - options.run_python_tests = False - - if not options.test_apk: - error_func('--test-apk must be specified.') - - - options.test_apk_path = os.path.join( + args.test_apk_path = os.path.join( constants.GetOutDirectory(), constants.SDK_BUILD_APKS_DIR, - '%s.apk' % options.test_apk) - options.test_apk_jar_path = os.path.join( + '%s.apk' % args.test_apk) + args.test_apk_jar_path = os.path.join( constants.GetOutDirectory(), constants.SDK_BUILD_TEST_JAVALIB_DIR, - '%s.jar' % options.test_apk) - options.test_support_apk_path = '%sSupport%s' % ( - os.path.splitext(options.test_apk_path)) + '%s.jar' % args.test_apk) + args.test_support_apk_path = '%sSupport%s' % ( + os.path.splitext(args.test_apk_path)) - options.test_runner = apk_helper.GetInstrumentationName(options.test_apk_path) + args.test_runner = apk_helper.GetInstrumentationName(args.test_apk_path) + # TODO(jbudorick): Get rid of InstrumentationOptions. return instrumentation_test_options.InstrumentationOptions( - options.tool, - options.cleanup_test_files, - options.annotations, - options.exclude_annotations, - options.test_filter, - options.test_data, - options.save_perf_json, - options.screenshot_failures, - options.wait_for_debugger, - options.coverage_dir, - options.test_apk, - options.test_apk_path, - options.test_apk_jar_path, - options.test_runner, - options.test_support_apk_path, - options.device_flags, - options.isolate_file_path + args.tool, + args.cleanup_test_files, + args.annotations, + args.exclude_annotations, + args.test_filter, + args.test_data, + args.save_perf_json, + args.screenshot_failures, + args.wait_for_debugger, + args.coverage_dir, + args.test_apk, + args.test_apk_path, + args.test_apk_jar_path, + args.test_runner, + args.test_support_apk_path, + args.device_flags, + args.isolate_file_path ) -def AddUIAutomatorTestOptions(option_parser): - """Adds UI Automator test options to |option_parser|.""" +def AddUIAutomatorTestOptions(parser): + """Adds UI Automator test options to |parser|.""" - option_parser.usage = '%prog uiautomator [options]' - option_parser.commands_dict = {} - option_parser.example = ( - '%prog uiautomator --test-jar=chrome_shell_uiautomator_tests' - ' --package=chrome_shell') - option_parser.add_option( - '--package', - help=('Package under test. Possible values: %s' % - constants.PACKAGE_INFO.keys())) - option_parser.add_option( - '--test-jar', dest='test_jar', + group = parser.add_argument_group('UIAutomator Test Options') + AddJavaTestOptions(group) + group.add_argument( + '--package', required=True, choices=constants.PACKAGE_INFO.keys(), + metavar='PACKAGE', help='Package under test.') + group.add_argument( + '--test-jar', dest='test_jar', required=True, help=('The name of the dexed jar containing the tests (without the ' '.dex.jar extension). Alternatively, this can be a full path ' 'to the jar.')) - AddJavaTestOptions(option_parser) - AddCommonOptions(option_parser) - AddDeviceOptions(option_parser) + AddCommonOptions(parser) + AddDeviceOptions(parser) -def ProcessUIAutomatorOptions(options, error_func): +def ProcessUIAutomatorOptions(args): """Processes UIAutomator options/arguments. Args: - options: optparse.Options object. - error_func: Function to call with the error message in case of an error. + args: argparse.Namespace object. Returns: A UIAutomatorOptions named tuple which contains all options relevant to uiautomator tests. """ - ProcessJavaTestOptions(options) + ProcessJavaTestOptions(args) - if not options.package: - error_func('--package is required.') - - if options.package not in constants.PACKAGE_INFO: - error_func('Invalid package.') - - if not options.test_jar: - error_func('--test-jar must be specified.') - - if os.path.exists(options.test_jar): + if os.path.exists(args.test_jar): # The dexed JAR is fully qualified, assume the info JAR lives along side. - options.uiautomator_jar = options.test_jar + args.uiautomator_jar = args.test_jar else: - options.uiautomator_jar = os.path.join( + args.uiautomator_jar = os.path.join( constants.GetOutDirectory(), constants.SDK_BUILD_JAVALIB_DIR, - '%s.dex.jar' % options.test_jar) - options.uiautomator_info_jar = ( - options.uiautomator_jar[:options.uiautomator_jar.find('.dex.jar')] + + '%s.dex.jar' % args.test_jar) + args.uiautomator_info_jar = ( + args.uiautomator_jar[:args.uiautomator_jar.find('.dex.jar')] + '_java.jar') return uiautomator_test_options.UIAutomatorOptions( - options.tool, - options.cleanup_test_files, - options.annotations, - options.exclude_annotations, - options.test_filter, - options.test_data, - options.save_perf_json, - options.screenshot_failures, - options.uiautomator_jar, - options.uiautomator_info_jar, - options.package) + args.tool, + args.cleanup_test_files, + args.annotations, + args.exclude_annotations, + args.test_filter, + args.test_data, + args.save_perf_json, + args.screenshot_failures, + args.uiautomator_jar, + args.uiautomator_info_jar, + args.package) -def AddJUnitTestOptions(option_parser): - """Adds junit test options to |option_parser|.""" - option_parser.usage = '%prog junit -s [test suite name]' - option_parser.commands_dict = {} +def AddJUnitTestOptions(parser): + """Adds junit test options to |parser|.""" - option_parser.add_option( - '-s', '--test-suite', dest='test_suite', + group = parser.add_argument_group('JUnit Test Options') + group.add_argument( + '-s', '--test-suite', dest='test_suite', required=True, help=('JUnit test suite to run.')) - option_parser.add_option( + group.add_argument( '-f', '--test-filter', dest='test_filter', help='Filters tests googletest-style.') - option_parser.add_option( + group.add_argument( '--package-filter', dest='package_filter', help='Filters tests by package.') - option_parser.add_option( + group.add_argument( '--runner-filter', dest='runner_filter', help='Filters tests by runner class. Must be fully qualified.') - option_parser.add_option( - '--sdk-version', dest='sdk_version', type="int", + group.add_argument( + '--sdk-version', dest='sdk_version', type=int, help='The Android SDK version.') - AddCommonOptions(option_parser) + AddCommonOptions(parser) -def ProcessJUnitTestOptions(options, error_func): - """Processes all JUnit test options.""" - if not options.test_suite: - error_func('No test suite specified.') - return options +def AddMonkeyTestOptions(parser): + """Adds monkey test options to |parser|.""" - -def AddMonkeyTestOptions(option_parser): - """Adds monkey test options to |option_parser|.""" - - option_parser.usage = '%prog monkey [options]' - option_parser.commands_dict = {} - option_parser.example = ( - '%prog monkey --package=chrome_shell') - - option_parser.add_option( - '--package', - help=('Package under test. Possible values: %s' % - constants.PACKAGE_INFO.keys())) - option_parser.add_option( - '--event-count', default=10000, type='int', - help='Number of events to generate [default: %default].') - option_parser.add_option( + group = parser.add_argument_group('Monkey Test Options') + group.add_argument( + '--package', required=True, choices=constants.PACKAGE_INFO.keys(), + metavar='PACKAGE', help='Package under test.') + group.add_argument( + '--event-count', default=10000, type=int, + help='Number of events to generate (default: %(default)s).') + group.add_argument( '--category', default='', help='A list of allowed categories.') - option_parser.add_option( - '--throttle', default=100, type='int', - help='Delay between events (ms) [default: %default]. ') - option_parser.add_option( - '--seed', type='int', + group.add_argument( + '--throttle', default=100, type=int, + help='Delay between events (ms) (default: %(default)s). ') + group.add_argument( + '--seed', type=int, help=('Seed value for pseudo-random generator. Same seed value generates ' 'the same sequence of events. Seed is randomized by default.')) - option_parser.add_option( + group.add_argument( '--extra-args', default='', - help=('String of other args to pass to the command verbatim ' - '[default: "%default"].')) + help=('String of other args to pass to the command verbatim.')) - AddCommonOptions(option_parser) - AddDeviceOptions(option_parser) + AddCommonOptions(parser) + AddDeviceOptions(parser) -def ProcessMonkeyTestOptions(options, error_func): +def ProcessMonkeyTestOptions(args): """Processes all monkey test options. Args: - options: optparse.Options object. - error_func: Function to call with the error message in case of an error. + args: argparse.Namespace object. Returns: A MonkeyOptions named tuple which contains all options relevant to monkey tests. """ - if not options.package: - error_func('--package is required.') - - if options.package not in constants.PACKAGE_INFO: - error_func('Invalid package.') - - category = options.category + # TODO(jbudorick): Handle this directly in argparse with nargs='+' + category = args.category if category: - category = options.category.split(',') + category = args.category.split(',') + # TODO(jbudorick): Get rid of MonkeyOptions. return monkey_test_options.MonkeyOptions( - options.verbose_count, - options.package, - options.event_count, + args.verbose_count, + args.package, + args.event_count, category, - options.throttle, - options.seed, - options.extra_args) + args.throttle, + args.seed, + args.extra_args) -def AddPerfTestOptions(option_parser): - """Adds perf test options to |option_parser|.""" +def AddPerfTestOptions(parser): + """Adds perf test options to |parser|.""" - option_parser.usage = '%prog perf [options]' - option_parser.commands_dict = {} - option_parser.example = ('%prog perf ' - '[--single-step -- command args] or ' - '[--steps perf_steps.json] or ' - '[--print-step step]') + group = parser.add_argument_group('Perf Test Options') - option_parser.add_option( - '--single-step', - action='store_true', + class SingleStepAction(argparse.Action): + def __call__(self, parser, namespace, values, option_string=None): + if values and not namespace.single_step: + parser.error('single step command provided, ' + 'but --single-step not specified.') + elif namespace.single_step and not values: + parser.error('--single-step specified, ' + 'but no single step command provided.') + setattr(namespace, self.dest, values) + + step_group = group.add_mutually_exclusive_group(required=True) + # TODO(jbudorick): Revise --single-step to use argparse.REMAINDER. + # This requires removing "--" from client calls. + step_group.add_argument( + '--single-step', action='store_true', help='Execute the given command with retries, but only print the result ' 'for the "most successful" round.') - option_parser.add_option( + step_group.add_argument( '--steps', help='JSON file containing the list of commands to run.') - option_parser.add_option( - '--flaky-steps', - help=('A JSON file containing steps that are flaky ' - 'and will have its exit code ignored.')) - option_parser.add_option( + step_group.add_argument( + '--print-step', + help='The name of a previously executed perf step to print.') + + group.add_argument( '--output-json-list', help='Write a simple list of names from --steps into the given file.') - option_parser.add_option( + group.add_argument( '--collect-chartjson-data', action='store_true', help='Cache the chartjson output from each step for later use.') - option_parser.add_option( + group.add_argument( '--output-chartjson-data', default='', help='Write out chartjson into the given file.') - option_parser.add_option( - '--print-step', - help='The name of a previously executed perf step to print.') - option_parser.add_option( + group.add_argument( + '--flaky-steps', + help=('A JSON file containing steps that are flaky ' + 'and will have its exit code ignored.')) + group.add_argument( '--no-timeout', action='store_true', help=('Do not impose a timeout. Each perf step is responsible for ' 'implementing the timeout logic.')) - option_parser.add_option( + group.add_argument( '-f', '--test-filter', help=('Test filter (will match against the names listed in --steps).')) - option_parser.add_option( - '--dry-run', - action='store_true', + group.add_argument( + '--dry-run', action='store_true', help='Just print the steps without executing.') - AddCommonOptions(option_parser) - AddDeviceOptions(option_parser) + group.add_argument('single_step_command', nargs='*', action=SingleStepAction, + help='If --single-step is specified, the command to run.') + AddCommonOptions(parser) + AddDeviceOptions(parser) -def ProcessPerfTestOptions(options, args, error_func): +def ProcessPerfTestOptions(args): """Processes all perf test options. Args: - options: optparse.Options object. - error_func: Function to call with the error message in case of an error. + args: argparse.Namespace object. Returns: A PerfOptions named tuple which contains all options relevant to perf tests. """ - # Only one of steps, print_step or single_step must be provided. - count = len(filter(None, - [options.steps, options.print_step, options.single_step])) - if count != 1: - error_func('Please specify one of: --steps, --print-step, --single-step.') - single_step = None - if options.single_step: - single_step = ' '.join(args[2:]) + # TODO(jbudorick): Move single_step handling down into the perf tests. + if args.single_step: + args.single_step = ' '.join(args.single_step_command) + # TODO(jbudorick): Get rid of PerfOptions. return perf_test_options.PerfOptions( - options.steps, options.flaky_steps, options.output_json_list, - options.print_step, options.no_timeout, options.test_filter, - options.dry_run, single_step, options.collect_chartjson_data, - options.output_chartjson_data) + args.steps, args.flaky_steps, args.output_json_list, + args.print_step, args.no_timeout, args.test_filter, + args.dry_run, args.single_step, args.collect_chartjson_data, + args.output_chartjson_data) -def AddPythonTestOptions(option_parser): - option_parser.add_option('-s', '--suite', dest='suite_name', - help=('Name of the test suite to run' - '(use -s help to list them).')) - AddCommonOptions(option_parser) +def AddPythonTestOptions(parser): + group = parser.add_argument_group('Python Test Options') + group.add_argument( + '-s', '--suite', dest='suite_name', metavar='SUITE_NAME', + choices=constants.PYTHON_UNIT_TEST_SUITES.keys(), + help='Name of the test suite to run.') + AddCommonOptions(parser) -def ProcessPythonTestOptions(options, error_func): - if options.suite_name not in constants.PYTHON_UNIT_TEST_SUITES: - available = ('Available test suites: [%s]' % - ', '.join(constants.PYTHON_UNIT_TEST_SUITES.iterkeys())) - if options.suite_name == 'help': - print available - else: - error_func('"%s" is not a valid suite. %s' % - (options.suite_name, available)) - - -def _RunGTests(options, devices): +def _RunGTests(args, devices): """Subcommand of RunTestsCommands which runs gtests.""" - ProcessGTestOptions(options) - exit_code = 0 - for suite_name in options.suite_name: - # TODO(gkanwar): Move this into ProcessGTestOptions once we require -s for - # the gtest command. + for suite_name in args.suite_name: + # TODO(jbudorick): Either deprecate multi-suite or move its handling down + # into the gtest code. gtest_options = gtest_test_options.GTestOptions( - options.tool, - options.cleanup_test_files, - options.test_filter, - options.run_disabled, - options.test_arguments, - options.timeout, - options.isolate_file_path, + args.tool, + args.cleanup_test_files, + args.test_filter, + args.run_disabled, + args.test_arguments, + args.timeout, + args.isolate_file_path, suite_name) runner_factory, tests = gtest_setup.Setup(gtest_options, devices) results, test_exit_code = test_dispatcher.RunTests( tests, runner_factory, devices, shard=True, test_timeout=None, - num_retries=options.num_retries) + num_retries=args.num_retries) if test_exit_code and exit_code != constants.ERROR_EXIT_CODE: exit_code = test_exit_code @@ -645,7 +569,10 @@ results=results, test_type='Unit test', test_package=suite_name, - flakiness_server=options.flakiness_dashboard_server) + flakiness_server=args.flakiness_dashboard_server) + + if args.json_results_file: + json_results.GenerateJsonResultsFile(results, args.json_results_file) if os.path.isdir(constants.ISOLATE_DEPS_DIR): shutil.rmtree(constants.ISOLATE_DEPS_DIR) @@ -653,52 +580,57 @@ return exit_code -def _RunLinkerTests(options, devices): +def _RunLinkerTests(args, devices): """Subcommand of RunTestsCommands which runs linker tests.""" - runner_factory, tests = linker_setup.Setup(options, devices) + runner_factory, tests = linker_setup.Setup(args, devices) results, exit_code = test_dispatcher.RunTests( tests, runner_factory, devices, shard=True, test_timeout=60, - num_retries=options.num_retries) + num_retries=args.num_retries) report_results.LogFull( results=results, test_type='Linker test', test_package='ChromiumLinkerTest') + if args.json_results_file: + json_results.GenerateJsonResultsFile(results, args.json_results_file) + return exit_code -def _RunInstrumentationTests(options, error_func, devices): +def _RunInstrumentationTests(args, devices): """Subcommand of RunTestsCommands which runs instrumentation tests.""" - instrumentation_options = ProcessInstrumentationOptions(options, error_func) + logging.info('_RunInstrumentationTests(%s, %s)' % (str(args), str(devices))) - if len(devices) > 1 and options.wait_for_debugger: + instrumentation_options = ProcessInstrumentationOptions(args) + + if len(devices) > 1 and args.wait_for_debugger: logging.warning('Debugger can not be sharded, using first available device') devices = devices[:1] results = base_test_result.TestRunResults() exit_code = 0 - if options.run_java_tests: + if args.run_java_tests: runner_factory, tests = instrumentation_setup.Setup( instrumentation_options, devices) test_results, exit_code = test_dispatcher.RunTests( tests, runner_factory, devices, shard=True, test_timeout=None, - num_retries=options.num_retries) + num_retries=args.num_retries) results.AddTestRunResults(test_results) - if options.run_python_tests: + if args.run_python_tests: runner_factory, tests = host_driven_setup.InstrumentationSetup( - options.host_driven_root, options.official_build, + args.host_driven_root, args.official_build, instrumentation_options) if tests: test_results, test_exit_code = test_dispatcher.RunTests( tests, runner_factory, devices, shard=True, test_timeout=None, - num_retries=options.num_retries) + num_retries=args.num_retries) results.AddTestRunResults(test_results) @@ -706,70 +638,77 @@ if test_exit_code and exit_code != constants.ERROR_EXIT_CODE: exit_code = test_exit_code - if options.device_flags: - options.device_flags = os.path.join(constants.DIR_SOURCE_ROOT, - options.device_flags) + if args.device_flags: + args.device_flags = os.path.join(constants.DIR_SOURCE_ROOT, + args.device_flags) report_results.LogFull( results=results, test_type='Instrumentation', - test_package=os.path.basename(options.test_apk), - annotation=options.annotations, - flakiness_server=options.flakiness_dashboard_server) + test_package=os.path.basename(args.test_apk), + annotation=args.annotations, + flakiness_server=args.flakiness_dashboard_server) + + if args.json_results_file: + json_results.GenerateJsonResultsFile(results, args.json_results_file) return exit_code -def _RunUIAutomatorTests(options, error_func, devices): +def _RunUIAutomatorTests(args, devices): """Subcommand of RunTestsCommands which runs uiautomator tests.""" - uiautomator_options = ProcessUIAutomatorOptions(options, error_func) + uiautomator_options = ProcessUIAutomatorOptions(args) runner_factory, tests = uiautomator_setup.Setup(uiautomator_options) results, exit_code = test_dispatcher.RunTests( tests, runner_factory, devices, shard=True, test_timeout=None, - num_retries=options.num_retries) + num_retries=args.num_retries) report_results.LogFull( results=results, test_type='UIAutomator', - test_package=os.path.basename(options.test_jar), - annotation=options.annotations, - flakiness_server=options.flakiness_dashboard_server) + test_package=os.path.basename(args.test_jar), + annotation=args.annotations, + flakiness_server=args.flakiness_dashboard_server) + + if args.json_results_file: + json_results.GenerateJsonResultsFile(results, args.json_results_file) return exit_code -def _RunJUnitTests(options, error_func): +def _RunJUnitTests(args): """Subcommand of RunTestsCommand which runs junit tests.""" - junit_options = ProcessJUnitTestOptions(options, error_func) - runner_factory, tests = junit_setup.Setup(junit_options) + runner_factory, tests = junit_setup.Setup(args) _, exit_code = junit_dispatcher.RunTests(tests, runner_factory) - return exit_code -def _RunMonkeyTests(options, error_func, devices): +def _RunMonkeyTests(args, devices): """Subcommand of RunTestsCommands which runs monkey tests.""" - monkey_options = ProcessMonkeyTestOptions(options, error_func) + monkey_options = ProcessMonkeyTestOptions(args) runner_factory, tests = monkey_setup.Setup(monkey_options) results, exit_code = test_dispatcher.RunTests( tests, runner_factory, devices, shard=False, test_timeout=None, - num_retries=options.num_retries) + num_retries=args.num_retries) report_results.LogFull( results=results, test_type='Monkey', test_package='Monkey') + if args.json_results_file: + json_results.GenerateJsonResultsFile(results, args.json_results_file) + return exit_code -def _RunPerfTests(options, args, error_func): +def _RunPerfTests(args): """Subcommand of RunTestsCommands which runs perf tests.""" - perf_options = ProcessPerfTestOptions(options, args, error_func) + perf_options = ProcessPerfTestOptions(args) # Just save a simple json with a list of test names. if perf_options.output_json_list: @@ -792,13 +731,16 @@ # which increases throughput but have no affinity. results, _ = test_dispatcher.RunTests( tests, runner_factory, devices, shard=False, test_timeout=None, - num_retries=options.num_retries) + num_retries=args.num_retries) report_results.LogFull( results=results, test_type='Perf', test_package='Perf') + if args.json_results_file: + json_results.GenerateJsonResultsFile(results, args.json_results_file) + if perf_options.single_step: return perf_test_runner.PrintTestOutput('single_step') @@ -809,11 +751,9 @@ return 0 -def _RunPythonTests(options, error_func): +def _RunPythonTests(args): """Subcommand of RunTestsCommand which runs python unit tests.""" - ProcessPythonTestOptions(options, error_func) - - suite_vars = constants.PYTHON_UNIT_TEST_SUITES[options.suite_name] + suite_vars = constants.PYTHON_UNIT_TEST_SUITES[args.suite_name] suite_path = suite_vars['path'] suite_test_modules = suite_vars['test_modules'] @@ -822,7 +762,7 @@ suite = unittest.TestSuite() suite.addTests(unittest.defaultTestLoader.loadTestsFromName(m) for m in suite_test_modules) - runner = unittest.TextTestRunner(verbosity=1+options.verbose_count) + runner = unittest.TextTestRunner(verbosity=1+args.verbose_count) return 0 if runner.run(suite).wasSuccessful() else 1 finally: sys.path = sys.path[1:] @@ -851,15 +791,12 @@ return sorted(attached_devices) -def RunTestsCommand(command, options, args, option_parser): +def RunTestsCommand(args, parser): """Checks test type and dispatches to the appropriate function. Args: - command: String indicating the command that was received to trigger - this function. - options: optparse options dictionary. - args: List of extra args from optparse. - option_parser: optparse.OptionParser object. + args: argparse.Namespace object. + parser: argparse.ArgumentParser object. Returns: Integer indicated exit code. @@ -868,47 +805,38 @@ Exception: Unknown command name passed in, or an exception from an individual test runner. """ + command = args.command - # Check for extra arguments - if len(args) > 2 and command != 'perf': - option_parser.error('Unrecognized arguments: %s' % (' '.join(args[2:]))) - return constants.ERROR_EXIT_CODE - if command == 'perf': - if ((options.single_step and len(args) <= 2) or - (not options.single_step and len(args) > 2)): - option_parser.error('Unrecognized arguments: %s' % (' '.join(args))) - return constants.ERROR_EXIT_CODE + ProcessCommonOptions(args) - ProcessCommonOptions(options, option_parser.error) - - if options.enable_platform_mode: - return RunTestsInPlatformMode(command, options, option_parser) + if args.enable_platform_mode: + return RunTestsInPlatformMode(args, parser.error) if command in constants.LOCAL_MACHINE_TESTS: devices = [] else: - devices = _GetAttachedDevices(options.test_device) + devices = _GetAttachedDevices(args.test_device) forwarder.Forwarder.RemoveHostLog() if not ports.ResetTestServerPortAllocation(): raise Exception('Failed to reset test server port.') if command == 'gtest': - return _RunGTests(options, devices) + return _RunGTests(args, devices) elif command == 'linker': - return _RunLinkerTests(options, devices) + return _RunLinkerTests(args, devices) elif command == 'instrumentation': - return _RunInstrumentationTests(options, option_parser.error, devices) + return _RunInstrumentationTests(args, devices) elif command == 'uiautomator': - return _RunUIAutomatorTests(options, option_parser.error, devices) + return _RunUIAutomatorTests(args, devices) elif command == 'junit': - return _RunJUnitTests(options, option_parser.error) + return _RunJUnitTests(args) elif command == 'monkey': - return _RunMonkeyTests(options, option_parser.error, devices) + return _RunMonkeyTests(args, devices) elif command == 'perf': - return _RunPerfTests(options, args, option_parser.error) + return _RunPerfTests(args) elif command == 'python': - return _RunPythonTests(options, option_parser.error) + return _RunPythonTests(args) else: raise Exception('Unknown test type.') @@ -919,93 +847,60 @@ ] -def RunTestsInPlatformMode(command, options, option_parser): +def RunTestsInPlatformMode(args, parser): - if command not in _SUPPORTED_IN_PLATFORM_MODE: - option_parser.error('%s is not yet supported in platform mode' % command) + if args.command not in _SUPPORTED_IN_PLATFORM_MODE: + parser.error('%s is not yet supported in platform mode' % args.command) - with environment_factory.CreateEnvironment( - command, options, option_parser.error) as env: - with test_instance_factory.CreateTestInstance( - command, options, option_parser.error) as test: + with environment_factory.CreateEnvironment(args, parser.error) as env: + with test_instance_factory.CreateTestInstance(args, parser.error) as test: with test_run_factory.CreateTestRun( - options, env, test, option_parser.error) as test_run: + args, env, test, parser.error) as test_run: results = test_run.RunTests() report_results.LogFull( results=results, test_type=test.TestType(), test_package=test_run.TestPackage(), - annotation=options.annotations, - flakiness_server=options.flakiness_dashboard_server) + annotation=args.annotations, + flakiness_server=args.flakiness_dashboard_server) + + if args.json_results_file: + json_results.GenerateJsonResultsFile( + results, args.json_results_file) return results -def HelpCommand(command, _options, args, option_parser): - """Display help for a certain command, or overall help. - - Args: - command: String indicating the command that was received to trigger - this function. - options: optparse options dictionary. unused. - args: List of extra args from optparse. - option_parser: optparse.OptionParser object. - - Returns: - Integer indicated exit code. - """ - # If we don't have any args, display overall help - if len(args) < 3: - option_parser.print_help() - return 0 - # If we have too many args, print an error - if len(args) > 3: - option_parser.error('Unrecognized arguments: %s' % (' '.join(args[3:]))) - return constants.ERROR_EXIT_CODE - - command = args[2] - - if command not in VALID_COMMANDS: - option_parser.error('Unrecognized command.') - - # Treat the help command as a special case. We don't care about showing a - # specific help page for itself. - if command == 'help': - option_parser.print_help() - return 0 - - VALID_COMMANDS[command].add_options_func(option_parser) - option_parser.usage = '%prog ' + command + ' [options]' - option_parser.commands_dict = {} - option_parser.print_help() - - return 0 - - -# Define a named tuple for the values in the VALID_COMMANDS dictionary so the -# syntax is a bit prettier. The tuple is two functions: (add options, run -# command). -CommandFunctionTuple = collections.namedtuple( - 'CommandFunctionTuple', ['add_options_func', 'run_command_func']) +CommandConfigTuple = collections.namedtuple( + 'CommandConfigTuple', + ['add_options_func', 'help_txt']) VALID_COMMANDS = { - 'gtest': CommandFunctionTuple(AddGTestOptions, RunTestsCommand), - 'instrumentation': CommandFunctionTuple( - AddInstrumentationTestOptions, RunTestsCommand), - 'uiautomator': CommandFunctionTuple( - AddUIAutomatorTestOptions, RunTestsCommand), - 'junit': CommandFunctionTuple( - AddJUnitTestOptions, RunTestsCommand), - 'monkey': CommandFunctionTuple( - AddMonkeyTestOptions, RunTestsCommand), - 'perf': CommandFunctionTuple( - AddPerfTestOptions, RunTestsCommand), - 'python': CommandFunctionTuple( - AddPythonTestOptions, RunTestsCommand), - 'linker': CommandFunctionTuple( - AddLinkerTestOptions, RunTestsCommand), - 'help': CommandFunctionTuple(lambda option_parser: None, HelpCommand) - } + 'gtest': CommandConfigTuple( + AddGTestOptions, + 'googletest-based C++ tests'), + 'instrumentation': CommandConfigTuple( + AddInstrumentationTestOptions, + 'InstrumentationTestCase-based Java tests'), + 'uiautomator': CommandConfigTuple( + AddUIAutomatorTestOptions, + "Tests that run via Android's uiautomator command"), + 'junit': CommandConfigTuple( + AddJUnitTestOptions, + 'JUnit4-based Java tests'), + 'monkey': CommandConfigTuple( + AddMonkeyTestOptions, + "Tests based on Android's monkey"), + 'perf': CommandConfigTuple( + AddPerfTestOptions, + 'Performance tests'), + 'python': CommandConfigTuple( + AddPythonTestOptions, + 'Python tests based on unittest.TestCase'), + 'linker': CommandConfigTuple( + AddLinkerTestOptions, + 'Linker tests'), +} def DumpThreadStacks(_signal, _frame): @@ -1015,9 +910,21 @@ def main(): signal.signal(signal.SIGUSR1, DumpThreadStacks) - option_parser = command_option_parser.CommandOptionParser( - commands_dict=VALID_COMMANDS) - return command_option_parser.ParseAndExecute(option_parser) + + parser = argparse.ArgumentParser() + command_parsers = parser.add_subparsers(title='test types', + dest='command') + + for test_type, config in sorted(VALID_COMMANDS.iteritems(), + key=lambda x: x[0]): + subparser = command_parsers.add_parser( + test_type, usage='%(prog)s [options]', help=config.help_txt) + config.add_options_func(subparser) + + args = parser.parse_args() + RunTestsCommand(args, parser) + + return 0 if __name__ == '__main__':
diff --git a/build/common.gypi b/build/common.gypi index 5c15346..22385a2b 100644 --- a/build/common.gypi +++ b/build/common.gypi
@@ -592,8 +592,8 @@ 'wix_path%': '<(DEPTH)/third_party/wix', - # Managed users are enabled by default. - 'enable_managed_users%': 1, + # Supervised users are enabled by default. + 'enable_supervised_users%': 1, # Platform natively supports discardable memory. 'native_discardable_memory%': 0, @@ -801,7 +801,7 @@ 'notifications%': 0, 'remoting%': 0, 'safe_browsing%': 0, - 'enable_managed_users%': 0, + 'enable_supervised_users%': 0, 'enable_task_manager%': 0, 'use_system_libcxx%': 1, 'support_pre_M6_history_database%': 0, @@ -1189,7 +1189,7 @@ 'google_api_key%': '<(google_api_key)', 'google_default_client_id%': '<(google_default_client_id)', 'google_default_client_secret%': '<(google_default_client_secret)', - 'enable_managed_users%': '<(enable_managed_users)', + 'enable_supervised_users%': '<(enable_supervised_users)', 'native_discardable_memory%': '<(native_discardable_memory)', 'native_memory_pressure_signals%': '<(native_memory_pressure_signals)', 'spdy_proxy_auth_property%': '<(spdy_proxy_auth_property)', @@ -1777,7 +1777,7 @@ 'use_openssl_certs%': 1, 'proprietary_codecs%': '<(proprietary_codecs)', - 'safe_browsing%': 1, + 'safe_browsing%': 2, 'enable_web_speech%': 0, 'java_bridge%': 1, 'build_ffmpegsumo%': 0, @@ -2239,7 +2239,7 @@ # Iterator debugging is slow. 'win_debug_disable_iterator_debugging': '1', # Try to disable optimizations that mess up stacks in a release build. - # DrM-i#1054 (http://code.google.com/p/drmemory/issues/detail?id=1054) + # DrM-i#1054 (https://github.com/DynamoRIO/drmemory/issues/1054) # /O2 and /Ob0 (disable inline) cannot be used together because of a # compiler bug, so we use /Ob1 instead. 'win_release_InlineFunctionExpansion': '1', @@ -2948,8 +2948,8 @@ ['use_icu_alternatives_on_android==1', { 'defines': ['USE_ICU_ALTERNATIVES_ON_ANDROID=1'], }], - ['enable_managed_users==1', { - 'defines': ['ENABLE_MANAGED_USERS=1'], + ['enable_supervised_users==1', { + 'defines': ['ENABLE_SUPERVISED_USERS=1'], }], ['spdy_proxy_auth_property != ""', { 'defines': ['SPDY_PROXY_AUTH_PROPERTY="<(spdy_proxy_auth_property)"'],
diff --git a/build/compiled_action.gni b/build/compiled_action.gni index b750af0..e5059aa 100644 --- a/build/compiled_action.gni +++ b/build/compiled_action.gni
@@ -102,22 +102,23 @@ # If that's not the case, we'll need another argument to the script to # specify this, since we can't know what the output name is (it might be in # another file not processed yet). - host_executable = get_label_info(host_tool, "root_out_dir") + "/" + - get_label_info(host_tool, "name") + _host_executable_suffix + host_executable = + get_label_info(host_tool, "root_out_dir") + "/" + + get_label_info(host_tool, "name") + _host_executable_suffix # Add the executable itself as an input. inputs += [ host_executable ] - deps = [ host_tool ] + deps = [ + host_tool, + ] if (defined(invoker.deps)) { deps += invoker.deps } # The script takes as arguments the binary to run, and then the arguments # to pass it. - args = [ - rebase_path(host_executable, root_build_dir) - ] + invoker.args + args = [ rebase_path(host_executable, root_build_dir) ] + invoker.args } } @@ -151,21 +152,22 @@ # If that's not the case, we'll need another argument to the script to # specify this, since we can't know what the output name is (it might be in # another file not processed yet). - host_executable = get_label_info(host_tool, "root_out_dir") + "/" + - get_label_info(host_tool, "name") + _host_executable_suffix + host_executable = + get_label_info(host_tool, "root_out_dir") + "/" + + get_label_info(host_tool, "name") + _host_executable_suffix # Add the executable itself as an input. inputs += [ host_executable ] - deps = [ host_tool ] + deps = [ + host_tool, + ] if (defined(invoker.deps)) { deps += invoker.deps } # The script takes as arguments the binary to run, and then the arguments # to pass it. - args = [ - rebase_path(host_executable, root_build_dir) - ] + invoker.args + args = [ rebase_path(host_executable, root_build_dir) ] + invoker.args } }
diff --git a/build/config/BUILD.gn b/build/config/BUILD.gn index c51709c..bd803ef 100644 --- a/build/config/BUILD.gn +++ b/build/config/BUILD.gn
@@ -30,8 +30,8 @@ config("feature_flags") { # TODO(brettw) most of these need to be parameterized. defines = [ - "CHROMIUM_BUILD", - "V8_DEPRECATION_WARNINGS", # Don't use deprecated V8 APIs anywhere. + "CHROMIUM_BUILD", + "V8_DEPRECATION_WARNINGS", # Don't use deprecated V8 APIs anywhere. ] if (cld_version > 0) { @@ -171,8 +171,8 @@ if (enable_settings_app) { defines += [ "ENABLE_SETTINGS_APP=1" ] } - if (enable_managed_users) { - defines += [ "ENABLE_MANAGED_USERS=1" ] + if (enable_supervised_users) { + defines += [ "ENABLE_SUPERVISED_USERS=1" ] } if (enable_service_discovery) { defines += [ "ENABLE_SERVICE_DISCOVERY=1" ] @@ -204,6 +204,9 @@ if (proprietary_codecs) { defines += [ "USE_PROPRIETARY_CODECS" ] } + if (enable_hangout_services_extension) { + defines += [ "ENABLE_HANGOUT_SERVICES_EXTENSION=1" ] + } } # Debug/release ---------------------------------------------------------------- @@ -231,9 +234,7 @@ } config("release") { - defines = [ - "NDEBUG", - ] + defines = [ "NDEBUG" ] } # Default libraries ------------------------------------------------------------ @@ -268,6 +269,7 @@ "winmm.lib", "winspool.lib", "ws2_32.lib", + # Please don't add more stuff here. We should actually be making this # list smaller, since all common things should be covered. If you need # some extra libraries, please just add a libs = [ "foo.lib" ] to your @@ -284,7 +286,7 @@ # '<!(<(android_toolchain)/*-gcc -print-libgcc-file-name)', "c", "dl", - "m" + "m", ] } else if (is_mac) { libs = [ @@ -305,8 +307,6 @@ "UIKit.framework", ] } else if (is_linux) { - libs = [ - "dl", - ] + libs = [ "dl" ] } }
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn index 0d65c44..39372d8e 100644 --- a/build/config/BUILDCONFIG.gn +++ b/build/config/BUILDCONFIG.gn
@@ -27,12 +27,13 @@ # Component build. is_component_build = false + # Debug build. is_debug = true # Set to true when compiling with the Clang compiler. Typically this is used # to configure warnings. - is_clang = (os == "mac" || os == "ios" || os == "linux" || os == "chromeos") + is_clang = os == "mac" || os == "ios" || os == "linux" || os == "chromeos" # Selects the desired build flavor. Official builds get additional # processing to prepare for release. Normally you will want to develop and @@ -238,9 +239,7 @@ ] } if (!is_mac && !is_ios) { - sources_assignment_filter += [ - "*.mm", - ] + sources_assignment_filter += [ "*.mm" ] } if (!is_linux) { sources_assignment_filter += [ @@ -269,6 +268,7 @@ "*\bchromeos/*", ] } + # DO NOT ADD MORE PATTERNS TO THIS LIST, see set_sources_assignment_filter call # below. @@ -309,7 +309,6 @@ # duplication in each target below. _native_compiler_configs = [ "//build/config:feature_flags", - "//build/config/compiler:compiler", "//build/config/compiler:compiler_arm_fpu", "//build/config/compiler:chromium_code", @@ -335,13 +334,13 @@ } if (is_linux) { - _native_compiler_configs += [ "//build/config/linux:sdk", ] + _native_compiler_configs += [ "//build/config/linux:sdk" ] } else if (is_mac) { - _native_compiler_configs += [ "//build/config/mac:sdk", ] + _native_compiler_configs += [ "//build/config/mac:sdk" ] } else if (is_ios) { - _native_compiler_configs += [ "//build/config/ios:sdk", ] + _native_compiler_configs += [ "//build/config/ios:sdk" ] } else if (is_android) { - _native_compiler_configs += [ "//build/config/android:sdk", ] + _native_compiler_configs += [ "//build/config/android:sdk" ] } if (is_clang) { @@ -388,15 +387,16 @@ if (is_win) { if (is_debug) { _default_incremental_linking_config = - "//build/config/win:incremental_linking" + "//build/config/win:incremental_linking" } else { _default_incremental_linking_config = - "//build/config/win:no_incremental_linking" + "//build/config/win:no_incremental_linking" } _windows_linker_configs = [ _default_incremental_linking_config, "//build/config/win:sdk_link", "//build/config/win:common_linker_setup", + # Default to console-mode apps. Most of our targets are tests and such # that shouldn't use the windows subsystem. "//build/config/win:console", @@ -404,15 +404,15 @@ } # Executable defaults. -_executable_configs = _native_compiler_configs + [ - "//build/config:default_libs", -] +_executable_configs = + _native_compiler_configs + [ "//build/config:default_libs" ] if (is_win) { _executable_configs += _windows_linker_configs } else if (is_mac) { _executable_configs += [ "//build/config/mac:mac_dynamic_flags", - "//build/config/mac:mac_executable_flags" ] + "//build/config/mac:mac_executable_flags", + ] } else if (is_linux || is_android) { _executable_configs += [ "//build/config/gcc:executable_ldconfig" ] if (is_android) { @@ -429,9 +429,8 @@ } # Shared library defaults (also for components in component mode). -_shared_library_configs = _native_compiler_configs + [ - "//build/config:default_libs", -] +_shared_library_configs = + _native_compiler_configs + [ "//build/config:default_libs" ] if (is_win) { _shared_library_configs += _windows_linker_configs } else if (is_mac) { @@ -465,7 +464,6 @@ } } - # ============================================================================== # TOOLCHAIN SETUP # ============================================================================== @@ -536,38 +534,91 @@ # the original target may have override it for some assignments. set_sources_assignment_filter([]) - if (defined(invoker.all_dependent_configs)) { all_dependent_configs = invoker.all_dependent_configs } - if (defined(invoker.allow_circular_includes_from)) { allow_circular_includes_from = invoker.allow_circular_includes_from } - if (defined(invoker.cflags)) { cflags = invoker.cflags } - if (defined(invoker.cflags_c)) { cflags_c = invoker.cflags_c } - if (defined(invoker.cflags_cc)) { cflags_cc = invoker.cflags_cc } - if (defined(invoker.cflags_objc)) { cflags_objc = invoker.cflags_objc } - if (defined(invoker.cflags_objcc)) { cflags_objcc = invoker.cflags_objcc } - if (defined(invoker.check_includes)) { check_includes = invoker.check_includes } - if (defined(invoker.data)) { data = invoker.data } - if (defined(invoker.datadeps)) { datadeps = invoker.datadeps } - if (defined(invoker.defines)) { defines = invoker.defines } + if (defined(invoker.all_dependent_configs)) { + all_dependent_configs = invoker.all_dependent_configs + } + if (defined(invoker.allow_circular_includes_from)) { + allow_circular_includes_from = invoker.allow_circular_includes_from + } + if (defined(invoker.cflags)) { + cflags = invoker.cflags + } + if (defined(invoker.cflags_c)) { + cflags_c = invoker.cflags_c + } + if (defined(invoker.cflags_cc)) { + cflags_cc = invoker.cflags_cc + } + if (defined(invoker.cflags_objc)) { + cflags_objc = invoker.cflags_objc + } + if (defined(invoker.cflags_objcc)) { + cflags_objcc = invoker.cflags_objcc + } + if (defined(invoker.check_includes)) { + check_includes = invoker.check_includes + } + if (defined(invoker.data)) { + data = invoker.data + } + if (defined(invoker.datadeps)) { + datadeps = invoker.datadeps + } + if (defined(invoker.defines)) { + defines = invoker.defines + } + # All shared libraries must have the sanitizer deps to properly link in # asan mode (this target will be empty in other cases). if (defined(invoker.deps)) { deps = invoker.deps + [ "//build/config/sanitizers:deps" ] } else { - deps = [ "//build/config/sanitizers:deps" ] + deps = [ + "//build/config/sanitizers:deps", + ] } - if (defined(invoker.direct_dependent_configs)) { direct_dependent_configs = invoker.direct_dependent_configs } - if (defined(invoker.forward_dependent_configs_from)) { forward_dependent_configs_from = invoker.forward_dependent_configs_from } - if (defined(invoker.include_dirs)) { include_dirs = invoker.include_dirs } - if (defined(invoker.ldflags)) { ldflags = invoker.ldflags } - if (defined(invoker.lib_dirs)) { lib_dirs = invoker.lib_dirs } - if (defined(invoker.libs)) { libs = invoker.libs } - if (defined(invoker.output_extension)) { output_extension = invoker.output_extension } - if (defined(invoker.output_name)) { output_name = invoker.output_name } - if (defined(invoker.public)) { public = invoker.public } - if (defined(invoker.public_configs)) { public_configs = invoker.public_configs } - if (defined(invoker.public_deps)) { public_deps = invoker.public_deps } - if (defined(invoker.sources)) { sources = invoker.sources } - if (defined(invoker.testonly)) { testonly = invoker.testonly } - if (defined(invoker.visibility)) { visibility = invoker.visibility } + if (defined(invoker.direct_dependent_configs)) { + direct_dependent_configs = invoker.direct_dependent_configs + } + if (defined(invoker.forward_dependent_configs_from)) { + forward_dependent_configs_from = invoker.forward_dependent_configs_from + } + if (defined(invoker.include_dirs)) { + include_dirs = invoker.include_dirs + } + if (defined(invoker.ldflags)) { + ldflags = invoker.ldflags + } + if (defined(invoker.lib_dirs)) { + lib_dirs = invoker.lib_dirs + } + if (defined(invoker.libs)) { + libs = invoker.libs + } + if (defined(invoker.output_extension)) { + output_extension = invoker.output_extension + } + if (defined(invoker.output_name)) { + output_name = invoker.output_name + } + if (defined(invoker.public)) { + public = invoker.public + } + if (defined(invoker.public_configs)) { + public_configs = invoker.public_configs + } + if (defined(invoker.public_deps)) { + public_deps = invoker.public_deps + } + if (defined(invoker.sources)) { + sources = invoker.sources + } + if (defined(invoker.testonly)) { + testonly = invoker.testonly + } + if (defined(invoker.visibility)) { + visibility = invoker.visibility + } } } else { source_set(target_name) { @@ -578,32 +629,84 @@ # See above call. set_sources_assignment_filter([]) - if (defined(invoker.all_dependent_configs)) { all_dependent_configs = invoker.all_dependent_configs } - if (defined(invoker.allow_circular_includes_from)) { allow_circular_includes_from = invoker.allow_circular_includes_from } - if (defined(invoker.cflags)) { cflags = invoker.cflags } - if (defined(invoker.cflags_c)) { cflags_c = invoker.cflags_c } - if (defined(invoker.cflags_cc)) { cflags_cc = invoker.cflags_cc } - if (defined(invoker.cflags_objc)) { cflags_objc = invoker.cflags_objc } - if (defined(invoker.cflags_objcc)) { cflags_objcc = invoker.cflags_objcc } - if (defined(invoker.check_includes)) { check_includes = invoker.check_includes } - if (defined(invoker.data)) { data = invoker.data } - if (defined(invoker.datadeps)) { datadeps = invoker.datadeps } - if (defined(invoker.defines)) { defines = invoker.defines } - if (defined(invoker.deps)) { deps = invoker.deps } - if (defined(invoker.direct_dependent_configs)) { direct_dependent_configs = invoker.direct_dependent_configs } - if (defined(invoker.forward_dependent_configs_from)) { forward_dependent_configs_from = invoker.forward_dependent_configs_from } - if (defined(invoker.include_dirs)) { include_dirs = invoker.include_dirs } - if (defined(invoker.ldflags)) { ldflags = invoker.ldflags } - if (defined(invoker.lib_dirs)) { lib_dirs = invoker.lib_dirs } - if (defined(invoker.libs)) { libs = invoker.libs } - if (defined(invoker.output_extension)) { output_extension = invoker.output_extension } - if (defined(invoker.output_name)) { output_name = invoker.output_name } - if (defined(invoker.public)) { public = invoker.public } - if (defined(invoker.public_configs)) { public_configs = invoker.public_configs } - if (defined(invoker.public_deps)) { public_deps = invoker.public_deps } - if (defined(invoker.sources)) { sources = invoker.sources } - if (defined(invoker.testonly)) { testonly = invoker.testonly } - if (defined(invoker.visibility)) { visibility = invoker.visibility } + if (defined(invoker.all_dependent_configs)) { + all_dependent_configs = invoker.all_dependent_configs + } + if (defined(invoker.allow_circular_includes_from)) { + allow_circular_includes_from = invoker.allow_circular_includes_from + } + if (defined(invoker.cflags)) { + cflags = invoker.cflags + } + if (defined(invoker.cflags_c)) { + cflags_c = invoker.cflags_c + } + if (defined(invoker.cflags_cc)) { + cflags_cc = invoker.cflags_cc + } + if (defined(invoker.cflags_objc)) { + cflags_objc = invoker.cflags_objc + } + if (defined(invoker.cflags_objcc)) { + cflags_objcc = invoker.cflags_objcc + } + if (defined(invoker.check_includes)) { + check_includes = invoker.check_includes + } + if (defined(invoker.data)) { + data = invoker.data + } + if (defined(invoker.datadeps)) { + datadeps = invoker.datadeps + } + if (defined(invoker.defines)) { + defines = invoker.defines + } + if (defined(invoker.deps)) { + deps = invoker.deps + } + if (defined(invoker.direct_dependent_configs)) { + direct_dependent_configs = invoker.direct_dependent_configs + } + if (defined(invoker.forward_dependent_configs_from)) { + forward_dependent_configs_from = invoker.forward_dependent_configs_from + } + if (defined(invoker.include_dirs)) { + include_dirs = invoker.include_dirs + } + if (defined(invoker.ldflags)) { + ldflags = invoker.ldflags + } + if (defined(invoker.lib_dirs)) { + lib_dirs = invoker.lib_dirs + } + if (defined(invoker.libs)) { + libs = invoker.libs + } + if (defined(invoker.output_extension)) { + output_extension = invoker.output_extension + } + if (defined(invoker.output_name)) { + output_name = invoker.output_name + } + if (defined(invoker.public)) { + public = invoker.public + } + if (defined(invoker.public_configs)) { + public_configs = invoker.public_configs + } + if (defined(invoker.public_deps)) { + public_deps = invoker.public_deps + } + if (defined(invoker.sources)) { + sources = invoker.sources + } + if (defined(invoker.testonly)) { + testonly = invoker.testonly + } + if (defined(invoker.visibility)) { + visibility = invoker.visibility + } } } } @@ -628,31 +731,81 @@ testonly = true - if (defined(invoker.all_dependent_configs)) { all_dependent_configs = invoker.all_dependent_configs } - if (defined(invoker.allow_circular_includes_from)) { allow_circular_includes_from = invoker.allow_circular_includes_from } - if (defined(invoker.cflags)) { cflags = invoker.cflags } - if (defined(invoker.cflags_c)) { cflags_c = invoker.cflags_c } - if (defined(invoker.cflags_cc)) { cflags_cc = invoker.cflags_cc } - if (defined(invoker.cflags_objc)) { cflags_objc = invoker.cflags_objc } - if (defined(invoker.cflags_objcc)) { cflags_objcc = invoker.cflags_objcc } - if (defined(invoker.check_includes)) { check_includes = invoker.check_includes } - if (defined(invoker.data)) { data = invoker.data } - if (defined(invoker.datadeps)) { datadeps = invoker.datadeps } - if (defined(invoker.defines)) { defines = invoker.defines } - if (defined(invoker.deps)) { deps = invoker.deps } - if (defined(invoker.direct_dependent_configs)) { direct_dependent_configs = invoker.direct_dependent_configs } - if (defined(invoker.forward_dependent_configs_from)) { forward_dependent_configs_from = invoker.forward_dependent_configs_from } - if (defined(invoker.include_dirs)) { include_dirs = invoker.include_dirs } - if (defined(invoker.ldflags)) { ldflags = invoker.ldflags } - if (defined(invoker.lib_dirs)) { lib_dirs = invoker.lib_dirs } - if (defined(invoker.libs)) { libs = invoker.libs } - if (defined(invoker.output_extension)) { output_extension = invoker.output_extension } - if (defined(invoker.output_name)) { output_name = invoker.output_name } - if (defined(invoker.public)) { public = invoker.public } - if (defined(invoker.public_configs)) { public_configs = invoker.public_configs } - if (defined(invoker.public_deps)) { public_deps = invoker.public_deps } - if (defined(invoker.sources)) { sources = invoker.sources } - if (defined(invoker.visibility)) { visibility = invoker.visibility } + if (defined(invoker.all_dependent_configs)) { + all_dependent_configs = invoker.all_dependent_configs + } + if (defined(invoker.allow_circular_includes_from)) { + allow_circular_includes_from = invoker.allow_circular_includes_from + } + if (defined(invoker.cflags)) { + cflags = invoker.cflags + } + if (defined(invoker.cflags_c)) { + cflags_c = invoker.cflags_c + } + if (defined(invoker.cflags_cc)) { + cflags_cc = invoker.cflags_cc + } + if (defined(invoker.cflags_objc)) { + cflags_objc = invoker.cflags_objc + } + if (defined(invoker.cflags_objcc)) { + cflags_objcc = invoker.cflags_objcc + } + if (defined(invoker.check_includes)) { + check_includes = invoker.check_includes + } + if (defined(invoker.data)) { + data = invoker.data + } + if (defined(invoker.datadeps)) { + datadeps = invoker.datadeps + } + if (defined(invoker.defines)) { + defines = invoker.defines + } + if (defined(invoker.deps)) { + deps = invoker.deps + } + if (defined(invoker.direct_dependent_configs)) { + direct_dependent_configs = invoker.direct_dependent_configs + } + if (defined(invoker.forward_dependent_configs_from)) { + forward_dependent_configs_from = invoker.forward_dependent_configs_from + } + if (defined(invoker.include_dirs)) { + include_dirs = invoker.include_dirs + } + if (defined(invoker.ldflags)) { + ldflags = invoker.ldflags + } + if (defined(invoker.lib_dirs)) { + lib_dirs = invoker.lib_dirs + } + if (defined(invoker.libs)) { + libs = invoker.libs + } + if (defined(invoker.output_extension)) { + output_extension = invoker.output_extension + } + if (defined(invoker.output_name)) { + output_name = invoker.output_name + } + if (defined(invoker.public)) { + public = invoker.public + } + if (defined(invoker.public_configs)) { + public_configs = invoker.public_configs + } + if (defined(invoker.public_deps)) { + public_deps = invoker.public_deps + } + if (defined(invoker.sources)) { + sources = invoker.sources + } + if (defined(invoker.visibility)) { + visibility = invoker.visibility + } } } else { executable(target_name) { @@ -665,37 +818,88 @@ testonly = true - if (defined(invoker.all_dependent_configs)) { all_dependent_configs = invoker.all_dependent_configs } - if (defined(invoker.allow_circular_includes_from)) { allow_circular_includes_from = invoker.allow_circular_includes_from } - if (defined(invoker.cflags)) { cflags = invoker.cflags } - if (defined(invoker.cflags_c)) { cflags_c = invoker.cflags_c } - if (defined(invoker.cflags_cc)) { cflags_cc = invoker.cflags_cc } - if (defined(invoker.cflags_objc)) { cflags_objc = invoker.cflags_objc } - if (defined(invoker.cflags_objcc)) { cflags_objcc = invoker.cflags_objcc } - if (defined(invoker.check_includes)) { check_includes = invoker.check_includes } - if (defined(invoker.data)) { data = invoker.data } - if (defined(invoker.datadeps)) { datadeps = invoker.datadeps } - if (defined(invoker.defines)) { defines = invoker.defines } + if (defined(invoker.all_dependent_configs)) { + all_dependent_configs = invoker.all_dependent_configs + } + if (defined(invoker.allow_circular_includes_from)) { + allow_circular_includes_from = invoker.allow_circular_includes_from + } + if (defined(invoker.cflags)) { + cflags = invoker.cflags + } + if (defined(invoker.cflags_c)) { + cflags_c = invoker.cflags_c + } + if (defined(invoker.cflags_cc)) { + cflags_cc = invoker.cflags_cc + } + if (defined(invoker.cflags_objc)) { + cflags_objc = invoker.cflags_objc + } + if (defined(invoker.cflags_objcc)) { + cflags_objcc = invoker.cflags_objcc + } + if (defined(invoker.check_includes)) { + check_includes = invoker.check_includes + } + if (defined(invoker.data)) { + data = invoker.data + } + if (defined(invoker.datadeps)) { + datadeps = invoker.datadeps + } + if (defined(invoker.defines)) { + defines = invoker.defines + } + # All shared libraries must have the sanitizer deps to properly link in # asan mode (this target will be empty in other cases). if (defined(invoker.deps)) { deps = invoker.deps + [ "//build/config/sanitizers:deps" ] } else { - deps = [ "//build/config/sanitizers:deps" ] + deps = [ + "//build/config/sanitizers:deps", + ] } - if (defined(invoker.direct_dependent_configs)) { direct_dependent_configs = invoker.direct_dependent_configs } - if (defined(invoker.forward_dependent_configs_from)) { forward_dependent_configs_from = invoker.forward_dependent_configs_from } - if (defined(invoker.include_dirs)) { include_dirs = invoker.include_dirs } - if (defined(invoker.ldflags)) { ldflags = invoker.ldflags } - if (defined(invoker.lib_dirs)) { lib_dirs = invoker.lib_dirs } - if (defined(invoker.libs)) { libs = invoker.libs } - if (defined(invoker.output_extension)) { output_extension = invoker.output_extension } - if (defined(invoker.output_name)) { output_name = invoker.output_name } - if (defined(invoker.public)) { public = invoker.public } - if (defined(invoker.public_configs)) { public_configs = invoker.public_configs } - if (defined(invoker.public_deps)) { public_deps = invoker.public_deps } - if (defined(invoker.sources)) { sources = invoker.sources } - if (defined(invoker.visibility)) { visibility = invoker.visibility } + if (defined(invoker.direct_dependent_configs)) { + direct_dependent_configs = invoker.direct_dependent_configs + } + if (defined(invoker.forward_dependent_configs_from)) { + forward_dependent_configs_from = invoker.forward_dependent_configs_from + } + if (defined(invoker.include_dirs)) { + include_dirs = invoker.include_dirs + } + if (defined(invoker.ldflags)) { + ldflags = invoker.ldflags + } + if (defined(invoker.lib_dirs)) { + lib_dirs = invoker.lib_dirs + } + if (defined(invoker.libs)) { + libs = invoker.libs + } + if (defined(invoker.output_extension)) { + output_extension = invoker.output_extension + } + if (defined(invoker.output_name)) { + output_name = invoker.output_name + } + if (defined(invoker.public)) { + public = invoker.public + } + if (defined(invoker.public_configs)) { + public_configs = invoker.public_configs + } + if (defined(invoker.public_deps)) { + public_deps = invoker.public_deps + } + if (defined(invoker.sources)) { + sources = invoker.sources + } + if (defined(invoker.visibility)) { + visibility = invoker.visibility + } } } }
diff --git a/build/config/allocator.gni b/build/config/allocator.gni index 2d2fed1..9fcfe49 100644 --- a/build/config/allocator.gni +++ b/build/config/allocator.gni
@@ -1,7 +1,7 @@ # Copyright 2014 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. - + # TODO(GYP): Make tcmalloc work on win. if (is_android || cpu_arch == "mipsel" || is_mac || is_asan || is_win) { _default_allocator = "none"
diff --git a/build/config/android/BUILD.gn b/build/config/android/BUILD.gn index 2528c18..0cc38b7e 100644 --- a/build/config/android/BUILD.gn +++ b/build/config/android/BUILD.gn
@@ -13,9 +13,11 @@ # Need to get some linker flags out of the sysroot. sysroot_ld_path = rebase_path("//build/config/linux/sysroot_ld_path.py") ldflags += [ exec_script(sysroot_ld_path, - [ rebase_path("//build/linux/sysroot_ld_path.sh"), sysroot ], - "value") - ] + [ + rebase_path("//build/linux/sysroot_ld_path.sh"), + sysroot, + ], + "value") ] } }
diff --git a/build/config/android/config.gni b/build/config/android/config.gni index ce9a175..99abf95 100644 --- a/build/config/android/config.gni +++ b/build/config/android/config.gni
@@ -5,9 +5,10 @@ # This file contains common system config stuff for the Android build. if (is_android) { - has_chrome_android_internal = exec_script("//build/dir_exists.py", - [ rebase_path("//clank", root_build_dir) ], - "string") == "True" + has_chrome_android_internal = + exec_script("//build/dir_exists.py", + [ rebase_path("//clank", root_build_dir) ], + "string") == "True" if (has_chrome_android_internal) { import("//clank/config.gni") @@ -27,7 +28,8 @@ # when this is unset, but builds using the normal chromium build system. is_android_webview_build = false - android_default_keystore_path = "//build/android/ant/chromium-debug.keystore" + android_default_keystore_path = + "//build/android/ant/chromium-debug.keystore" android_default_keystore_name = "chromiumdebugkey" android_default_keystore_password = "chromium" @@ -89,7 +91,8 @@ android_sdk = "${android_sdk_root}/platforms/android-${android_sdk_version}" android_sdk_tools = "${android_sdk_root}/tools" - android_sdk_build_tools = "${android_sdk_root}/build-tools/$android_sdk_build_tools_version" + android_sdk_build_tools = + "${android_sdk_root}/build-tools/$android_sdk_build_tools_version" # Path to the SDK's android.jar android_sdk_jar = "$android_sdk/android.jar" @@ -99,16 +102,22 @@ # Subdirectories inside android_ndk_root that contain the sysroot for the # associated platform. _android_api_level = 14 - x86_android_sysroot_subdir = "platforms/android-${_android_api_level}/arch-x86" - arm_android_sysroot_subdir = "platforms/android-${_android_api_level}/arch-arm" - mips_android_sysroot_subdir = "platforms/android-${_android_api_level}/arch-mips" + x86_android_sysroot_subdir = + "platforms/android-${_android_api_level}/arch-x86" + arm_android_sysroot_subdir = + "platforms/android-${_android_api_level}/arch-arm" + mips_android_sysroot_subdir = + "platforms/android-${_android_api_level}/arch-mips" # Toolchain root directory for each build. The actual binaries are inside # a "bin" directory inside of these. _android_toolchain_version = "4.9" - x86_android_toolchain_root = "$android_ndk_root/toolchains/x86-${_android_toolchain_version}/prebuilt/${android_host_os}-${android_host_arch}" - arm_android_toolchain_root = "$android_ndk_root/toolchains/arm-linux-androideabi-${_android_toolchain_version}/prebuilt/${android_host_os}-${android_host_arch}" - mips_android_toolchain_root = "$android_ndk_root/toolchains/mipsel-linux-android-${_android_toolchain_version}/prebuilt/${android_host_os}-${android_host_arch}" + x86_android_toolchain_root = + "$android_ndk_root/toolchains/x86-${_android_toolchain_version}/prebuilt/${android_host_os}-${android_host_arch}" + arm_android_toolchain_root = + "$android_ndk_root/toolchains/arm-linux-androideabi-${_android_toolchain_version}/prebuilt/${android_host_os}-${android_host_arch}" + mips_android_toolchain_root = + "$android_ndk_root/toolchains/mipsel-linux-android-${_android_toolchain_version}/prebuilt/${android_host_os}-${android_host_arch}" # Location of libgcc. This is only needed for the current GN toolchain, so we # only need to define the current one, rather than one for every platform @@ -118,24 +127,24 @@ _binary_prefix = "i686-linux-android" android_toolchain_root = "$x86_android_toolchain_root" android_libgcc_file = - "$android_toolchain_root/lib/gcc/i686-linux-android/${_android_toolchain_version}/libgcc.a" + "$android_toolchain_root/lib/gcc/i686-linux-android/${_android_toolchain_version}/libgcc.a" } else if (cpu_arch == "arm") { android_prebuilt_arch = "android-arm" _binary_prefix = "arm-linux-androideabi" android_toolchain_root = "$arm_android_toolchain_root" if (arm_use_thumb) { android_libgcc_file = - "$android_toolchain_root/lib/gcc/arm-linux-androideabi/${_android_toolchain_version}/thumb/libgcc.a" + "$android_toolchain_root/lib/gcc/arm-linux-androideabi/${_android_toolchain_version}/thumb/libgcc.a" } else { android_libgcc_file = - "$android_toolchain_root/lib/gcc/arm-linux-androideabi/${_android_toolchain_version}/libgcc.a" + "$android_toolchain_root/lib/gcc/arm-linux-androideabi/${_android_toolchain_version}/libgcc.a" } } else if (cpu_arch == "mipsel") { android_prebuilt_arch = "android-mips" _binary_prefix = "mipsel-linux-android" android_toolchain_root = "$mips_android_toolchain_root" android_libgcc_file = - "$android_toolchain_root/lib/gcc/mipsel-linux-android/${_android_toolchain_version}/libgcc.a" + "$android_toolchain_root/lib/gcc/mipsel-linux-android/${_android_toolchain_version}/libgcc.a" } else { assert(false, "Need android libgcc support for your target arch.") } @@ -143,7 +152,8 @@ android_tool_prefix = "$android_toolchain_root/bin/$_binary_prefix-" android_readelf = "${android_tool_prefix}readelf" android_objcopy = "${android_tool_prefix}objcopy" - android_gdbserver = "$android_ndk_root/prebuilt/$android_prebuilt_arch/gdbserver/gdbserver" + android_gdbserver = + "$android_ndk_root/prebuilt/$android_prebuilt_arch/gdbserver/gdbserver" # stlport stuff --------------------------------------------------------------
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni index d33c200..41fd75f35 100644 --- a/build/config/android/internal_rules.gni +++ b/build/config/android/internal_rules.gni
@@ -6,16 +6,18 @@ assert(is_android) - rebased_android_sdk = rebase_path(android_sdk, root_build_dir) rebased_android_sdk_root = rebase_path(android_sdk_root, root_build_dir) -rebased_android_sdk_build_tools = rebase_path(android_sdk_build_tools, root_build_dir) +rebased_android_sdk_build_tools = + rebase_path(android_sdk_build_tools, root_build_dir) android_sdk_jar = "$android_sdk/android.jar" rebased_android_sdk_jar = rebase_path(android_sdk_jar, root_build_dir) template("android_lint") { - if (defined(invoker.testonly)) { testonly = invoker.testonly } + if (defined(invoker.testonly)) { + testonly = invoker.testonly + } jar_path = invoker.jar_path android_manifest = invoker.android_manifest @@ -28,35 +30,41 @@ config_path = base_path + "/config.xml" suppressions_file = "//build/android/lint/suppressions.xml" inputs = [ - suppressions_file, - android_manifest, - jar_path, - ] + java_files + suppressions_file, + android_manifest, + jar_path, + ] + java_files outputs = [ config_path, - result_path + result_path, ] rebased_java_files = rebase_path(java_files, root_build_dir) args = [ "--lint-path=$rebased_android_sdk_root/tools/lint", - "--config-path", rebase_path(suppressions_file, root_build_dir), - "--manifest-path", rebase_path(android_manifest, root_build_dir), + "--config-path", + rebase_path(suppressions_file, root_build_dir), + "--manifest-path", + rebase_path(android_manifest, root_build_dir), "--product-dir=.", - "--jar-path", rebase_path(jar_path, root_build_dir), - "--processed-config-path", rebase_path(config_path, root_build_dir), - "--result-path", rebase_path(result_path, root_build_dir), + "--jar-path", + rebase_path(jar_path, root_build_dir), + "--processed-config-path", + rebase_path(config_path, root_build_dir), + "--result-path", + rebase_path(result_path, root_build_dir), "--java-files=$rebased_java_files", "--enable", ] } } - template("dex") { - if (defined(invoker.testonly)) { testonly = invoker.testonly } + if (defined(invoker.testonly)) { + testonly = invoker.testonly + } assert(defined(invoker.sources)) assert(defined(invoker.output)) @@ -64,7 +72,10 @@ script = "//build/android/gyp/dex.py" depfile = "$target_gen_dir/$target_name.d" sources = invoker.sources - outputs = [depfile, invoker.output] + outputs = [ + depfile, + invoker.output, + ] if (defined(invoker.inputs)) { inputs = invoker.inputs } @@ -76,15 +87,16 @@ rebased_output = rebase_path(invoker.output, root_build_dir) args = [ - "--depfile", rebase_path(depfile, root_build_dir), - "--android-sdk-tools", rebased_android_sdk_build_tools, - "--dex-path", rebased_output, + "--depfile", + rebase_path(depfile, root_build_dir), + "--android-sdk-tools", + rebased_android_sdk_build_tools, + "--dex-path", + rebased_output, ] if (defined(invoker.no_locals) && invoker.no_locals) { - args += [ - "--no-locals=1" - ] + args += [ "--no-locals=1" ] } if (defined(invoker.args)) { @@ -95,11 +107,12 @@ } } - # Creates a zip archive of the inputs. # If base_dir is provided, the archive paths will be relative to it. template("zip") { - if (defined(invoker.testonly)) { testonly = invoker.testonly } + if (defined(invoker.testonly)) { + testonly = invoker.testonly + } assert(defined(invoker.inputs)) assert(defined(invoker.output)) @@ -112,22 +125,23 @@ inputs = invoker.inputs outputs = [ depfile, - invoker.output + invoker.output, ] args = [ - "--depfile", rebase_path(depfile, root_build_dir), + "--depfile", + rebase_path(depfile, root_build_dir), "--inputs=$rebase_inputs", "--output=$rebase_output", ] if (defined(invoker.base_dir)) { args += [ - "--base-dir", rebase_path(invoker.base_dir, root_build_dir) + "--base-dir", + rebase_path(invoker.base_dir, root_build_dir), ] } } } - # Write the target's .build_config file. This is a json file that contains a # dictionary of information about how to build this target (things that # require knowledge about this target's dependencies and cannot be calculated @@ -138,7 +152,9 @@ # See build/android/gyp/write_build_config.py and # build/android/gyp/util/build_utils.py:ExpandFileArgs template("write_build_config") { - if (defined(invoker.testonly)) { testonly = invoker.testonly } + if (defined(invoker.testonly)) { + testonly = invoker.testonly + } assert(defined(invoker.type)) assert(defined(invoker.build_config)) @@ -146,7 +162,8 @@ type = invoker.type build_config = invoker.build_config - assert(type == "android_apk" || type == "java_library" || type == "android_resources") + assert(type == "android_apk" || type == "java_library" || + type == "android_resources") action(target_name) { script = "//build/android/gyp/write_build_config.py" @@ -168,29 +185,33 @@ outputs = [ depfile, - build_config + build_config, ] args = [ - "--type", type, - "--depfile", rebase_path(depfile, root_build_dir), + "--type", + type, + "--depfile", + rebase_path(depfile, root_build_dir), "--possible-deps-configs=$rebase_possible_deps_configs", - "--build-config", rebase_path(build_config, root_build_dir), + "--build-config", + rebase_path(build_config, root_build_dir), ] is_java_library = type == "java_library" is_apk = type == "android_apk" is_android_resources = type == "android_resources" - supports_android = (is_apk || is_android_resources || - (is_java_library && defined(invoker.supports_android) && - invoker.supports_android)) - requires_android = (is_apk || is_android_resources || - (is_java_library && defined(invoker.requires_android) && - invoker.requires_android)) + supports_android = is_apk || is_android_resources || + (is_java_library && defined(invoker.supports_android) && + invoker.supports_android) + requires_android = is_apk || is_android_resources || + (is_java_library && defined(invoker.requires_android) && + invoker.requires_android) - assert(!requires_android || supports_android, "requires_android requires" + - " supports_android") + assert(!requires_android || supports_android, + "requires_android requires" + " supports_android") + # Mark these variables as used. assert(is_java_library || true) assert(is_apk || true) @@ -198,13 +219,15 @@ if (is_java_library || is_apk) { args += [ - "--jar-path", rebase_path(invoker.jar_path, root_build_dir), + "--jar-path", + rebase_path(invoker.jar_path, root_build_dir), ] } if (is_apk || (is_java_library && supports_android)) { args += [ - "--dex-path", rebase_path(invoker.dex_path, root_build_dir), + "--dex-path", + rebase_path(invoker.dex_path, root_build_dir), ] } if (supports_android) { @@ -221,19 +244,20 @@ if (is_android_resources || is_apk) { assert(defined(invoker.resources_zip)) args += [ - "--resources-zip", rebase_path(invoker.resources_zip, root_build_dir), + "--resources-zip", + rebase_path(invoker.resources_zip, root_build_dir), ] if (defined(invoker.android_manifest)) { - inputs += [ - invoker.android_manifest - ] + inputs += [ invoker.android_manifest ] args += [ - "--android-manifest", rebase_path(invoker.android_manifest, root_build_dir), + "--android-manifest", + rebase_path(invoker.android_manifest, root_build_dir), ] } if (defined(invoker.custom_package)) { args += [ - "--package-name", invoker.custom_package + "--package-name", + invoker.custom_package, ] } } @@ -251,15 +275,17 @@ if (defined(invoker.srcjar)) { args += [ - "--srcjar", rebase_path(invoker.srcjar, root_build_dir) + "--srcjar", + rebase_path(invoker.srcjar, root_build_dir), ] } } } - template("process_java_prebuilt") { - if (defined(invoker.testonly)) { testonly = invoker.testonly } + if (defined(invoker.testonly)) { + testonly = invoker.testonly + } _input_jar_path = invoker.input_jar_path _output_jar_path = invoker.output_jar_path @@ -287,19 +313,27 @@ _output_jar_path, ] args = [ - "--depfile", rebase_path(depfile, root_build_dir), - "--proguard-path", rebase_path(_proguard_jar_path, root_build_dir), - "--input-path", rebase_path(_input_jar_path, root_build_dir), - "--output-path", rebase_path(_output_jar_path, root_build_dir), - "--proguard-config", rebase_path(_proguard_config_path, root_build_dir), - "--classpath", rebased_android_sdk_jar, + "--depfile", + rebase_path(depfile, root_build_dir), + "--proguard-path", + rebase_path(_proguard_jar_path, root_build_dir), + "--input-path", + rebase_path(_input_jar_path, root_build_dir), + "--output-path", + rebase_path(_output_jar_path, root_build_dir), + "--proguard-config", + rebase_path(_proguard_config_path, root_build_dir), + "--classpath", + rebased_android_sdk_jar, "--classpath=@FileArg($_rebased_build_config:javac:classpath)", ] } } else { copy("${target_name}__copy_jar") { - sources = [_input_jar_path] - outputs = [_output_jar_path] + sources = [ + _input_jar_path, + ] + outputs = [ _output_jar_path ] } } @@ -309,28 +343,34 @@ outputs = [ depfile, _jar_toc_path, - _jar_toc_path + ".md5.stamp" + _jar_toc_path + ".md5.stamp", ] - inputs = [ _output_jar_path ] + inputs = [ + _output_jar_path, + ] args = [ - "--depfile", rebase_path(depfile, root_build_dir), - "--jar-path", rebase_path(_output_jar_path, root_build_dir), - "--toc-path", rebase_path(_jar_toc_path, root_build_dir), + "--depfile", + rebase_path(depfile, root_build_dir), + "--jar-path", + rebase_path(_output_jar_path, root_build_dir), + "--toc-path", + rebase_path(_jar_toc_path, root_build_dir), ] } group(target_name) { deps = [ - ":${target_name}__jar_toc" + ":${target_name}__jar_toc", ] } } - # Packages resources, assets, dex, and native libraries into an apk. Signs and # zipaligns the apk. template("create_apk") { - if (defined(invoker.testonly)) { testonly = invoker.testonly } + if (defined(invoker.testonly)) { + testonly = invoker.testonly + } _android_manifest = invoker.android_manifest _base_path = invoker.base_path @@ -349,7 +389,7 @@ _native_libs_dir = "//build/android/empty/res" if (defined(invoker.native_libs_dir)) { - _native_libs_dir = invoker.native_libs_dir + _native_libs_dir = invoker.native_libs_dir } _asset_location = "//build/android/empty/res" @@ -364,8 +404,8 @@ _resource_packaged_apk_path = _base_apk_path + ".ap_" _packaged_apk_path = _base_apk_path + ".unfinished.apk" - _shared_resources = defined(invoker.shared_resources) && invoker.shared_resources - + _shared_resources = + defined(invoker.shared_resources) && invoker.shared_resources _configuration_name = "Release" if (is_debug) { @@ -381,28 +421,35 @@ _android_manifest, _resources_zip, ] - outputs = [depfile, _resource_packaged_apk_path] + outputs = [ + depfile, + _resource_packaged_apk_path, + ] - _rebased_resources_zips = [rebase_path(_resources_zip, root_build_dir)] + _rebased_resources_zips = [ rebase_path(_resources_zip, root_build_dir) ] args = [ - "--depfile", rebase_path(depfile, root_build_dir), - "--android-sdk", rebased_android_sdk, - "--android-sdk-tools", rebased_android_sdk_build_tools, - - "--configuration-name=$_configuration_name", - - "--android-manifest", rebase_path(_android_manifest, root_build_dir), - "--version-code", _version_code, - "--version-name", _version_name, - - "--asset-dir", rebase_path(_asset_location, root_build_dir), - "--resource-zips=$_rebased_resources_zips", - - "--apk-path", rebase_path(_resource_packaged_apk_path, root_build_dir), - ] + "--depfile", + rebase_path(depfile, root_build_dir), + "--android-sdk", + rebased_android_sdk, + "--android-sdk-tools", + rebased_android_sdk_build_tools, + "--configuration-name=$_configuration_name", + "--android-manifest", + rebase_path(_android_manifest, root_build_dir), + "--version-code", + _version_code, + "--version-name", + _version_name, + "--asset-dir", + rebase_path(_asset_location, root_build_dir), + "--resource-zips=$_rebased_resources_zips", + "--apk-path", + rebase_path(_resource_packaged_apk_path, root_build_dir), + ] if (_shared_resources) { - args += ["--shared-resources"] + args += [ "--shared-resources" ] } } @@ -415,7 +462,7 @@ inputs = [ _dex_path, _resource_packaged_apk_path, - _ant_script + _ant_script, ] outputs = [ @@ -424,13 +471,14 @@ ] _rebased_emma_jar = "" - _rebased_resource_packaged_apk_path = rebase_path( - _resource_packaged_apk_path, root_build_dir) + _rebased_resource_packaged_apk_path = + rebase_path(_resource_packaged_apk_path, root_build_dir) _rebased_packaged_apk_path = rebase_path(_packaged_apk_path, root_build_dir) _rebased_native_libs_dir = rebase_path(_native_libs_dir, root_build_dir) _rebased_dex_path = rebase_path(_dex_path, root_build_dir) args = [ - "--depfile", rebase_path(depfile, root_build_dir), + "--depfile", + rebase_path(depfile, root_build_dir), "--", "-quiet", "-DANDROID_SDK_ROOT=$rebased_android_sdk_root", @@ -443,9 +491,9 @@ "-DEMMA_INSTRUMENT=0", "-DEMMA_DEVICE_JAR=$_rebased_emma_jar", "-DDEX_FILE_PATH=$_rebased_dex_path", - "-Dbasedir=.", - "-buildfile", rebase_path(_ant_script, root_build_dir) + "-buildfile", + rebase_path(_ant_script, root_build_dir), ] } @@ -453,40 +501,57 @@ script = "//build/android/gyp/finalize_apk.py" depfile = "$target_gen_dir/$target_name.d" - sources = [_packaged_apk_path] - inputs = [_keystore_path] - outputs = [depfile, _final_apk_path] + sources = [ + _packaged_apk_path, + ] + inputs = [ + _keystore_path, + ] + outputs = [ + depfile, + _final_apk_path, + ] args = [ - "--depfile", rebase_path(depfile, root_build_dir), - "--zipalign-path", rebase_path(zipalign_path, root_build_dir), - "--unsigned-apk-path", rebase_path(_packaged_apk_path, root_build_dir), - "--final-apk-path", rebase_path(_final_apk_path, root_build_dir), - "--key-path", rebase_path(_keystore_path, root_build_dir), - "--key-name", _keystore_name, - "--key-passwd", _keystore_password, + "--depfile", + rebase_path(depfile, root_build_dir), + "--zipalign-path", + rebase_path(zipalign_path, root_build_dir), + "--unsigned-apk-path", + rebase_path(_packaged_apk_path, root_build_dir), + "--final-apk-path", + rebase_path(_final_apk_path, root_build_dir), + "--key-path", + rebase_path(_keystore_path, root_build_dir), + "--key-name", + _keystore_name, + "--key-passwd", + _keystore_password, ] if (_load_library_from_apk) { _rezip_jar_path = "$root_build_dir/lib.java/rezip_apk.jar" - inputs += [ - _rezip_jar_path - ] + inputs += [ _rezip_jar_path ] args += [ "--load-library-from-zip-file=1", - "--rezip-apk-jar-path", rebase_path(_rezip_jar_path, root_build_dir) + "--rezip-apk-jar-path", + rebase_path(_rezip_jar_path, root_build_dir), ] } } group(target_name) { - deps = [":${target_name}__finalize"] + deps = [ + ":${target_name}__finalize", + ] } } template("java_prebuilt_impl") { - if (defined(invoker.testonly)) { testonly = invoker.testonly } - _supports_android = ( - defined(invoker.supports_android) && invoker.supports_android) + if (defined(invoker.testonly)) { + testonly = invoker.testonly + } + _supports_android = + defined(invoker.supports_android) && invoker.supports_android assert(defined(invoker.jar_path)) _base_path = "${target_gen_dir}/$target_name" @@ -500,13 +565,12 @@ _final_deps = [] _template_name = target_name - _final_deps += [ ":${_template_name}__build_config" ] write_build_config("${_template_name}__build_config") { type = "java_library" supports_android = _supports_android - requires_android = (defined(invoker.requires_android) && - invoker.requires_android) + requires_android = + defined(invoker.requires_android) && invoker.requires_android deps = [] if (defined(invoker.deps)) { @@ -534,7 +598,9 @@ if (_supports_android) { _final_deps += [ ":${_template_name}__dex" ] dex("${_template_name}__dex") { - sources = [_jar_path] + sources = [ + _jar_path, + ] output = _dex_path } } @@ -544,7 +610,6 @@ } } - # Compiles and jars a set of java files. # # Outputs: @@ -561,7 +626,9 @@ # jar_path: Use this to explicitly set the output jar path. Defaults to # "${target_gen_dir}/${target_name}.jar. template("compile_java") { - if (defined(invoker.testonly)) { testonly = invoker.testonly } + if (defined(invoker.testonly)) { + testonly = invoker.testonly + } assert(defined(invoker.java_files)) assert(defined(invoker.build_config)) @@ -597,6 +664,7 @@ _dep_name = get_label_info(dep, "name") _java_srcjars += [ "$_dep_gen_dir/$_dep_name.srcjar" ] } + # Mark srcjar_deps as used. assert(_srcjar_deps == [] || true) @@ -617,7 +685,7 @@ outputs = [ depfile, _intermediate_jar_path, - _intermediate_jar_path + ".md5.stamp" + _intermediate_jar_path + ".md5.stamp", ] sources = _java_files + _java_srcjars inputs = _system_jars + [ _build_config ] @@ -657,12 +725,14 @@ } } - template("java_library_impl") { - if (defined(invoker.testonly)) { testonly = invoker.testonly } + if (defined(invoker.testonly)) { + testonly = invoker.testonly + } - assert(defined(invoker.java_files) || defined(invoker.DEPRECATED_java_in_dir) - || defined(invoker.srcjars) || defined(invoker.srcjar_deps)) + assert( + defined(invoker.java_files) || defined(invoker.DEPRECATED_java_in_dir) || + defined(invoker.srcjars) || defined(invoker.srcjar_deps)) _base_path = "$target_gen_dir/$target_name" _jar_path = _base_path + ".jar" if (defined(invoker.jar_path)) { @@ -676,10 +746,10 @@ _final_datadeps = invoker.datadeps } - _supports_android = (defined(invoker.supports_android) && - invoker.supports_android) - _requires_android = (defined(invoker.requires_android) && - invoker.requires_android) + _supports_android = + defined(invoker.supports_android) && invoker.supports_android + _requires_android = + defined(invoker.requires_android) && invoker.requires_android if (_supports_android) { _dex_path = _base_path + ".dex.jar" @@ -697,8 +767,8 @@ type = "java_library" supports_android = _supports_android requires_android = _requires_android - bypass_platform_checks = (defined(invoker.bypass_platform_checks) && - invoker.bypass_platform_checks) + bypass_platform_checks = defined(invoker.bypass_platform_checks) && + invoker.bypass_platform_checks deps = [] if (defined(invoker.deps)) { @@ -734,21 +804,20 @@ } else if (defined(invoker.DEPRECATED_java_in_dir)) { _src_dir = invoker.DEPRECATED_java_in_dir + "/src" _src_dir_exists = exec_script("//build/dir_exists.py", - [ rebase_path(_src_dir, root_build_dir) ], - "string") + [ rebase_path(_src_dir, root_build_dir) ], + "string") assert(_src_dir_exists == "False", - "In GN, java_in_dir should be the fully specified java directory " + - "(i.e. including the trailing \"/src\")") + "In GN, java_in_dir should be the fully specified java directory " + + "(i.e. including the trailing \"/src\")") _java_files_build_rel = exec_script( - "//build/android/gyp/find.py", - [ - "--pattern", - "*.java", - rebase_path(invoker.DEPRECATED_java_in_dir, root_build_dir) - ], - "list lines" - ) + "//build/android/gyp/find.py", + [ + "--pattern", + "*.java", + rebase_path(invoker.DEPRECATED_java_in_dir, root_build_dir), + ], + "list lines") _java_files = rebase_path(_java_files_build_rel, ".", root_build_dir) } assert(_java_files != [] || _srcjar_deps != [] || _srcjars != []) @@ -763,10 +832,18 @@ chromium_code = _chromium_code android = _requires_android - if (defined(invoker.jar_excluded_patterns)) { jar_excluded_patterns = invoker.jar_excluded_patterns } - if (defined(invoker.proguard_preprocess)) { proguard_preprocess = invoker.proguard_preprocess } - if (defined(invoker.proguard_config)) { proguard_config = invoker.proguard_config } - if (defined(invoker.dist_jar_path)) { dist_jar_path = invoker.dist_jar_path } + if (defined(invoker.jar_excluded_patterns)) { + jar_excluded_patterns = invoker.jar_excluded_patterns + } + if (defined(invoker.proguard_preprocess)) { + proguard_preprocess = invoker.proguard_preprocess + } + if (defined(invoker.proguard_config)) { + proguard_config = invoker.proguard_config + } + if (defined(invoker.dist_jar_path)) { + dist_jar_path = invoker.dist_jar_path + } } if (defined(invoker.main_class)) { @@ -775,18 +852,24 @@ script = "//build/android/gyp/create_java_binary_script.py" depfile = "$target_gen_dir/$target_name.d" java_script = "$root_build_dir/bin/$_template_name" - inputs = [ _build_config ] + inputs = [ + _build_config, + ] outputs = [ depfile, java_script, ] _rebased_build_config = rebase_path(_build_config, root_build_dir) args = [ - "--depfile", rebase_path(depfile, root_build_dir), - "--output", rebase_path(java_script, root_build_dir), + "--depfile", + rebase_path(depfile, root_build_dir), + "--output", + rebase_path(java_script, root_build_dir), "--classpath=@FileArg($_rebased_build_config:java:full_classpath)", - "--jar-path", rebase_path(_jar_path, root_build_dir), - "--main-class", invoker.main_class, + "--jar-path", + rebase_path(_jar_path, root_build_dir), + "--main-class", + invoker.main_class, ] } } @@ -808,9 +891,23 @@ _final_deps += [ ":${_template_name}__dex" ] dex("${_template_name}__dex") { - sources = [_jar_path] + sources = [ + _jar_path, + ] output = _dex_path } + + if (defined(invoker.standalone_dex_path)) { + _final_deps += [ ":${_template_name}__standalone_dex" ] + _rebased_build_config = rebase_path(_build_config, root_build_dir) + dex("${_template_name}__standalone_dex") { + sources = [_jar_path] + inputs = [_build_config] + output = invoker.standalone_dex_path + dex_arg_key = "${_rebased_build_config}:final_dex:dependency_dex_files" + args = [ "--inputs=@FileArg($dex_arg_key)" ] + } + } } group(target_name) { @@ -822,10 +919,11 @@ } } - # Runs process_resources.py template("process_resources") { - if (defined(invoker.testonly)) { testonly = invoker.testonly } + if (defined(invoker.testonly)) { + testonly = invoker.testonly + } zip_path = invoker.zip_path srcjar_path = invoker.srcjar_path @@ -848,11 +946,9 @@ srcjar_path, ] - sources_build_rel = exec_script( - "//build/android/gyp/find.py", - rebase_path(resource_dirs, root_build_dir), - "list lines" - ) + sources_build_rel = exec_script("//build/android/gyp/find.py", + rebase_path(resource_dirs, root_build_dir), + "list lines") sources = rebase_path(sources_build_rel, ".", root_build_dir) inputs = [ @@ -863,15 +959,19 @@ rebase_resource_dirs = rebase_path(resource_dirs, root_build_dir) rebase_build_config = rebase_path(build_config, root_build_dir) args = [ - "--depfile", rebase_path(depfile, root_build_dir), - "--android-sdk", rebase_path(android_sdk, root_build_dir), - "--android-sdk-tools", rebase_path(android_sdk_build_tools, root_build_dir), - "--android-manifest", rebase_path(android_manifest, root_build_dir), - + "--depfile", + rebase_path(depfile, root_build_dir), + "--android-sdk", + rebase_path(android_sdk, root_build_dir), + "--android-sdk-tools", + rebase_path(android_sdk_build_tools, root_build_dir), + "--android-manifest", + rebase_path(android_manifest, root_build_dir), "--resource-dirs=$rebase_resource_dirs", - "--srcjar-out", rebase_path(srcjar_path, root_build_dir), - "--resource-zip-out", rebase_path(zip_path, root_build_dir), - + "--srcjar-out", + rebase_path(srcjar_path, root_build_dir), + "--resource-zip-out", + rebase_path(zip_path, root_build_dir), "--dependencies-res-zips=@FileArg($rebase_build_config:resources:dependency_zips)", "--extra-res-packages=@FileArg($rebase_build_config:resources:extra_package_names)", ] @@ -882,24 +982,25 @@ if (defined(invoker.custom_package)) { args += [ - "--custom-package", invoker.custom_package, + "--custom-package", + invoker.custom_package, ] } if (defined(invoker.v14_verify_only) && invoker.v14_verify_only) { - args += ["--v14-verify-only"] + args += [ "--v14-verify-only" ] } - if (defined(invoker.shared_resources) && - invoker.shared_resources) { - args += ["--shared-resources"] + if (defined(invoker.shared_resources) && invoker.shared_resources) { + args += [ "--shared-resources" ] } if (defined(invoker.all_resources_zip_path)) { all_resources_zip = invoker.all_resources_zip_path outputs += [ all_resources_zip ] args += [ - "--all-resources-zip-out", rebase_path(all_resources_zip, root_build_dir) + "--all-resources-zip-out", + rebase_path(all_resources_zip, root_build_dir), ] } @@ -910,12 +1011,16 @@ } template("copy_ex") { - if (defined(invoker.testonly)) { testonly = invoker.testonly } + if (defined(invoker.testonly)) { + testonly = invoker.testonly + } action(target_name) { script = "//build/android/gyp/copy_ex.py" - if (defined(invoker.deps)) { deps = invoker.deps } + if (defined(invoker.deps)) { + deps = invoker.deps + } sources = [] if (defined(invoker.sources)) { @@ -928,19 +1033,19 @@ } depfile = "$target_gen_dir/$target_name.d" - outputs = [ - depfile, - ] + outputs = [ depfile ] args = [ - "--depfile", rebase_path(depfile, root_build_dir), - "--dest", rebase_path(invoker.dest, root_build_dir), + "--depfile", + rebase_path(depfile, root_build_dir), + "--dest", + rebase_path(invoker.dest, root_build_dir), ] rebased_sources = rebase_path(sources, root_build_dir) args += [ "--files=$rebased_sources" ] if (defined(invoker.clear_dir) && invoker.clear_dir) { - args += ["--clear"] + args += [ "--clear" ] } if (defined(invoker.args)) {
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni index a5c0b0a..d1342ac2 100644 --- a/build/config/android/rules.gni +++ b/build/config/android/rules.gni
@@ -30,7 +30,9 @@ # jni_package = "foo" # } template("generate_jni") { - if (defined(invoker.testonly)) { testonly = invoker.testonly } + if (defined(invoker.testonly)) { + testonly = invoker.testonly + } assert(defined(invoker.sources)) assert(defined(invoker.jni_package)) @@ -46,23 +48,29 @@ script = "//base/android/jni_generator/jni_generator.py" depfile = "$target_gen_dir/$target_name.{{source_name_part}}.d" sources = invoker.sources - inputs = [ jni_generator_include ] + inputs = [ + jni_generator_include, + ] outputs = [ depfile, - "${jni_output_dir}/{{source_name_part}}_jni.h" + "${jni_output_dir}/{{source_name_part}}_jni.h", ] args = [ - "--depfile", rebase_path(depfile, root_build_dir), + "--depfile", + rebase_path(depfile, root_build_dir), "--input_file={{source}}", "--optimize_generation=1", "--ptr_type=long", - "--output_dir", rebase_path(jni_output_dir, root_build_dir), - "--includes", rebase_path(jni_generator_include, "//"), + "--output_dir", + rebase_path(jni_output_dir, root_build_dir), + "--includes", + rebase_path(jni_generator_include, "//"), ] if (defined(invoker.jni_generator_jarjar_file)) { args += [ - "--jarjar", rebase_path(jni_generator_jarjar_file, root_build_dir), + "--jarjar", + rebase_path(jni_generator_jarjar_file, root_build_dir), ] } } @@ -78,7 +86,9 @@ } group(target_name) { - deps = [ ":$foreach_target_name" ] + deps = [ + ":$foreach_target_name", + ] public_configs = [ ":jni_includes_${target_name}" ] if (defined(invoker.deps)) { @@ -88,11 +98,12 @@ public_deps = invoker.public_deps } - if (defined(invoker.visibility)) { visibility = invoker.visibility } + if (defined(invoker.visibility)) { + visibility = invoker.visibility + } } } - # Declare a jni target for a prebuilt jar # # This target generates the native jni bindings for a set of classes in a .jar. @@ -117,7 +128,9 @@ # jni_package = "foo" # } template("generate_jar_jni") { - if (defined(invoker.testonly)) { testonly = invoker.testonly } + if (defined(invoker.testonly)) { + testonly = invoker.testonly + } assert(defined(invoker.classes)) assert(defined(invoker.jni_package)) @@ -139,8 +152,7 @@ jni_actions = [] foreach(class, invoker.classes) { _classname_list = [] - _classname_list = process_file_template( - [class], "{{source_name_part}}") + _classname_list = process_file_template([ class ], "{{source_name_part}}") classname = _classname_list[0] jni_target_name = "${target_name}__jni_${classname}" jni_actions += [ ":$jni_target_name" ] @@ -153,17 +165,22 @@ ] outputs = [ depfile, - "${jni_output_dir}/${classname}_jni.h" + "${jni_output_dir}/${classname}_jni.h", ] args = [ - "--depfile", rebase_path(depfile, root_build_dir), - "--jar_file", rebase_path(jar_file, root_build_dir), - "--input_file", class, + "--depfile", + rebase_path(depfile, root_build_dir), + "--jar_file", + rebase_path(jar_file, root_build_dir), + "--input_file", + class, "--optimize_generation=1", "--ptr_type=long", - "--output_dir", rebase_path(jni_output_dir, root_build_dir), - "--includes", rebase_path(jni_generator_include, root_build_dir), + "--output_dir", + rebase_path(jni_output_dir, root_build_dir), + "--includes", + rebase_path(jni_generator_include, root_build_dir), ] } } @@ -184,7 +201,6 @@ } } - # Declare a target for c-preprocessor-generated java files # # NOTE: For generating Java conterparts to enums prefer using the java_cpp_enum @@ -221,7 +237,9 @@ # include_path = "android/java/templates" # } template("java_cpp_template") { - if (defined(invoker.testonly)) { testonly = invoker.testonly } + if (defined(invoker.testonly)) { + testonly = invoker.testonly + } assert(defined(invoker.sources)) package_name = invoker.package_name + "" @@ -241,24 +259,31 @@ sources = invoker.sources - gen_dir = "${target_gen_dir}/${target_name}/java_cpp_template/${package_name}" + gen_dir = + "${target_gen_dir}/${target_name}/java_cpp_template/${package_name}" gcc_template_output_pattern = "${gen_dir}/{{source_name_part}}.java" outputs = [ depfile, - gcc_template_output_pattern + gcc_template_output_pattern, ] args = [ - "--depfile", rebase_path(depfile, root_build_dir), - "--include-path", rebase_path(include_path, root_build_dir), - "--output", rebase_path(gen_dir, root_build_dir) + "/{{source_name_part}}.java", + "--depfile", + rebase_path(depfile, root_build_dir), + "--include-path", + rebase_path(include_path, root_build_dir), + "--output", + rebase_path(gen_dir, root_build_dir) + "/{{source_name_part}}.java", "--template={{source}}", ] if (defined(invoker.defines)) { foreach(def, invoker.defines) { - args += ["--defines", def] + args += [ + "--defines", + def, + ] } } } @@ -275,7 +300,7 @@ group(target_name) { deps = [ - ":${target_name}__zip_srcjar" + ":${target_name}__zip_srcjar", ] } } @@ -308,7 +333,9 @@ # ] # } template("java_cpp_enum") { - if (defined(invoker.testonly)) { testonly = invoker.testonly } + if (defined(invoker.testonly)) { + testonly = invoker.testonly + } assert(defined(invoker.sources)) assert(defined(invoker.outputs)) @@ -317,21 +344,25 @@ sources = invoker.sources script = "//build/android/gyp/java_cpp_enum.py" gen_dir = "${target_gen_dir}/${target_name}/enums" - outputs = get_path_info( - rebase_path(invoker.outputs, ".", gen_dir), "abspath") + outputs = + get_path_info(rebase_path(invoker.outputs, ".", gen_dir), "abspath") args = [ - "--output_dir", rebase_path(gen_dir, root_build_dir), + "--output_dir", + rebase_path(gen_dir, root_build_dir), ] foreach(output, rebase_path(outputs, root_build_dir)) { - args += ["--assert_file", output] + args += [ + "--assert_file", + output, + ] } args += rebase_path(invoker.sources, root_build_dir) } generate_enum_outputs = get_target_outputs(":${target_name}__generate_enum") - base_gen_dir = get_label_info(":${target_name}__generate_enum", - "target_gen_dir") + base_gen_dir = + get_label_info(":${target_name}__generate_enum", "target_gen_dir") srcjar_path = "${target_gen_dir}/${target_name}.srcjar" zip("${target_name}__zip_srcjar") { @@ -342,7 +373,7 @@ group(target_name) { deps = [ - ":${target_name}__zip_srcjar" + ":${target_name}__zip_srcjar", ] } } @@ -361,13 +392,17 @@ # output = "$target_gen_dir/AndroidManifest.xml" # } template("jinja_template") { - if (defined(invoker.testonly)) { testonly = invoker.testonly } + if (defined(invoker.testonly)) { + testonly = invoker.testonly + } assert(defined(invoker.input)) assert(defined(invoker.output)) action(target_name) { - sources = [invoker.input] + sources = [ + invoker.input, + ] script = "//build/android/gyp/jinja_template.py" depfile = "$target_gen_dir/$target_name.d" @@ -377,13 +412,16 @@ ] args = [ - "--inputs", rebase_path(invoker.input, root_build_dir), - "--output", rebase_path(invoker.output, root_build_dir), - "--depfile", rebase_path(depfile, root_build_dir), + "--inputs", + rebase_path(invoker.input, root_build_dir), + "--output", + rebase_path(invoker.output, root_build_dir), + "--depfile", + rebase_path(depfile, root_build_dir), ] if (defined(invoker.variables)) { variables = invoker.variables - args += ["--variables=${variables}" ] + args += [ "--variables=${variables}" ] } } } @@ -410,7 +448,9 @@ # variables = ["color=red"] # } template("jinja_template_resources") { - if (defined(invoker.testonly)) { testonly = invoker.testonly } + if (defined(invoker.testonly)) { + testonly = invoker.testonly + } assert(defined(invoker.resources)) assert(defined(invoker.res_dir)) @@ -438,13 +478,16 @@ rebased_resources = rebase_path(invoker.resources, root_build_dir) args = [ "--inputs=${rebased_resources}", - "--inputs-base-dir", rebase_path(invoker.res_dir, root_build_dir), - "--outputs-zip", rebase_path(_resources_zip, root_build_dir), - "--depfile", rebase_path(depfile, root_build_dir), + "--inputs-base-dir", + rebase_path(invoker.res_dir, root_build_dir), + "--outputs-zip", + rebase_path(_resources_zip, root_build_dir), + "--depfile", + rebase_path(depfile, root_build_dir), ] if (defined(invoker.variables)) { variables = invoker.variables - args += ["--variables=${variables}" ] + args += [ "--variables=${variables}" ] } } @@ -487,7 +530,9 @@ # custom_package = "org.chromium.foo" # } template("android_resources") { - if (defined(invoker.testonly)) { testonly = invoker.testonly } + if (defined(invoker.testonly)) { + testonly = invoker.testonly + } assert(defined(invoker.resource_dirs)) assert(defined(invoker.android_manifest) || defined(invoker.custom_package)) @@ -501,9 +546,15 @@ type = "android_resources" resources_zip = zip_path srcjar = srcjar_path - if (defined(invoker.deps)) { deps = invoker.deps } - if (defined(invoker.android_manifest)) { android_manifest = invoker.android_manifest } - if (defined(invoker.custom_package)) { custom_package = invoker.custom_package } + if (defined(invoker.deps)) { + deps = invoker.deps + } + if (defined(invoker.android_manifest)) { + android_manifest = invoker.android_manifest + } + if (defined(invoker.custom_package)) { + custom_package = invoker.custom_package + } } android_manifest = "//build/android/AndroidManifest.xml" @@ -534,7 +585,6 @@ } } - # Declare a target that generates localized strings.xml from a .grd file. # # If this target is included in the deps of an android resources/library/apk, @@ -550,7 +600,9 @@ # grd_file = "foo_strings.grd" # } template("java_strings_grd") { - if (defined(invoker.testonly)) { testonly = invoker.testonly } + if (defined(invoker.testonly)) { + testonly = invoker.testonly + } base_path = "$target_gen_dir/$target_name" resources_zip = base_path + ".resources.zip" @@ -570,7 +622,8 @@ grit_output_dir = "$target_gen_dir/$extra_output_path" grit(grit_target_name) { grit_flags = [ - "-E", "ANDROID_JAVA_TAGGED_ONLY=false", + "-E", + "ANDROID_JAVA_TAGGED_ONLY=false", ] output_dir = grit_output_dir resource_ids = "" @@ -613,7 +666,9 @@ # ] # } template("java_strings_grd_prebuilt") { - if (defined(invoker.testonly)) { testonly = invoker.testonly } + if (defined(invoker.testonly)) { + testonly = invoker.testonly + } base_path = "$target_gen_dir/$target_name" resources_zip = base_path + ".resources.zip" @@ -673,21 +728,38 @@ # TODO(cjhopman): This should not act like a java_library for dependents (i.e. # dependents shouldn't get the jar in their classpath, etc.). java_library_impl(target_name) { - if (defined(invoker.DEPRECATED_java_in_dir)) { DEPRECATED_java_in_dir = invoker.DEPRECATED_java_in_dir } - if (defined(invoker.chromium_code)) { chromium_code = invoker.chromium_code } - if (defined(invoker.datadeps)) { deps = invoker.datadeps } - if (defined(invoker.deps)) { deps = invoker.deps } - if (defined(invoker.java_files)) { java_files = invoker.java_files } - if (defined(invoker.srcjar_deps)) { srcjar_deps = invoker.srcjar_deps } - if (defined(invoker.srcjars)) { srcjars = invoker.srcjars } - if (defined(invoker.bypass_platform_checks)) { bypass_platform_checks = invoker.bypass_platform_checks } - if (defined(invoker.testonly)) { testonly = invoker.testonly } + if (defined(invoker.DEPRECATED_java_in_dir)) { + DEPRECATED_java_in_dir = invoker.DEPRECATED_java_in_dir + } + if (defined(invoker.chromium_code)) { + chromium_code = invoker.chromium_code + } + if (defined(invoker.datadeps)) { + deps = invoker.datadeps + } + if (defined(invoker.deps)) { + deps = invoker.deps + } + if (defined(invoker.java_files)) { + java_files = invoker.java_files + } + if (defined(invoker.srcjar_deps)) { + srcjar_deps = invoker.srcjar_deps + } + if (defined(invoker.srcjars)) { + srcjars = invoker.srcjars + } + if (defined(invoker.bypass_platform_checks)) { + bypass_platform_checks = invoker.bypass_platform_checks + } + if (defined(invoker.testonly)) { + testonly = invoker.testonly + } main_class = invoker.main_class } } - # Declare an java library target # # Variables @@ -739,19 +811,45 @@ # } template("java_library") { java_library_impl(target_name) { - if (defined(invoker.DEPRECATED_java_in_dir)) { DEPRECATED_java_in_dir = invoker.DEPRECATED_java_in_dir } - if (defined(invoker.chromium_code)) { chromium_code = invoker.chromium_code } - if (defined(invoker.datadeps)) { deps = invoker.datadeps } - if (defined(invoker.deps)) { deps = invoker.deps } - if (defined(invoker.jar_excluded_patterns)) { jar_excluded_patterns = invoker.jar_excluded_patterns } - if (defined(invoker.java_files)) { java_files = invoker.java_files } - if (defined(invoker.proguard_config)) { proguard_config = invoker.proguard_config } - if (defined(invoker.proguard_preprocess)) { proguard_preprocess = invoker.proguard_preprocess } - if (defined(invoker.srcjar_deps)) { srcjar_deps = invoker.srcjar_deps } - if (defined(invoker.srcjars)) { srcjars = invoker.srcjars } - if (defined(invoker.bypass_platform_checks)) { bypass_platform_checks = invoker.bypass_platform_checks } - if (defined(invoker.testonly)) { testonly = invoker.testonly } - if (defined(invoker.jar_path)) { jar_path = invoker.jar_path } + if (defined(invoker.DEPRECATED_java_in_dir)) { + DEPRECATED_java_in_dir = invoker.DEPRECATED_java_in_dir + } + if (defined(invoker.chromium_code)) { + chromium_code = invoker.chromium_code + } + if (defined(invoker.datadeps)) { + deps = invoker.datadeps + } + if (defined(invoker.deps)) { + deps = invoker.deps + } + if (defined(invoker.jar_excluded_patterns)) { + jar_excluded_patterns = invoker.jar_excluded_patterns + } + if (defined(invoker.java_files)) { + java_files = invoker.java_files + } + if (defined(invoker.proguard_config)) { + proguard_config = invoker.proguard_config + } + if (defined(invoker.proguard_preprocess)) { + proguard_preprocess = invoker.proguard_preprocess + } + if (defined(invoker.srcjar_deps)) { + srcjar_deps = invoker.srcjar_deps + } + if (defined(invoker.srcjars)) { + srcjars = invoker.srcjars + } + if (defined(invoker.bypass_platform_checks)) { + bypass_platform_checks = invoker.bypass_platform_checks + } + if (defined(invoker.testonly)) { + testonly = invoker.testonly + } + if (defined(invoker.jar_path)) { + jar_path = invoker.jar_path + } if (defined(invoker.supports_android) && invoker.supports_android) { supports_android = true @@ -759,7 +857,6 @@ } } - # Declare an java library target for a prebuilt jar # # Variables @@ -781,10 +878,18 @@ template("java_prebuilt") { java_prebuilt_impl(target_name) { jar_path = invoker.jar_path - if (defined(invoker.testonly)) { testonly = invoker.testonly } - if (defined(invoker.deps)) { deps = invoker.deps } - if (defined(invoker.proguard_config)) { proguard_config = invoker.proguard_config } - if (defined(invoker.proguard_preprocess)) { proguard_preprocess = invoker.proguard_preprocess } + if (defined(invoker.testonly)) { + testonly = invoker.testonly + } + if (defined(invoker.deps)) { + deps = invoker.deps + } + if (defined(invoker.proguard_config)) { + proguard_config = invoker.proguard_config + } + if (defined(invoker.proguard_preprocess)) { + proguard_preprocess = invoker.proguard_preprocess + } } } @@ -815,6 +920,11 @@ # be used to remove unwanted parts of the library. # proguard_config: Path to the proguard config for preprocessing. # +# dex_path: If set, the resulting .dex.jar file will be placed under this +# path. +# standalone_dex_path: If set, a standalone .dex.jar containing the code from +# the library and all dependencies will be placed under this path. +# # # Example # android_library("foo_java") { @@ -835,29 +945,62 @@ # } template("android_library") { assert(!defined(invoker.jar_path), - "android_library does not support a custom jar path") + "android_library does not support a custom jar path") java_library_impl(target_name) { - if (defined(invoker.DEPRECATED_java_in_dir)) { DEPRECATED_java_in_dir = invoker.DEPRECATED_java_in_dir } - if (defined(invoker.chromium_code)) { chromium_code = invoker.chromium_code } - if (defined(invoker.datadeps)) { deps = invoker.datadeps } - if (defined(invoker.deps)) { deps = invoker.deps } - if (defined(invoker.jar_excluded_patterns)) { jar_excluded_patterns = invoker.jar_excluded_patterns } - if (defined(invoker.java_files)) { java_files = invoker.java_files } - if (defined(invoker.proguard_config)) { proguard_config = invoker.proguard_config } - if (defined(invoker.proguard_preprocess)) { proguard_preprocess = invoker.proguard_preprocess } - if (defined(invoker.srcjar_deps)) { srcjar_deps = invoker.srcjar_deps } - if (defined(invoker.srcjars)) { srcjars = invoker.srcjars } - if (defined(invoker.testonly)) { testonly = invoker.testonly } - if (defined(invoker.visibility)) { visibility = invoker.visibility } - if (defined(invoker.dex_path)) { dex_path = invoker.dex_path } + if (defined(invoker.DEPRECATED_java_in_dir)) { + DEPRECATED_java_in_dir = invoker.DEPRECATED_java_in_dir + } + if (defined(invoker.chromium_code)) { + chromium_code = invoker.chromium_code + } + if (defined(invoker.datadeps)) { + deps = invoker.datadeps + } + if (defined(invoker.deps)) { + deps = invoker.deps + } + if (defined(invoker.jar_excluded_patterns)) { + jar_excluded_patterns = invoker.jar_excluded_patterns + } + if (defined(invoker.java_files)) { + java_files = invoker.java_files + } + if (defined(invoker.proguard_config)) { + proguard_config = invoker.proguard_config + } + if (defined(invoker.proguard_preprocess)) { + proguard_preprocess = invoker.proguard_preprocess + } + if (defined(invoker.srcjar_deps)) { + srcjar_deps = invoker.srcjar_deps + } + if (defined(invoker.srcjars)) { + srcjars = invoker.srcjars + } + if (defined(invoker.testonly)) { + testonly = invoker.testonly + } + if (defined(invoker.visibility)) { + visibility = invoker.visibility + } + if (defined(invoker.dex_path)) { + dex_path = invoker.dex_path + } + if (defined(invoker.standalone_dex_path)) { + standalone_dex_path = invoker.standalone_dex_path + } supports_android = true requires_android = true - if (!defined(jar_excluded_patterns)) { jar_excluded_patterns = [] } + if (!defined(jar_excluded_patterns)) { + jar_excluded_patterns = [] + } jar_excluded_patterns += [ - "*/R.class", "*/R##*.class", - "*/Manifest.class", "*/Manifest##*.class", + "*/R.class", + "*/R##*.class", + "*/Manifest.class", + "*/Manifest##*.class", ] } } @@ -889,15 +1032,21 @@ jar_path = invoker.jar_path supports_android = true requires_android = true - if (defined(invoker.testonly)) { testonly = invoker.testonly } - if (defined(invoker.deps)) { deps = invoker.deps } - if (defined(invoker.proguard_config)) { proguard_config = invoker.proguard_config } - if (defined(invoker.proguard_preprocess)) { proguard_preprocess = invoker.proguard_preprocess } + if (defined(invoker.testonly)) { + testonly = invoker.testonly + } + if (defined(invoker.deps)) { + deps = invoker.deps + } + if (defined(invoker.proguard_config)) { + proguard_config = invoker.proguard_config + } + if (defined(invoker.proguard_preprocess)) { + proguard_preprocess = invoker.proguard_preprocess + } } } - - # Declare an Android apk target # # This target creates an Android APK containing java code, resources, assets, @@ -947,7 +1096,9 @@ # ] # } template("android_apk") { - if (defined(invoker.testonly)) { testonly = invoker.testonly } + if (defined(invoker.testonly)) { + testonly = invoker.testonly + } assert(defined(invoker.final_apk_path) || defined(invoker.apk_name)) gen_dir = "$target_gen_dir/$target_name" @@ -964,10 +1115,10 @@ } else if (defined(invoker.apk_name)) { _final_apk_path = "$root_build_dir/apks/" + invoker.apk_name + ".apk" } - _dist_jar_path_list = process_file_template( - [ _final_apk_path ], - "$root_build_dir/test.lib.java/{{source_name_part}}.jar" - ) + _dist_jar_path_list = + process_file_template( + [ _final_apk_path ], + "$root_build_dir/test.lib.java/{{source_name_part}}.jar") _dist_jar_path = _dist_jar_path_list[0] _native_libs = [] @@ -992,35 +1143,35 @@ if (defined(invoker.native_libs)) { _use_chromium_linker = false if (defined(invoker.use_chromium_linker)) { - _use_chromium_linker = (invoker.use_chromium_linker && - chromium_linker_supported) + _use_chromium_linker = + invoker.use_chromium_linker && chromium_linker_supported } if (defined(invoker.load_library_from_apk) && invoker.load_library_from_apk) { _load_library_from_apk = true - assert(_use_chromium_linker, "Loading library from the apk requires use" + - " of the Chromium linker.") + assert(_use_chromium_linker, + "Loading library from the apk requires use" + + " of the Chromium linker.") } _enable_relocation_packing = false if (defined(invoker.enable_relocation_packing) && invoker.enable_relocation_packing) { _enable_relocation_packing = relocation_packing_supported - assert(_use_chromium_linker, "Relocation packing requires use of the" + - " Chromium linker.") + assert(_use_chromium_linker, + "Relocation packing requires use of the" + " Chromium linker.") } _native_libs = process_file_template( - invoker.native_libs, - "$root_build_dir/lib.stripped/{{source_file_part}}") + invoker.native_libs, + "$root_build_dir/lib.stripped/{{source_file_part}}") _native_libs_dir = base_path + "/libs" if (_use_chromium_linker) { - _native_libs += [ - "$root_build_dir/lib.stripped/libchromium_android_linker.so" - ] + _native_libs += + [ "$root_build_dir/lib.stripped/libchromium_android_linker.so" ] } _enable_relocation_packing = false @@ -1047,16 +1198,16 @@ final_deps = [] - final_deps += [":${_template_name}__process_resources"] + final_deps += [ ":${_template_name}__process_resources" ] process_resources("${_template_name}__process_resources") { srcjar_path = "${target_gen_dir}/${target_name}.srcjar" android_manifest = invoker.android_manifest - resource_dirs = ["//build/android/ant/empty/res"] + resource_dirs = [ "//build/android/ant/empty/res" ] zip_path = resources_zip_path generate_constant_ids = true build_config = _build_config } - _srcjar_deps += [":${_template_name}__process_resources"] + _srcjar_deps += [ ":${_template_name}__process_resources" ] if (_native_libs != []) { _enable_chromium_linker_tests = false @@ -1077,17 +1228,17 @@ defines = [ "NATIVE_LIBRARIES_LIST=" + - "@FileArg($_rebased_build_config:native:java_libraries_list)", + "@FileArg($_rebased_build_config:native:java_libraries_list)", "NATIVE_LIBRARIES_VERSION_NUMBER=\"$_native_lib_version_name\"", ] if (_use_chromium_linker) { - defines += ["ENABLE_CHROMIUM_LINKER"] + defines += [ "ENABLE_CHROMIUM_LINKER" ] } if (_load_library_from_apk) { - defines += ["ENABLE_CHROMIUM_LINKER_LIBRARY_IN_ZIP_FILE"] + defines += [ "ENABLE_CHROMIUM_LINKER_LIBRARY_IN_ZIP_FILE" ] } if (_enable_chromium_linker_tests) { - defines += ["ENABLE_CHROMIUM_LINKER_TESTS"] + defines += [ "ENABLE_CHROMIUM_LINKER_TESTS" ] } } _srcjar_deps += [ ":${_template_name}__native_libraries_java" ] @@ -1113,37 +1264,46 @@ if (_dist_jar_path != "") { final_deps += [ ":${_template_name}__create_dist_jar" ] + # TODO(cjhopman): This is only ever needed to calculate the list of tests to # run. See build/android/pylib/instrumentation/test_jar.py. We should be # able to just do that calculation at build time instead. action("${_template_name}__create_dist_jar") { script = "//build/android/gyp/create_dist_jar.py" depfile = "$target_gen_dir/$target_name.d" - inputs = [ _build_config ] + inputs = [ + _build_config, + ] outputs = [ depfile, _dist_jar_path, ] args = [ - "--depfile", rebase_path(depfile, root_build_dir), - "--output", rebase_path(_dist_jar_path, root_build_dir), + "--depfile", + rebase_path(depfile, root_build_dir), + "--output", + rebase_path(_dist_jar_path, root_build_dir), "--inputs=@FileArg($_rebased_build_config:dist_jar:dependency_jars)", ] inputs += [ jar_path ] _rebased_jar_path = rebase_path([ jar_path ], root_build_dir) - args += [ - "--inputs=$_rebased_jar_path", - ] + args += [ "--inputs=$_rebased_jar_path" ] } } - final_deps += [":${_template_name}__final_dex"] + final_deps += [ ":${_template_name}__final_dex" ] dex("${_template_name}__final_dex") { - deps = [ ":${_template_name}__java" ] - sources = [ jar_path ] - inputs = [ _build_config ] + deps = [ + ":${_template_name}__java", + ] + sources = [ + jar_path, + ] + inputs = [ + _build_config, + ] output = final_dex_path - dex_arg_key = "${_rebased_build_config}:apk_dex:dependency_dex_files" + dex_arg_key = "${_rebased_build_config}:final_dex:dependency_dex_files" args = [ "--inputs=@FileArg($dex_arg_key)" ] } @@ -1152,11 +1312,9 @@ script = "//build/android/gyp/pack_arm_relocations.py" packed_libraries_dir = "$_native_libs_dir/$android_app_abi" depfile = "$target_gen_dir/$target_name.d" - outputs = [ - depfile - ] + outputs = [ depfile ] inputs = [ - _build_config + _build_config, ] deps = [] skip_packing_list = [ @@ -1167,35 +1325,36 @@ enable_packing_arg = 0 if (_enable_relocation_packing) { enable_packing_arg = 1 - deps += [ - relocation_packer_target - ] + deps += [ relocation_packer_target ] } args = [ - "--depfile", rebase_path(depfile, root_build_dir), + "--depfile", + rebase_path(depfile, root_build_dir), "--enable-packing=$enable_packing_arg", "--has-relocations-with-addends=$relocations_have_addends", "--exclude-packing-list=$skip_packing_list", - "--android-pack-relocations", rebase_path(relocation_packer_exe, root_build_dir), - "--android-objcopy", rebase_path(android_objcopy, root_build_dir), - "--stripped-libraries-dir", rebase_path(root_build_dir, root_build_dir), - "--packed-libraries-dir", rebase_path(packed_libraries_dir, root_build_dir), + "--android-pack-relocations", + rebase_path(relocation_packer_exe, root_build_dir), + "--android-objcopy", + rebase_path(android_objcopy, root_build_dir), + "--stripped-libraries-dir", + rebase_path(root_build_dir, root_build_dir), + "--packed-libraries-dir", + rebase_path(packed_libraries_dir, root_build_dir), "--libraries=@FileArg(${_rebased_build_config}:native:libraries)", - "--clear-dir" + "--clear-dir", ] if (is_debug) { rebased_gdbserver = rebase_path([ android_gdbserver ], root_build_dir) inputs += [ android_gdbserver ] - args += [ - "--libraries=$rebased_gdbserver" - ] + args += [ "--libraries=$rebased_gdbserver" ] } } } - final_deps += [":${_template_name}__create"] + final_deps += [ ":${_template_name}__create" ] create_apk("${_template_name}__create") { apk_path = _final_apk_path android_manifest = invoker.android_manifest @@ -1220,6 +1379,7 @@ deps = [] if (defined(invoker.asset_location)) { asset_location = invoker.asset_location + # We don't know the exact dependencies that create the assets in # |asset_location|; we depend on all caller deps until a better solution # is figured out (http://crbug.com/433330). @@ -1230,7 +1390,7 @@ if (_native_libs != []) { native_libs_dir = _native_libs_dir - deps += [":${_template_name}__prepare_native"] + deps += [ ":${_template_name}__prepare_native" ] } } @@ -1243,7 +1403,6 @@ } } - # Declare an Android gtest apk # # This target creates an Android apk for running gtest-based unittests. @@ -1281,12 +1440,13 @@ android_apk(target_name) { _apk_name = test_suite_name final_apk_path = "$root_build_dir/${_apk_name}_apk/${_apk_name}-debug.apk" - java_files = [ - "//testing/android/java/src/org/chromium/native_test/ChromeNativeTestActivity.java" - ] + java_files = + [ "//testing/android/java/src/org/chromium/native_test/ChromeNativeTestActivity.java" ] android_manifest = "//testing/android/java/AndroidManifest.xml" native_libs = [ unittests_binary ] - deps = [ "//base:base_java" ] + deps = [ + "//base:base_java", + ] if (defined(invoker.deps)) { deps += invoker.deps } @@ -1317,7 +1477,9 @@ # ] # } template("android_aidl") { - if (defined(invoker.testonly)) { testonly = invoker.testonly } + if (defined(invoker.testonly)) { + testonly = invoker.testonly + } srcjar_path = "${target_gen_dir}/${target_name}.srcjar" aidl_path = "${android_sdk_build_tools}/aidl" @@ -1333,35 +1495,35 @@ imports += [ invoker.interface_file ] } - inputs = [ - aidl_path, - ] + imports + inputs = [ aidl_path ] + imports depfile = "${target_gen_dir}/${target_name}.d" outputs = [ depfile, - srcjar_path + srcjar_path, ] rebased_imports = rebase_path(imports, root_build_dir) args = [ - "--depfile", rebase_path(depfile, root_build_dir), - "--aidl-path", rebase_path(aidl_path, root_build_dir), + "--depfile", + rebase_path(depfile, root_build_dir), + "--aidl-path", + rebase_path(aidl_path, root_build_dir), "--imports=$rebased_imports", - "--srcjar", rebase_path(srcjar_path, root_build_dir), + "--srcjar", + rebase_path(srcjar_path, root_build_dir), ] if (defined(invoker.import_include) && invoker.import_include != "") { # TODO(cjhopman): aidl supports creating a depfile. We should be able to # switch to constructing a depfile for the overall action from that # instead of having all the .java files in the include paths as inputs. - rebased_import_includes = rebase_path( - [invoker.import_include], root_build_dir) + rebased_import_includes = + rebase_path([ invoker.import_include ], root_build_dir) args += [ "--includes=$rebased_import_includes" ] - _java_files_build_rel = exec_script( - "//build/android/gyp/find.py", - rebase_path([invoker.import_include], root_build_dir), - "list lines" - ) + _java_files_build_rel = + exec_script("//build/android/gyp/find.py", + rebase_path([ invoker.import_include ], root_build_dir), + "list lines") _java_files = rebase_path(_java_files_build_rel, ".", root_build_dir) inputs += _java_files } @@ -1390,14 +1552,17 @@ # binary = "$root_build_dir/exe.stripped/foo" # } template("create_native_executable_dist") { - if (defined(invoker.testonly)) { testonly = invoker.testonly } + if (defined(invoker.testonly)) { + testonly = invoker.testonly + } dist_dir = invoker.dist_dir binary = invoker.binary final_deps = [] template_name = target_name - libraries_list = "${target_gen_dir}/${template_name}_library_dependencies.list" + libraries_list = + "${target_gen_dir}/${template_name}_library_dependencies.list" # TODO(gyp) #'dependencies': [ @@ -1419,11 +1584,15 @@ ] rebased_binaries = rebase_path([ binary ], root_build_dir) args = [ - "--depfile", rebase_path(depfile, root_build_dir), + "--depfile", + rebase_path(depfile, root_build_dir), "--input-libraries=$rebased_binaries", - "--libraries-dir", rebase_path(stripped_libraries_dir, root_build_dir), - "--output", rebase_path(libraries_list, root_build_dir), - "--readelf", rebase_path(android_readelf, root_build_dir), + "--libraries-dir", + rebase_path(stripped_libraries_dir, root_build_dir), + "--output", + rebase_path(libraries_list, root_build_dir), + "--readelf", + rebase_path(android_readelf, root_build_dir), ] } @@ -1432,7 +1601,7 @@ clear_dir = true inputs = [ binary, - libraries_list + libraries_list, ] dest = dist_dir rebased_binaries_list = rebase_path([ binary ], root_build_dir) @@ -1448,7 +1617,6 @@ } } - # Compile a protocol buffer to java. # # This generates java files from protocol buffers and creates an Android library @@ -1475,7 +1643,7 @@ srcjar_path = "$target_gen_dir/$target_name.srcjar" script = "//build/protoc_java.py" deps = [ - _protoc_dep + _protoc_dep, ] sources = invoker.sources depfile = "$target_gen_dir/$target_name.d" @@ -1484,11 +1652,15 @@ srcjar_path, ] args = [ - "--depfile", rebase_path(depfile, root_build_dir), - "--protoc", rebase_path(_protoc_bin, root_build_dir), - "--proto-path", rebase_path(_proto_path, root_build_dir), - "--srcjar", rebase_path(srcjar_path, root_build_dir), - ] + rebase_path(sources, root_build_dir) + "--depfile", + rebase_path(depfile, root_build_dir), + "--protoc", + rebase_path(_protoc_bin, root_build_dir), + "--proto-path", + rebase_path(_proto_path, root_build_dir), + "--srcjar", + rebase_path(srcjar_path, root_build_dir), + ] + rebase_path(sources, root_build_dir) } android_library(target_name) { @@ -1502,7 +1674,9 @@ # TODO(GYP): implement this. template("uiautomator_test") { - if (defined(invoker.testonly)) { testonly = invoker.testonly } + if (defined(invoker.testonly)) { + testonly = invoker.testonly + } assert(target_name != "") assert(invoker.deps != [] || true) group(target_name) {
diff --git a/build/config/arm.gni b/build/config/arm.gni index 59de6687..d942c3b 100644 --- a/build/config/arm.gni +++ b/build/config/arm.gni
@@ -22,10 +22,8 @@ arm_use_neon = true } - assert(arm_float_abi == "" || - arm_float_abi == "hard" || - arm_float_abi == "soft" || - arm_float_abi == "softfp") + assert(arm_float_abi == "" || arm_float_abi == "hard" || + arm_float_abi == "soft" || arm_float_abi == "softfp") if (is_android) { arm_use_neon = false @@ -41,10 +39,10 @@ arm_float_abi = "softfp" } arm_fpu = "vfp" + # Thumb is a reduced instruction set available on some ARM processors that # has increased code density. arm_use_thumb = false - } else if (arm_version == 7) { arm_arch = "armv7-a" if (arm_tune == "") {
diff --git a/build/config/clang/BUILD.gn b/build/config/clang/BUILD.gn index 00fb9e0..39fe251 100644 --- a/build/config/clang/BUILD.gn +++ b/build/config/clang/BUILD.gn
@@ -7,23 +7,26 @@ config("find_bad_constructs") { if (clang_use_chrome_plugins) { cflags = [ - "-Xclang", "-load", + "-Xclang", + "-load", "-Xclang", ] if (is_mac || is_ios) { cflags += [ rebase_path( - "//third_party/llvm-build/Release+Asserts/lib/libFindBadConstructs.dylib", - root_build_dir) ] + "//third_party/llvm-build/Release+Asserts/lib/libFindBadConstructs.dylib", + root_build_dir) ] } else if (is_linux) { cflags += [ rebase_path( - "//third_party/llvm-build/Release+Asserts/lib/libFindBadConstructs.so", - root_build_dir) ] + "//third_party/llvm-build/Release+Asserts/lib/libFindBadConstructs.so", + root_build_dir) ] } cflags += [ - "-Xclang", "-add-plugin", - "-Xclang", "find-bad-constructs", + "-Xclang", + "-add-plugin", + "-Xclang", + "find-bad-constructs", ] } }
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn index af54dbb..45e186c1 100644 --- a/build/config/compiler/BUILD.gn +++ b/build/config/compiler/BUILD.gn
@@ -90,19 +90,16 @@ "/FS", # Preserve previous PDB behavior. ] if (is_component_build) { - cflags += [ - "/EHsc", # Assume C functions can't throw exceptions and don't catch - # structured exceptions (only C++ ones). - ] + cflags += [ "/EHsc" ] # Assume C functions can't throw exceptions and don't catch + # structured exceptions (only C++ ones). } } else { # Common GCC compiler flags setup. # -------------------------------- - cflags += [ - "-fno-strict-aliasing", # See http://crbug.com/32204 - ] + cflags += [ "-fno-strict-aliasing" ] # See http://crbug.com/32204 cflags_cc += [ "-fno-threadsafe-statics", + # Not exporting C++ inline functions can generally be applied anywhere # so we do so here. Normal function visibility is controlled by # //build/config/gcc:symbol_visibility_hidden. @@ -113,7 +110,10 @@ if (is_mac) { cflags += [ "-fstack-protector-all" ] } else if (is_linux) { - cflags += [ "-fstack-protector", "--param=ssp-buffer-size=4" ] + cflags += [ + "-fstack-protector", + "--param=ssp-buffer-size=4", + ] } # Linker warnings. @@ -155,11 +155,10 @@ # when turning clang on or off. (defines are passed via the command line, # and build system rebuild things when their commandline changes). Nothing # should ever read this define. - defines += [ - "CR_CLANG_REVISION=" + - exec_script( - "//tools/clang/scripts/posix-print-revision.py", [], "value") - ] + defines += [ "CR_CLANG_REVISION=" + + exec_script("//tools/clang/scripts/posix-print-revision.py", + [], + "value") ] } # Mac-specific compiler flags setup. @@ -170,16 +169,22 @@ # CPU architecture. if (cpu_arch == "x64") { - common_mac_flags += [ "-arch", "x86_64" ] + common_mac_flags += [ + "-arch", + "x86_64", + ] } else if (cpu_arch == "x86") { - common_mac_flags += [ "-arch", "i386" ] + common_mac_flags += [ + "-arch", + "i386", + ] } cflags += common_mac_flags # Without this, the constructors and destructors of a C++ object inside # an Objective C struct won't be called, which is very bad. - cflags_objcc = [ "-fobjc-call-cxx-cdtors", ] + cflags_objcc = [ "-fobjc-call-cxx-cdtors" ] cflags_c += [ "-std=c99" ] cflags_cc += [ "-std=gnu++11" ] @@ -189,9 +194,7 @@ # Non-Mac Posix compiler flags setup. # ----------------------------------- if (gcc_version >= 48) { - cflags_cc += [ - "-std=gnu++11", - ] + cflags_cc += [ "-std=gnu++11" ] } if (enable_profiling && !is_debug) { @@ -216,7 +219,10 @@ # CPU architecture. We may or may not be doing a cross compile now, so for # simplicity we always explicitly set the architecture. if (cpu_arch == "x64") { - cflags += [ "-m64", "-march=x86-64", ] + cflags += [ + "-m64", + "-march=x86-64", + ] ldflags += [ "-m64" ] } else if (cpu_arch == "x86") { cflags += [ "-m32" ] @@ -226,6 +232,7 @@ # Else building libyuv gives clang's register allocator issues, # see llvm.org/PR15798 / crbug.com/233709 "-momit-leaf-frame-pointer", + # Align the stack on 16-byte boundaries, http://crbug.com/418554. "-mstack-alignment=16", "-mstackrealign", @@ -257,6 +264,7 @@ # compiler (r5-r7). This can be verified using # webkit_unit_tests' WTF.Checked_int8_t test. "-fno-tree-sra", + # The following option is disabled to improve binary # size and performance in gcc 4.9. "-fno-caller-saves", @@ -299,9 +307,7 @@ # ------------------------------------ if (is_linux) { cflags += [ "-pthread" ] - ldflags += [ - "-pthread", - ] + ldflags += [ "-pthread" ] } if (use_gold) { # Use gold for linking on 64-bit Linux only (on 32-bit it runs out of @@ -340,12 +346,8 @@ # Clang-specific compiler flags setup. # ------------------------------------ if (is_clang) { - cflags += [ - "-fcolor-diagnostics", - ] - cflags_cc += [ - "-std=gnu++11", - ] + cflags += [ "-fcolor-diagnostics" ] + cflags_cc += [ "-std=gnu++11" ] } # Android-specific flags setup. @@ -358,9 +360,7 @@ ] if (!is_clang) { # Clang doesn't support these flags. - cflags += [ - "-finline-limit=64", - ] + cflags += [ "-finline-limit=64" ] } if (is_android_webview_build) { # Android predefines this as 1; undefine it here so Chromium can redefine @@ -391,13 +391,14 @@ ldflags += [ "-fuse-ld=gold" ] if (is_clang) { # Let clang find the ld.gold in the NDK. - ldflags += [ "--gcc-toolchain=" + rebase_path(android_toolchain_root, - root_build_dir) ] + ldflags += [ "--gcc-toolchain=" + + rebase_path(android_toolchain_root, root_build_dir) ] } } ldflags += [ "-Wl,--no-undefined", + # Don't export symbols from statically linked libraries. "-Wl,--exclude-libs=ALL", ] @@ -410,9 +411,7 @@ if (is_clang) { if (cpu_arch == "arm") { - cflags += [ - "-target arm-linux-androideabi", - ] + cflags += [ "-target arm-linux-androideabi" ] ldflags += [ "-target arm-linux-androideabi" ] } else if (cpu_arch == "x86") { cflags += [ "-target x86-linux-androideabi" ] @@ -424,9 +423,7 @@ config("compiler_arm_fpu") { if (cpu_arch == "arm" && !is_android_webview_build) { - cflags = [ - "-mfpu=$arm_fpu", - ] + cflags = [ "-mfpu=$arm_fpu" ] } } @@ -513,11 +510,9 @@ # caution. android_stlport_root = "$android_ndk_root/sources/cxx-stl/stlport" - cflags += [ - "-isystem" + rebase_path("$android_stlport_root/stlport", - root_build_dir) - ] - if (arm_use_thumb) { + cflags += [ "-isystem" + + rebase_path("$android_stlport_root/stlport", root_build_dir) ] + if (cpu_arch == "arm" && arm_use_thumb) { lib_dirs += [ "$android_stlport_root/libs/$android_app_abi/thumb" ] } else { lib_dirs += [ "$android_stlport_root/libs/$android_app_abi" ] @@ -550,7 +545,6 @@ "dl", "m", ] - } } @@ -561,9 +555,7 @@ config("chromium_code") { if (is_win) { - cflags = [ - "/W4", # Warning level 4. - ] + cflags = [ "/W4" ] # Warning level 4. } else { cflags = [ "-Wall", @@ -661,8 +653,7 @@ config("default_warnings") { if (is_win) { cflags = [ - "/WX", # Treat warnings as errors. - + "/WX", # Treat warnings as errors. # Warnings permanently disabled: # TODO(GYP) The GYP build doesn't have this globally enabled but disabled @@ -717,8 +708,6 @@ # have to turn off this warning (and be careful about how object # destruction happens in such cases). "/wd4611", - - # Warnings to evaluate and possibly fix/reenable later: "/wd4100", # Unreferenced formal function parameter. @@ -745,9 +734,7 @@ cflags_cc = [] if (is_mac) { - cflags += [ - "-Wnewline-eof", - ] + cflags += [ "-Wnewline-eof" ] } if (is_clang) { @@ -785,6 +772,7 @@ cflags_cc += [ # See comment for -Wno-c++11-narrowing. "-Wno-narrowing", + # TODO(thakis): Remove, http://crbug.com/263960 "-Wno-literal-suffix", ] @@ -811,6 +799,7 @@ # correctly when building with the Android build system. # TODO(torne): Fix this in WebKit. "-Wno-error=c++0x-compat", + # Other things unrelated to -Wextra: "-Wno-non-virtual-dtor", "-Wno-sign-promo", @@ -821,9 +810,7 @@ # Don't warn about the "typedef 'foo' locally defined but not used" # for gcc 4.8. # TODO: remove this flag once all builds work. See crbug.com/227506 - cflags += [ - "-Wno-unused-local-typedefs", - ] + cflags += [ "-Wno-unused-local-typedefs" ] } } } @@ -854,7 +841,7 @@ "/O2", "/Ob2", # both explicit and auto inlining. "/Oy-", # disable omitting frame pointers, must be after /o2. - "/Os", # favor size over speed. + "/Os", # favor size over speed. ] common_optimize_on_ldflags = [] } else { @@ -862,6 +849,7 @@ # Don't emit the GCC version ident directives, they just end up in the # .comment section taking up binary size. "-fno-ident", + # Put data and code in their own sections, so that unused symbols # can be removed at link time with --gc-sections. "-fdata-sections", @@ -882,9 +870,7 @@ if (is_mac) { if (symbol_level == 2) { # Mac dead code stripping requires symbols. - common_optimize_on_ldflags += [ - "-Wl,-dead_strip", - ] + common_optimize_on_ldflags += [ "-Wl,-dead_strip" ] } } else { # Non-Mac Posix linker flags. @@ -903,17 +889,11 @@ cflags = common_optimize_on_cflags ldflags = common_optimize_on_ldflags if (is_win) { - cflags += [ - "/Os", # favor size over speed. - ] + cflags += [ "/Os" ] # favor size over speed. } else if (is_android || is_ios) { - cflags += [ - "-Os", # Favor size over speed. - ] + cflags += [ "-Os" ] # Favor size over speed. } else { - cflags += [ - "-O2", - ] + cflags += [ "-O2" ] } } @@ -949,32 +929,25 @@ cflags = common_optimize_on_cflags ldflags = common_optimize_on_ldflags if (is_win) { - cflags -= [ - "/Os", - ] - cflags += [ - "/Ot", # Favor speed over size. - ] + cflags -= [ "/Os" ] + cflags += [ "/Ot" ] # Favor speed over size. if (is_official_build) { # TODO(GYP): TODO(dpranke): Should these only be on in an official # build, or on all the time? For now we'll require official build so # that the compile is clean. cflags += [ - "/GL", # Whole program optimization. + "/GL", # Whole program optimization. + # Disable Warning 4702 ("Unreachable code") for the WPO/PGO builds. # Probably anything that this would catch that wouldn't be caught in a # normal build isn't going to actually be a bug, so the incremental # value of C4702 for PGO builds is likely very small. "/wd4702", ] - ldflags += [ - "/LTCG", - ] + ldflags += [ "/LTCG" ] } } else { - cflags += [ - "-O2", - ] + cflags += [ "-O2" ] } } @@ -982,7 +955,12 @@ config("symbols") { if (is_win) { - cflags = [ "/Zi" ] # Produce PDB file, no edit and continue. + import("//build/toolchain/goma.gni") + if (use_goma) { + cflags = [ "/Z7" ] # No PDB file + } else { + cflags = [ "/Zi" ] # Produce PDB file, no edit and continue. + } ldflags = [ "/DEBUG" ] } else { cflags = [ "-g2" ]
diff --git a/build/config/features.gni b/build/config/features.gni index 9953a0d..ac48896 100644 --- a/build/config/features.gni +++ b/build/config/features.gni
@@ -75,7 +75,7 @@ # Do not disable seccomp_bpf anywhere without talking to # security@chromium.org! use_seccomp_bpf = (is_linux || is_android) && - (cpu_arch == "x86" || cpu_arch == "x64" || cpu_arch == "arm") + (cpu_arch == "x86" || cpu_arch == "x64" || cpu_arch == "arm") # Enable notifications everywhere except iOS. enable_notifications = !is_ios @@ -83,18 +83,20 @@ # TODO(brettw) this should be moved to net and only dependents get this define. disable_ftp_support = is_ios -enable_web_speech = (!is_android && !is_ios) +enable_web_speech = !is_android && !is_ios use_dbus = is_linux -enable_extensions = (!is_android && !is_ios) +enable_extensions = !is_android && !is_ios # Variable safe_browsing is used to control the build time configuration for # safe browsing feature. Safe browsing can be compiled in 3 different levels: 0 # disables it, 1 enables it fully, and 2 enables only UI and reporting features # without enabling phishing and malware detection. This is useful to integrate # a third party phishing/malware detection to existing safe browsing logic. -if (is_ios) { +if (is_android) { + safe_browsing_mode = 2 +} else if (is_ios) { safe_browsing_mode = 0 } else { safe_browsing_mode = 1 @@ -129,7 +131,7 @@ enable_app_list = !is_ios && !is_android enable_settings_app = enable_app_list && !is_chromeos -enable_managed_users = !is_ios +enable_supervised_users = !is_ios enable_service_discovery = enable_mdns || is_mac @@ -157,3 +159,8 @@ # system). # TODO(GYP) also require !embedded to enable. use_gconf = is_linux && !is_chromeos + +# Hangout services is an extension that adds extra features to Hangouts. +# For official GYP builds, this flag is set, it will likely need to be +# parameterized in the future for a similar use. +enable_hangout_services_extension = false
diff --git a/build/config/gcc/BUILD.gn b/build/config/gcc/BUILD.gn index 28502c2e..c6cfe72 100644 --- a/build/config/gcc/BUILD.gn +++ b/build/config/gcc/BUILD.gn
@@ -23,7 +23,6 @@ ldflags = [ # Want to pass "\$". GN will re-escape as required for ninja. "-Wl,-rpath=\$ORIGIN/", - "-Wl,-rpath-link=", # Newer binutils don't set DT_RPATH unless you disable "new" dtags
diff --git a/build/config/gcc/gcc_version.gni b/build/config/gcc/gcc_version.gni index 1ff464a..2ecc54a 100644 --- a/build/config/gcc/gcc_version.gni +++ b/build/config/gcc/gcc_version.gni
@@ -11,11 +11,21 @@ } } else if (current_toolchain == "//build/toolchain/cros:target") { # TODO(benchan): Generalize the check for platforms other than Chrome OS. - gcc_version = exec_script("../../compiler_version.py", [ "target", "compiler" ], "value") + gcc_version = exec_script("../../compiler_version.py", + [ + "target", + "compiler", + ], + "value") } else if (current_toolchain == "//build/toolchain/linux:x64" || current_toolchain == "//build/toolchain/linux:x86") { # These are both the same and just use the default gcc on the system. - gcc_version = exec_script("../../compiler_version.py", [ "host", "compiler" ], "value") + gcc_version = exec_script("../../compiler_version.py", + [ + "host", + "compiler", + ], + "value") } else { gcc_version = 0 }
diff --git a/build/config/ios/BUILD.gn b/build/config/ios/BUILD.gn index 0886be4..471f28a 100644 --- a/build/config/ios/BUILD.gn +++ b/build/config/ios/BUILD.gn
@@ -6,7 +6,10 @@ import("//build/config/ios/ios_sdk.gni") config("sdk") { - common_flags = [ "-isysroot", sysroot ] + common_flags = [ + "-isysroot", + sysroot, + ] cflags = common_flags ldflags = common_flags
diff --git a/build/config/ios/ios_sdk.gni b/build/config/ios/ios_sdk.gni index 6b81a03..cb2708b 100644 --- a/build/config/ios/ios_sdk.gni +++ b/build/config/ios/ios_sdk.gni
@@ -25,6 +25,6 @@ _ios_sdk_to_query = "iphoneos" } _ios_sdk_result = - exec_script("ios_sdk.py", [ _ios_sdk_to_query ], "list lines") + exec_script("ios_sdk.py", [ _ios_sdk_to_query ], "list lines") ios_sdk_path = _ios_sdk_result[0] }
diff --git a/build/config/linux/BUILD.gn b/build/config/linux/BUILD.gn index dec10177..e132116 100644 --- a/build/config/linux/BUILD.gn +++ b/build/config/linux/BUILD.gn
@@ -8,11 +8,10 @@ import("//build/config/ui.gni") import("//tools/generate_library_loader/generate_library_loader.gni") -gypi_values = exec_script( - "//build/gypi_to_gn.py", - [ rebase_path("../../linux/system.gyp") ], - "scope", - [ "../../linux/system.gyp" ]) +gypi_values = exec_script("//build/gypi_to_gn.py", + [ rebase_path("../../linux/system.gyp") ], + "scope", + [ "../../linux/system.gyp" ]) config("sdk") { if (sysroot != "") { @@ -21,9 +20,12 @@ # Need to get some linker flags out of the sysroot. ldflags += [ exec_script("sysroot_ld_path.py", - [ rebase_path("//build/linux/sysroot_ld_path.sh", root_build_dir), - sysroot ], - "value") ] + [ + rebase_path("//build/linux/sysroot_ld_path.sh", + root_build_dir), + sysroot, + ], + "value") ] } # Set here because OS_CHROMEOS cannot be autodetected in build_config.h like @@ -42,7 +44,12 @@ } pkg_config("glib") { - packages = [ "glib-2.0", "gmodule-2.0", "gobject-2.0", "gthread-2.0" ] + packages = [ + "glib-2.0", + "gmodule-2.0", + "gobject-2.0", + "gthread-2.0", + ] } pkg_config("pangocairo") { @@ -148,6 +155,7 @@ pkg_config("gio_config") { packages = [ "gio-2.0" ] + # glib >=2.40 deprecate g_settings_list_schemas in favor of # g_settings_schema_source_list_schemas. This function is not available on # earlier versions that we still need to support (specifically, 2.32), so @@ -155,7 +163,10 @@ # TODO(mgiuca): Remove this suppression when we drop support for Ubuntu 13.10 # (saucy) and earlier. Update the code to use # g_settings_schema_source_list_schemas instead. - defines = [ "USE_GIO", "GLIB_DISABLE_DEPRECATION_WARNINGS" ] + defines = [ + "USE_GIO", + "GLIB_DISABLE_DEPRECATION_WARNINGS", + ] # TODO(brettw) Theoretically I think ignore_libs should be set so that we # don't link directly to GIO and use the loader generated below. But the gio
diff --git a/build/config/linux/pkg_config.gni b/build/config/linux/pkg_config.gni index 687afc5..631d60aa 100644 --- a/build/config/linux/pkg_config.gni +++ b/build/config/linux/pkg_config.gni
@@ -39,16 +39,24 @@ # need to invoke it manually. if (sysroot != "") { # Pass the sysroot if we're using one (it requires the CPU arch also). - pkg_config_args = ["-s", sysroot, "-a", cpu_arch] + pkg_config_args = [ + "-s", + sysroot, + "-a", + cpu_arch, + ] } else if (pkg_config != "") { - pkg_config_args = ["-p", pkg_config] + pkg_config_args = [ + "-p", + pkg_config, + ] } else { pkg_config_args = [] } template("pkg_config") { assert(defined(invoker.packages), - "Variable |packages| must be defined to be a list in pkg_config.") + "Variable |packages| must be defined to be a list in pkg_config.") config(target_name) { args = pkg_config_args + invoker.packages if (defined(invoker.extra_args)) {
diff --git a/build/config/mac/BUILD.gn b/build/config/mac/BUILD.gn index 2ebf458..9288add 100644 --- a/build/config/mac/BUILD.gn +++ b/build/config/mac/BUILD.gn
@@ -6,8 +6,9 @@ config("sdk") { common_flags = [ - "-isysroot", sysroot, - "-mmacosx-version-min=10.6" + "-isysroot", + sysroot, + "-mmacosx-version-min=10.6", ] cflags = common_flags @@ -19,8 +20,10 @@ ldflags = [ "-Wl,-search_paths_first", "-L.", + # Path for loading shared libraries for unbundled binaries. "-Wl,-rpath,@loader_path/.", + # Path for loading shared libraries for bundled binaries. Get back from # Binary.app/Contents/MacOS. "-Wl,-rpath,@loader_path/../../..", @@ -29,7 +32,5 @@ # On Mac, this is used only for executables. config("mac_executable_flags") { - ldflags = [ - "-Wl,-pie", # Position independent. - ] + ldflags = [ "-Wl,-pie" ] # Position independent. }
diff --git a/build/config/mac/mac_sdk.gni b/build/config/mac/mac_sdk.gni index aa03332..44995a3 100644 --- a/build/config/mac/mac_sdk.gni +++ b/build/config/mac/mac_sdk.gni
@@ -14,10 +14,15 @@ find_sdk_args = [ "--print_sdk_path" ] if (is_chrome_branded && is_official_build) { - find_sdk_args += [ "--verify", mac_sdk_min, "--sdk_path=" + mac_sdk_path ] + find_sdk_args += [ + "--verify", + mac_sdk_min, + "--sdk_path=" + mac_sdk_path, + ] } else { find_sdk_args += [ mac_sdk_min ] } + # The tool will print the SDK path on the first line, and the version on the # second line. find_sdk_lines =
diff --git a/build/config/sanitizers/BUILD.gn b/build/config/sanitizers/BUILD.gn index 6012b48..63728d94 100644 --- a/build/config/sanitizers/BUILD.gn +++ b/build/config/sanitizers/BUILD.gn
@@ -8,17 +8,24 @@ group("deps") { if (is_asan) { public_configs = [ ":sanitizer_options_link_helper" ] - deps = [ ":options_sources" ] + deps = [ + ":options_sources", + ] } } config("sanitizer_options_link_helper") { - ldflags = [ "-Wl,-u_sanitizer_options_link_helper", "-fsanitize=address" ] + ldflags = [ + "-Wl,-u_sanitizer_options_link_helper", + "-fsanitize=address", + ] } source_set("options_sources") { visibility = [ ":deps" ] - sources = [ "//build/sanitizers/sanitizer_options.cc" ] + sources = [ + "//build/sanitizers/sanitizer_options.cc", + ] if (is_tsan) { sources += [ "//build/sanitizers/tsan_suppressions.cc" ]
diff --git a/build/config/win/BUILD.gn b/build/config/win/BUILD.gn index f6230648..bc2ea88 100644 --- a/build/config/win/BUILD.gn +++ b/build/config/win/BUILD.gn
@@ -122,9 +122,7 @@ # to have a separate config for it. Remove this config from your target to # get the "bloaty and accomodating" version of windows.h. config("lean_and_mean") { - defines = [ - "WIN32_LEAN_AND_MEAN", - ] + defines = [ "WIN32_LEAN_AND_MEAN" ] } # Nominmax -------------------------------------------------------------------- @@ -134,7 +132,5 @@ # For such targets, this config can be removed. config("nominmax") { - defines = [ - "NOMINMAX", - ] + defines = [ "NOMINMAX" ] }
diff --git a/build/go/rules.gni b/build/go/rules.gni index 55dd386..d4b1f50c 100644 --- a/build/go/rules.gni +++ b/build/go/rules.gni
@@ -40,23 +40,24 @@ ] script = "//build/go/go.py" outputs = [ "${target_out_dir}/${target_name}" ] + # Since go test does not permit specifying an output directory or output # binary name, we create a temporary build directory, and the python # script will later identify the output, copy it to the target location, # and clean up the temporary build directory. build_dir = "${target_out_dir}/${target_name}_build" args = [ - "--", - "${go_build_tool}", - rebase_path(build_dir, root_build_dir), - rebase_path(target_out_dir, root_build_dir) + "/${target_name}", - rebase_path("//", root_build_dir), - "-I" + rebase_path("//"), - " -L" + rebase_path(target_out_dir) + - " -l" + static_library_name + - " -lstdc++ -lpthread -lm -lglib-2.0", - "test", "-c", - ] + rebase_path(invoker.sources, build_dir) + "--", + "${go_build_tool}", + rebase_path(build_dir, root_build_dir), + rebase_path(target_out_dir, root_build_dir) + "/${target_name}", + rebase_path("//", root_build_dir), + "-I" + rebase_path("//"), + " -L" + rebase_path(target_out_dir) + " -l" + static_library_name + + " -lstdc++ -lpthread -lm -lglib-2.0", + "test", + "-c", + ] + rebase_path(invoker.sources, build_dir) } } @@ -74,24 +75,27 @@ } action(target_name) { - deps = [ ":$static_library_name" ] + deps = [ + ":$static_library_name", + ] script = "//build/go/go.py" outputs = [ "${target_out_dir}/${target_name}" ] + # Since go test does not permit specifying an output directory or output # binary name, we create a temporary build directory, and the python # script will later identify the output, copy it to the target location, # and clean up the temporary build directory. build_dir = "${target_out_dir}/${target_name}_build" args = [ - "--", - "CGO_ENABLED=1 GOOS=android GOARCH=arm GOARM=7 ${go_build_tool}", - rebase_path(build_dir, root_build_dir), - rebase_path(target_out_dir, root_build_dir) + "/${target_name}", - rebase_path("//", root_build_dir), - "-I" + rebase_path("//"), - " -L" + rebase_path(target_out_dir) + - " -l" + static_library_name + "", - "build -ldflags=-shared", - ] + rebase_path(invoker.sources, build_dir) + "--", + "CGO_ENABLED=1 GOOS=android GOARCH=arm GOARM=7 ${go_build_tool}", + rebase_path(build_dir, root_build_dir), + rebase_path(target_out_dir, root_build_dir) + "/${target_name}", + rebase_path("//", root_build_dir), + "-I" + rebase_path("//"), + " -L" + rebase_path(target_out_dir) + " -l" + static_library_name + + "", + "build -ldflags=-shared", + ] + rebase_path(invoker.sources, build_dir) } -} \ No newline at end of file +}
diff --git a/build/install-build-deps.sh b/build/install-build-deps.sh index a9ec4ec..d1d844a 100755 --- a/build/install-build-deps.sh +++ b/build/install-build-deps.sh
@@ -73,10 +73,10 @@ fi lsb_release=$(lsb_release --codename --short) -ubuntu_codenames="(precise|quantal|raring|saucy|trusty)" +ubuntu_codenames="(precise|quantal|raring|saucy|trusty|utopic)" if [ 0 -eq "${do_unsupported-0}" ] && [ 0 -eq "${do_quick_check-0}" ] ; then if [[ ! $lsb_release =~ $ubuntu_codenames ]]; then - echo "ERROR: Only Ubuntu 12.04 (precise) through 14.04 (trusty) are"\ + echo "ERROR: Only Ubuntu 12.04 (precise) through 14.10 (utopic) are"\ "currently supported" >&2 exit 1 fi
diff --git a/build/java_prebuilt.gypi b/build/java_prebuilt.gypi index a3a8cc0c..8efc4ef 100644 --- a/build/java_prebuilt.gypi +++ b/build/java_prebuilt.gypi
@@ -27,6 +27,7 @@ 'intermediate_dir': '<(SHARED_INTERMEDIATE_DIR)/<(_target_name)', 'android_jar': '<(android_sdk)/android.jar', 'input_jars_paths': [ '<(android_jar)' ], + 'neverlink%': 0, 'proguard_config%': '', 'proguard_preprocess%': '0', 'variables': { @@ -46,7 +47,13 @@ 'all_dependent_settings': { 'variables': { 'input_jars_paths': ['<(dex_input_jar_path)'], - 'library_dexed_jars_paths': ['<(dex_path)'], + 'conditions': [ + ['neverlink == 1', { + 'library_dexed_jars_paths': [], + }, { + 'library_dexed_jars_paths': ['<(dex_path)'], + }], + ], }, }, 'conditions' : [ @@ -76,18 +83,20 @@ }, ], }], - ], - 'actions': [ - { - 'action_name': 'dex_<(_target_name)', - 'message': 'Dexing <(_target_name) jar', - 'variables': { - 'dex_input_paths': [ - '<(dex_input_jar_path)', - ], - 'output_path': '<(dex_path)', - }, - 'includes': [ 'android/dex_action.gypi' ], - }, + ['neverlink == 0', { + 'actions': [ + { + 'action_name': 'dex_<(_target_name)', + 'message': 'Dexing <(_target_name) jar', + 'variables': { + 'dex_input_paths': [ + '<(dex_input_jar_path)', + ], + 'output_path': '<(dex_path)', + }, + 'includes': [ 'android/dex_action.gypi' ], + }, + ], + }], ], }
diff --git a/build/json_schema_api.gni b/build/json_schema_api.gni index 5857739..dd8ab92 100644 --- a/build/json_schema_api.gni +++ b/build/json_schema_api.gni
@@ -57,8 +57,8 @@ schemas = defined(invoker.schemas) && invoker.schemas bundle = defined(invoker.bundle) && invoker.bundle - bundle_registration = defined(invoker.bundle_registration) && - invoker.bundle_registration + bundle_registration = + defined(invoker.bundle_registration) && invoker.bundle_registration schema_include_rules = "" if (defined(invoker.schema_include_rules)) { @@ -108,11 +108,15 @@ "--destdir=" + rebase_path(root_gen_dir, root_build_dir), "--namespace=$root_namespace", "--generator=cpp", - "--include-rules=$schema_include_rules" ] + "--include-rules=$schema_include_rules", + ] if (defined(invoker.visibility)) { # If visibility is restricted, add our own target to it. - visibility = [ invoker.visibility, target_visibility ] + visibility = [ + invoker.visibility, + target_visibility, + ] } } } @@ -120,7 +124,7 @@ if (bundle) { uncompiled_sources = [] if (defined(invoker.uncompiled_sources)) { - uncompiled_sources = invoker.uncompiled_sources + uncompiled_sources = invoker.uncompiled_sources } bundle_generator_schema_name = target_name + "_bundle_generator_schema" @@ -132,28 +136,28 @@ "$target_gen_dir/generated_schemas.h", ] args = [ - "--root=" + rebase_path("//", root_build_dir), - "--destdir=" + rebase_path(root_gen_dir, root_build_dir), - "--namespace=$root_namespace", - "--generator=cpp-bundle-schema", - "--include-rules=$schema_include_rules" ] - + rebase_path(sources, root_build_dir) - + rebase_path(uncompiled_sources, root_build_dir) + "--root=" + rebase_path("//", root_build_dir), + "--destdir=" + rebase_path(root_gen_dir, root_build_dir), + "--namespace=$root_namespace", + "--generator=cpp-bundle-schema", + "--include-rules=$schema_include_rules", + ] + rebase_path(sources, root_build_dir) + + rebase_path(uncompiled_sources, root_build_dir) } } if (bundle_registration) { uncompiled_sources = [] if (defined(invoker.uncompiled_sources)) { - uncompiled_sources = invoker.uncompiled_sources + uncompiled_sources = invoker.uncompiled_sources } assert(defined(invoker.impl_dir), "\"impl_dir\" must be defined for the $target_name template.") impl_dir = invoker.impl_dir - bundle_generator_registration_name = target_name + - "_bundle_generator_registration" + bundle_generator_registration_name = + target_name + "_bundle_generator_registration" action(bundle_generator_registration_name) { script = compiler_script inputs = compiler_sources + sources + uncompiled_sources @@ -162,14 +166,14 @@ "$root_gen_dir/$impl_dir/generated_api_registration.h", ] args = [ - "--root=" + rebase_path("//", root_build_dir), - "--destdir=" + rebase_path(root_gen_dir, root_build_dir), - "--namespace=$root_namespace", - "--generator=cpp-bundle-registration", - "--impl-dir=" + rebase_path(impl_dir, "//"), - "--include-rules=$schema_include_rules" ] - + rebase_path(sources, root_build_dir) - + rebase_path(uncompiled_sources, root_build_dir) + "--root=" + rebase_path("//", root_build_dir), + "--destdir=" + rebase_path(root_gen_dir, root_build_dir), + "--namespace=$root_namespace", + "--generator=cpp-bundle-registration", + "--impl-dir=" + rebase_path(impl_dir, "//"), + "--include-rules=$schema_include_rules", + ] + rebase_path(sources, root_build_dir) + + rebase_path(uncompiled_sources, root_build_dir) } }
diff --git a/build/sanitizers/sanitizer_options.cc b/build/sanitizers/sanitizer_options.cc index 821ba485a..a3b05c1e 100644 --- a/build/sanitizers/sanitizer_options.cc +++ b/build/sanitizers/sanitizer_options.cc
@@ -49,6 +49,8 @@ // fast_unwind_on_fatal=1 - use the fast (frame-pointer-based) stack unwinder // to print error reports. V8 doesn't generate debug info for the JIT code, // so the slow unwinder may not work properly. +// detect_stack_use_after_return=1 - use fake stack to delay the reuse of +// stack allocations and detect stack-use-after-return errors. #if defined(OS_LINUX) #if defined(GOOGLE_CHROME_BUILD) // Default AddressSanitizer options for the official build. These do not affect @@ -62,13 +64,14 @@ // Default AddressSanitizer options for buildbots and non-official builds. const char *kAsanDefaultOptions = "strict_memcmp=0 symbolize=false check_printf=1 use_sigaltstack=1 " - "detect_leaks=0 strip_path_prefix=Release/../../ fast_unwind_on_fatal=1"; + "detect_leaks=0 strip_path_prefix=Release/../../ fast_unwind_on_fatal=1 " + "detect_stack_use_after_return=1 "; #endif // GOOGLE_CHROME_BUILD #elif defined(OS_MACOSX) const char *kAsanDefaultOptions = "strict_memcmp=0 replace_intrin=0 check_printf=1 use_sigaltstack=1 " - "strip_path_prefix=Release/../../ fast_unwind_on_fatal=1"; + "strip_path_prefix=Release/../../ fast_unwind_on_fatal=1 "; static const char kNaClDefaultOptions[] = "handle_segv=0"; static const char kNaClFlag[] = "--type=nacl-loader"; #endif // OS_LINUX
diff --git a/build/secondary/testing/BUILD.gn b/build/secondary/testing/BUILD.gn index 2cafa68..fc5063749 100644 --- a/build/secondary/testing/BUILD.gn +++ b/build/secondary/testing/BUILD.gn
@@ -7,5 +7,7 @@ "gmock_mutant.h", # gMock helpers ] - deps = [ "//base" ] + deps = [ + "//base", + ] }
diff --git a/build/secondary/testing/gmock/BUILD.gn b/build/secondary/testing/gmock/BUILD.gn index a0dbad7..4ec6224 100644 --- a/build/secondary/testing/gmock/BUILD.gn +++ b/build/secondary/testing/gmock/BUILD.gn
@@ -24,6 +24,7 @@ "include/gmock/internal/gmock-generated-internal-utils.h", "include/gmock/internal/gmock-internal-utils.h", "include/gmock/internal/gmock-port.h", + #"src/gmock-all.cc", # Not needed by our build. "src/gmock-cardinalities.cc", "src/gmock-internal-utils.cc", @@ -44,6 +45,10 @@ static_library("gmock_main") { # TODO http://crbug.com/412064 enable this flag all the time. testonly = !is_component_build - sources = [ "src/gmock_main.cc" ] - deps = [ ":gmock" ] + sources = [ + "src/gmock_main.cc", + ] + deps = [ + ":gmock", + ] }
diff --git a/build/secondary/testing/gtest/BUILD.gn b/build/secondary/testing/gtest/BUILD.gn index f50afb63..96f4112 100644 --- a/build/secondary/testing/gtest/BUILD.gn +++ b/build/secondary/testing/gtest/BUILD.gn
@@ -9,10 +9,10 @@ ] defines = [ - # In order to allow regex matches in gtest to be shared between Windows # and other systems, we tell gtest to always use it's internal engine. "GTEST_HAS_POSIX_RE=0", + # Chrome doesn't support / require C++11, yet. "GTEST_LANG_CXX11=0", ] @@ -81,6 +81,7 @@ "include/gtest/internal/gtest-string.h", "include/gtest/internal/gtest-tuple.h", "include/gtest/internal/gtest-type-util.h", + #"gtest/src/gtest-all.cc", # Not needed by our build. "src/gtest-death-test.cc", "src/gtest-filepath.cc", @@ -115,6 +116,10 @@ source_set("gtest_main") { # TODO http://crbug.com/412064 enable this flag all the time. testonly = !is_component_build - sources = [ "src/gtest_main.cc" ] - deps = [ ":gtest" ] + sources = [ + "src/gtest_main.cc", + ] + deps = [ + ":gtest", + ] }
diff --git a/build/secondary/third_party/android_tools/BUILD.gn b/build/secondary/third_party/android_tools/BUILD.gn index 14e6c07..0df6545 100644 --- a/build/secondary/third_party/android_tools/BUILD.gn +++ b/build/secondary/third_party/android_tools/BUILD.gn
@@ -11,7 +11,9 @@ # This is the GN version of # //build/android/cpufeatures.gypi:cpufeatures source_set("cpu_features") { - sources = [ "ndk/sources/android/cpufeatures/cpu-features.c" ] + sources = [ + "ndk/sources/android/cpufeatures/cpu-features.c", + ] public_configs = [ ":cpu_features_include" ] configs -= [ "//build/config/compiler:chromium_code" ] @@ -27,27 +29,29 @@ } android_java_prebuilt("android_support_v13_java") { - jar_path = "$android_sdk_root/extras/android/support/v13/android-support-v13.jar" + jar_path = + "$android_sdk_root/extras/android/support/v13/android-support-v13.jar" } android_resources("android_support_v7_appcompat_resources") { v14_verify_only = true - resource_dirs = [ - "$android_sdk_root/extras/android/support/v7/appcompat/res" - ] + resource_dirs = + [ "$android_sdk_root/extras/android/support/v7/appcompat/res" ] custom_package = "android.support.v7.appcompat" } android_java_prebuilt("android_support_v7_appcompat_java") { - deps = [ ":android_support_v7_appcompat_resources" ] - jar_path = "$android_sdk_root/extras/android/support/v7/appcompat/libs/android-support-v7-appcompat.jar" + deps = [ + ":android_support_v7_appcompat_resources", + ] + jar_path = + "$android_sdk_root/extras/android/support/v7/appcompat/libs/android-support-v7-appcompat.jar" } android_resources("android_support_v7_mediarouter_resources") { v14_verify_only = true - resource_dirs = [ - "$android_sdk_root/extras/android/support/v7/mediarouter/res" - ] + resource_dirs = + [ "$android_sdk_root/extras/android/support/v7/mediarouter/res" ] deps = [ ":android_support_v7_appcompat_resources", ] @@ -59,5 +63,6 @@ ":android_support_v7_mediarouter_resources", ":android_support_v7_appcompat_java", ] - jar_path = "$android_sdk_root/extras/android/support/v7/mediarouter/libs/android-support-v7-mediarouter.jar" + jar_path = + "$android_sdk_root/extras/android/support/v7/mediarouter/libs/android-support-v7-mediarouter.jar" }
diff --git a/build/secondary/third_party/cacheinvalidation/src/google/cacheinvalidation/BUILD.gn b/build/secondary/third_party/cacheinvalidation/src/google/cacheinvalidation/BUILD.gn index 2dc1b999..3bbb844e 100644 --- a/build/secondary/third_party/cacheinvalidation/src/google/cacheinvalidation/BUILD.gn +++ b/build/secondary/third_party/cacheinvalidation/src/google/cacheinvalidation/BUILD.gn
@@ -25,4 +25,3 @@ proto_out_dir = "google/cacheinvalidation" } -
diff --git a/build/secondary/third_party/freetype/BUILD.gn b/build/secondary/third_party/freetype/BUILD.gn index 2b96239..2181d87 100644 --- a/build/secondary/third_party/freetype/BUILD.gn +++ b/build/secondary/third_party/freetype/BUILD.gn
@@ -39,9 +39,7 @@ "DARWIN_NO_CARBON", ] - include_dirs = [ - "build", - ] + include_dirs = [ "build" ] public_configs = [ ":freetype_config" ]
diff --git a/build/secondary/third_party/icu/BUILD.gn b/build/secondary/third_party/icu/BUILD.gn index 865a5e4..b618673 100644 --- a/build/secondary/third_party/icu/BUILD.gn +++ b/build/secondary/third_party/icu/BUILD.gn
@@ -224,9 +224,7 @@ "source/i18n/zrule.cpp", "source/i18n/ztrans.cpp", ] - defines = [ - "U_I18N_IMPLEMENTATION", - ] + defines = [ "U_I18N_IMPLEMENTATION" ] deps = [ ":icuuc", ] @@ -259,6 +257,7 @@ cflags += [ "-Wno-header-hygiene", + # Looks like a real issue, see http://crbug.com/114660 "-Wno-return-type-c-linkage", ] @@ -439,9 +438,7 @@ "source/common/uvectr64.cpp", "source/common/wintz.c", ] - defines = [ - "U_COMMON_IMPLEMENTATION", - ] + defines = [ "U_COMMON_IMPLEMENTATION" ] deps = [ ":icudata", ] @@ -475,9 +472,13 @@ } else { copy("icudata") { if (is_android) { - sources = [ "android/icudtl.dat" ] + sources = [ + "android/icudtl.dat", + ] } else { - sources = [ "source/data/in/icudtl.dat" ] + sources = [ + "source/data/in/icudtl.dat", + ] } outputs = [ "$root_out_dir/icudtl.dat" ] @@ -487,7 +488,9 @@ if (is_win) { # On Windows the target DLL is pre-built so just use a copy rule. copy("icudata") { - sources = [ "windows/icudt.dll" ] + sources = [ + "windows/icudt.dll", + ] outputs = [ "$root_out_dir/icudt.dll" ] } } else { @@ -497,11 +500,17 @@ # TODO(GYP): Gyp has considerations here for QNX and for the host toolchain # that have not been ported over. if (is_linux) { - sources = [ "linux/icudtl_dat.S" ] + sources = [ + "linux/icudtl_dat.S", + ] } else if (is_mac) { - sources = [ "mac/icudtl_dat.S" ] + sources = [ + "mac/icudtl_dat.S", + ] } else if (is_android) { - sources = [ "android/icudtl_dat.S" ] + sources = [ + "android/icudtl_dat.S", + ] } else { assert(false, "No icu data for this platform") }
diff --git a/build/secondary/third_party/leveldatabase/BUILD.gn b/build/secondary/third_party/leveldatabase/BUILD.gn index 3653a98..67cda92d 100644 --- a/build/secondary/third_party/leveldatabase/BUILD.gn +++ b/build/secondary/third_party/leveldatabase/BUILD.gn
@@ -70,6 +70,7 @@ "src/include/leveldb/write_batch.h", "src/port/port.h", "src/port/port_example.h", + #"src/port/port_posix.cc", # We use the chromium port instead of this. #"src/port/port_posix.h", "src/table/block.cc", @@ -205,7 +206,7 @@ test("leveldb_crc32c_test") { sources = [ - "src/util/crc32c_test.cc" + "src/util/crc32c_test.cc", ] configs -= [ "//build/config/compiler:chromium_code" ] configs += [ "//build/config/compiler:no_chromium_code" ]
diff --git a/build/secondary/third_party/libjpeg_turbo/BUILD.gn b/build/secondary/third_party/libjpeg_turbo/BUILD.gn index 4dbca978a..82472e7 100644 --- a/build/secondary/third_party/libjpeg_turbo/BUILD.gn +++ b/build/secondary/third_party/libjpeg_turbo/BUILD.gn
@@ -10,106 +10,92 @@ } if (cpu_arch == "x86" || cpu_arch == "x64") { + import("//third_party/yasm/yasm_assemble.gni") -import("//third_party/yasm/yasm_assemble.gni") + yasm_assemble("simd_asm") { + defines = [] -yasm_assemble("simd_asm") { - defines = [] - - if (cpu_arch == "x86") { - sources = [ - "simd/jccolmmx.asm", - "simd/jccolss2.asm", - "simd/jcgrammx.asm", - "simd/jcgrass2.asm", - "simd/jcqnt3dn.asm", - "simd/jcqntmmx.asm", - "simd/jcqnts2f.asm", - "simd/jcqnts2i.asm", - "simd/jcqntsse.asm", - "simd/jcsammmx.asm", - "simd/jcsamss2.asm", - "simd/jdcolmmx.asm", - "simd/jdcolss2.asm", - "simd/jdmermmx.asm", - "simd/jdmerss2.asm", - "simd/jdsammmx.asm", - "simd/jdsamss2.asm", - "simd/jf3dnflt.asm", - "simd/jfmmxfst.asm", - "simd/jfmmxint.asm", - "simd/jfss2fst.asm", - "simd/jfss2int.asm", - "simd/jfsseflt.asm", - "simd/ji3dnflt.asm", - "simd/jimmxfst.asm", - "simd/jimmxint.asm", - "simd/jimmxred.asm", - "simd/jiss2flt.asm", - "simd/jiss2fst.asm", - "simd/jiss2int.asm", - "simd/jiss2red.asm", - "simd/jisseflt.asm", - "simd/jsimdcpu.asm", - ] - defines += [ - "__x86__", - ] - } else if (cpu_arch == "x64") { - sources = [ - "simd/jccolss2-64.asm", - "simd/jcgrass2-64.asm", - "simd/jcqnts2f-64.asm", - "simd/jcqnts2i-64.asm", - "simd/jcsamss2-64.asm", - "simd/jdcolss2-64.asm", - "simd/jdmerss2-64.asm", - "simd/jdsamss2-64.asm", - "simd/jfss2fst-64.asm", - "simd/jfss2int-64.asm", - "simd/jfsseflt-64.asm", - "simd/jiss2flt-64.asm", - "simd/jiss2fst-64.asm", - "simd/jiss2int-64.asm", - "simd/jiss2red-64.asm", - ] - defines += [ - "__x86_64__", - ] - } - - if (is_win) { - defines += [ - "MSVC", - ] - include_dirs = [ "win" ] if (cpu_arch == "x86") { - defines += [ - "WIN32", + sources = [ + "simd/jccolmmx.asm", + "simd/jccolss2.asm", + "simd/jcgrammx.asm", + "simd/jcgrass2.asm", + "simd/jcqnt3dn.asm", + "simd/jcqntmmx.asm", + "simd/jcqnts2f.asm", + "simd/jcqnts2i.asm", + "simd/jcqntsse.asm", + "simd/jcsammmx.asm", + "simd/jcsamss2.asm", + "simd/jdcolmmx.asm", + "simd/jdcolss2.asm", + "simd/jdmermmx.asm", + "simd/jdmerss2.asm", + "simd/jdsammmx.asm", + "simd/jdsamss2.asm", + "simd/jf3dnflt.asm", + "simd/jfmmxfst.asm", + "simd/jfmmxint.asm", + "simd/jfss2fst.asm", + "simd/jfss2int.asm", + "simd/jfsseflt.asm", + "simd/ji3dnflt.asm", + "simd/jimmxfst.asm", + "simd/jimmxint.asm", + "simd/jimmxred.asm", + "simd/jiss2flt.asm", + "simd/jiss2fst.asm", + "simd/jiss2int.asm", + "simd/jiss2red.asm", + "simd/jisseflt.asm", + "simd/jsimdcpu.asm", ] - } else { - defines += [ - "WIN64", + defines += [ "__x86__" ] + } else if (cpu_arch == "x64") { + sources = [ + "simd/jccolss2-64.asm", + "simd/jcgrass2-64.asm", + "simd/jcqnts2f-64.asm", + "simd/jcqnts2i-64.asm", + "simd/jcsamss2-64.asm", + "simd/jdcolss2-64.asm", + "simd/jdmerss2-64.asm", + "simd/jdsamss2-64.asm", + "simd/jfss2fst-64.asm", + "simd/jfss2int-64.asm", + "simd/jfsseflt-64.asm", + "simd/jiss2flt-64.asm", + "simd/jiss2fst-64.asm", + "simd/jiss2int-64.asm", + "simd/jiss2red-64.asm", ] + defines += [ "__x86_64__" ] } - } else if (is_mac) { - defines += [ - "MACHO", - ] - include_dirs = [ "mac" ] - } else if (is_linux) { - defines += [ - "ELF", - ] - include_dirs = [ "linux" ] - } -} + if (is_win) { + defines += [ "MSVC" ] + include_dirs = [ "win" ] + if (cpu_arch == "x86") { + defines += [ "WIN32" ] + } else { + defines += [ "WIN64" ] + } + } else if (is_mac) { + defines += [ "MACHO" ] + include_dirs = [ "mac" ] + } else if (is_linux) { + defines += [ "ELF" ] + include_dirs = [ "linux" ] + } + } } source_set("simd") { if (cpu_arch == "x86") { - deps = [ ":simd_asm" ] + deps = [ + ":simd_asm", + ] sources = [ "simd/jsimd_i386.c", ] @@ -117,7 +103,9 @@ cflags = [ "/wd4245" ] } } else if (cpu_arch == "x64") { - deps = [ ":simd_asm" ] + deps = [ + ":simd_asm", + ] sources = [ "simd/jsimd_x86_64.c", ] @@ -128,7 +116,9 @@ "simd/jsimd_arm_neon.S", ] } else { - sources = [ "jsimd_none.c" ] + sources = [ + "jsimd_none.c", + ] } } @@ -212,7 +202,9 @@ if (is_msan || is_linux) { sources += [ "jsimd_none.c" ] } else { - deps = [ ":simd" ] + deps = [ + ":simd", + ] } # TODO(GYP): Compile the .asm files with YASM as GYP does.
diff --git a/build/secondary/third_party/libsrtp/BUILD.gn b/build/secondary/third_party/libsrtp/BUILD.gn index b0e0a91e..506d19f 100644 --- a/build/secondary/third_party/libsrtp/BUILD.gn +++ b/build/secondary/third_party/libsrtp/BUILD.gn
@@ -38,6 +38,7 @@ defines += [ "INLINE=__inline", "HAVE_BYTESWAP_METHODS_H", + # All Windows architectures are this way. "SIZEOF_UNSIGNED_LONG=4", "SIZEOF_UNSIGNED_LONG_LONG=8", @@ -67,7 +68,10 @@ if (use_system_libsrtp) { group("libsrtp") { - public_configs = [ ":libsrtp_config", ":system_libsrtp_config" ] + public_configs = [ + ":libsrtp_config", + ":system_libsrtp_config", + ] libs = [ "-lsrtp" ] } } else { @@ -118,7 +122,6 @@ # sources "srtp/srtp/ekt.c", "srtp/srtp/srtp.c", - "srtp/crypto/cipher/aes.c", "srtp/crypto/cipher/aes_cbc.c", "srtp/crypto/cipher/aes_icm.c", @@ -154,7 +157,9 @@ executable("rdbx_driver") { configs -= [ "//build/config/compiler:chromium_code" ] configs += [ "//build/config/compiler:no_chromium_code" ] - deps = [ ":libsrtp" ] + deps = [ + ":libsrtp", + ] sources = [ "srtp/include/getopt_s.h", "srtp/test/getopt_s.c", @@ -165,7 +170,9 @@ executable("srtp_driver") { configs -= [ "//build/config/compiler:chromium_code" ] configs += [ "//build/config/compiler:no_chromium_code" ] - deps = [ ":libsrtp" ] + deps = [ + ":libsrtp", + ] sources = [ "srtp/include/getopt_s.h", "srtp/include/srtp_priv.h", @@ -177,7 +184,9 @@ executable("roc_driver") { configs -= [ "//build/config/compiler:chromium_code" ] configs += [ "//build/config/compiler:no_chromium_code" ] - deps = [ ":libsrtp" ] + deps = [ + ":libsrtp", + ] sources = [ "srtp/crypto/include/rdbx.h", "srtp/include/ut_sim.h", @@ -188,7 +197,9 @@ executable("replay_driver") { configs -= [ "//build/config/compiler:chromium_code" ] configs += [ "//build/config/compiler:no_chromium_code" ] - deps = [ ":libsrtp" ] + deps = [ + ":libsrtp", + ] sources = [ "srtp/crypto/include/rdbx.h", "srtp/include/ut_sim.h", @@ -199,7 +210,9 @@ executable("rtpw") { configs -= [ "//build/config/compiler:chromium_code" ] configs += [ "//build/config/compiler:no_chromium_code" ] - deps = [ ":libsrtp" ] + deps = [ + ":libsrtp", + ] sources = [ "srtp/include/getopt_s.h", "srtp/include/rtp.h", @@ -220,7 +233,9 @@ executable("srtp_test_cipher_driver") { configs -= [ "//build/config/compiler:chromium_code" ] configs += [ "//build/config/compiler:no_chromium_code" ] - deps = [ ":libsrtp" ] + deps = [ + ":libsrtp", + ] sources = [ "srtp/crypto/test/cipher_driver.c", ] @@ -229,7 +244,9 @@ executable("srtp_test_datatypes_driver") { configs -= [ "//build/config/compiler:chromium_code" ] configs += [ "//build/config/compiler:no_chromium_code" ] - deps = [ ":libsrtp" ] + deps = [ + ":libsrtp", + ] sources = [ "srtp/crypto/test/datatypes_driver.c", ] @@ -238,7 +255,9 @@ executable("srtp_test_stat_driver") { configs -= [ "//build/config/compiler:chromium_code" ] configs += [ "//build/config/compiler:no_chromium_code" ] - deps = [ ":libsrtp" ] + deps = [ + ":libsrtp", + ] sources = [ "srtp/crypto/test/stat_driver.c", ] @@ -247,7 +266,9 @@ executable("srtp_test_sha1_driver") { configs -= [ "//build/config/compiler:chromium_code" ] configs += [ "//build/config/compiler:no_chromium_code" ] - deps = [ ":libsrtp" ] + deps = [ + ":libsrtp", + ] sources = [ "srtp/crypto/test/sha1_driver.c", ] @@ -256,7 +277,9 @@ executable("srtp_test_kernel_driver") { configs -= [ "//build/config/compiler:chromium_code" ] configs += [ "//build/config/compiler:no_chromium_code" ] - deps = [ ":libsrtp" ] + deps = [ + ":libsrtp", + ] sources = [ "srtp/crypto/test/kernel_driver.c", ] @@ -265,7 +288,9 @@ executable("srtp_test_aes_calc") { configs -= [ "//build/config/compiler:chromium_code" ] configs += [ "//build/config/compiler:no_chromium_code" ] - deps = [ ":libsrtp" ] + deps = [ + ":libsrtp", + ] sources = [ "srtp/crypto/test/aes_calc.c", ] @@ -274,7 +299,9 @@ executable("srtp_test_rand_gen") { configs -= [ "//build/config/compiler:chromium_code" ] configs += [ "//build/config/compiler:no_chromium_code" ] - deps = [ ":libsrtp" ] + deps = [ + ":libsrtp", + ] sources = [ "srtp/crypto/test/rand_gen.c", ] @@ -283,7 +310,9 @@ executable("srtp_test_env") { configs -= [ "//build/config/compiler:chromium_code" ] configs += [ "//build/config/compiler:no_chromium_code" ] - deps = [ ":libsrtp" ] + deps = [ + ":libsrtp", + ] sources = [ "srtp/crypto/test/env.c", ]
diff --git a/build/secondary/third_party/nss/BUILD.gn b/build/secondary/third_party/nss/BUILD.gn index 16568c03..768a85d 100644 --- a/build/secondary/third_party/nss/BUILD.gn +++ b/build/secondary/third_party/nss/BUILD.gn
@@ -14,7 +14,10 @@ # platform and build config. pkg_config("system_nss_no_ssl_config") { packages = [ "nss" ] - extra_args = [ "-v", "-lssl3" ] + extra_args = [ + "-v", + "-lssl3", + ] } } else { include_nss_root_certs = is_ios @@ -207,9 +210,7 @@ public_configs = [ ":nspr_config" ] - configs -= [ - "//build/config/compiler:chromium_code", - ] + configs -= [ "//build/config/compiler:chromium_code" ] if (is_win) { configs -= [ "//build/config/win:unicode", # Requires 8-bit mode. @@ -224,9 +225,7 @@ "FORCE_PR_LOG", ] - include_dirs = [ - "nspr/pr/include/private", - ] + include_dirs = [ "nspr/pr/include/private" ] if (is_win) { cflags = [ @@ -314,9 +313,7 @@ } if (is_mac) { - defines += [ - "HAVE_CRT_EXTERNS_H", - ] + defines += [ "HAVE_CRT_EXTERNS_H" ] libs = [ "CoreFoundation.framework", "CoreServices.framework", @@ -328,8 +325,10 @@ # nspr uses a bunch of deprecated functions (NSLinkModule etc) in # prlink.c on mac. "-Wno-deprecated-declarations", + # nspr passes "const char*" through "void*". "-Wno-incompatible-pointer-types", + # nspr passes "int*" through "unsigned int*". "-Wno-pointer-sign", ] @@ -348,7 +347,9 @@ "nss/lib/nss/nssver.c", ] - public_deps = [ ":nss_static" ] + public_deps = [ + ":nss_static", + ] if (include_nss_root_certs) { public_deps += [ ":nssckbi" ] @@ -359,9 +360,8 @@ ldflags = [ "-all_load" ] } else if (is_win) { # Pass the def file to the linker. - ldflags = [ - "/DEF:" + rebase_path("nss/exports_win.def", root_build_dir) - ] + ldflags = + [ "/DEF:" + rebase_path("nss/exports_win.def", root_build_dir) ] } } } @@ -429,14 +429,10 @@ "nss/lib/ckfw/wrap.c", ] - configs -= [ - "//build/config/compiler:chromium_code" - ] + configs -= [ "//build/config/compiler:chromium_code" ] if (is_win) { - configs -= [ - "//build/config/win:unicode", # Requires 8-bit mode. - ] + configs -= [ "//build/config/win:unicode" ] # Requires 8-bit mode. } configs += [ "//build/config/compiler:no_chromium_code" ] @@ -870,22 +866,21 @@ # NOTE: mpi_arm.c can be used directly on Linux. mpi_arm.c will need # to be excluded conditionally if we start to build NSS on Linux. "nss/lib/freebl/mpi/mpi_arm.c", + # primes.c is included by mpprime.c. "nss/lib/freebl/mpi/primes.c", + # unix_rand.c and win_rand.c are included by sysrand.c. "nss/lib/freebl/unix_rand.c", "nss/lib/freebl/win_rand.c", + # debug_module.c is included by pk11load.c. "nss/lib/pk11wrap/debug_module.c", ] - configs -= [ - "//build/config/compiler:chromium_code" - ] + configs -= [ "//build/config/compiler:chromium_code" ] if (is_win) { - configs -= [ - "//build/config/win:unicode", # Requires 8-bit mode. - ] + configs -= [ "//build/config/win:unicode" ] # Requires 8-bit mode. } configs += [ "//build/config/compiler:no_chromium_code" ] public_configs = [ ":nss_static_config" ] @@ -1112,9 +1107,7 @@ } if (is_mac || is_ios) { - sources -= [ - "nss/lib/freebl/mpi/mpi_amd64.c", - ] + sources -= [ "nss/lib/freebl/mpi/mpi_amd64.c" ] cflags += [ "-include", rebase_path("//third_party/nss/nss/lib/freebl/nss_build_config_mac.h", @@ -1159,10 +1152,7 @@ "USE_HW_AES", "INTEL_GCM", ] - sources -= [ - "nss/lib/freebl/mpi/mpi_amd64.c", - ] - + sources -= [ "nss/lib/freebl/mpi/mpi_amd64.c" ] } else if (cpu_arch == "x64") { sources -= [ "nss/lib/freebl/intel-aes-x86-masm.asm", @@ -1191,12 +1181,16 @@ cflags += [ # nss doesn"t explicitly cast between different enum types. "-Wno-conversion", + # nss passes "const char*" through "void*". "-Wno-incompatible-pointer-types", + # nss prefers `a && b || c` over `(a && b) || c`. "-Wno-logical-op-parentheses", + # nss doesn"t use exhaustive switches on enums "-Wno-switch", + # nss has some `unsigned < 0` checks. "-Wno-tautological-compare", ] @@ -1215,4 +1209,3 @@ } } } # Windows/Mac/iOS. -
diff --git a/build/secondary/third_party/openmax_dl/dl/BUILD.gn b/build/secondary/third_party/openmax_dl/dl/BUILD.gn index 158e3f8b..40c1513 100644 --- a/build/secondary/third_party/openmax_dl/dl/BUILD.gn +++ b/build/secondary/third_party/openmax_dl/dl/BUILD.gn
@@ -19,8 +19,7 @@ # Enable run-time NEON selection. defines = [ "DL_ARM_NEON_OPTIONAL" ] } - } - else if (cpu_arch == "arm64") { + } else if (cpu_arch == "arm64") { # Enable build-time NEON selection. defines = [ "DL_ARM_NEON" ] } @@ -40,9 +39,7 @@ defines = [] if (openmax_big_float_fft) { - defines += [ - "BIG_FFT_TABLE", - ] + defines += [ "BIG_FFT_TABLE" ] } if (cpu_arch == "arm" || cpu_arch == "arm64") { @@ -63,14 +60,10 @@ if (cpu_arch == "arm") { if (arm_use_neon || is_android) { - deps += [ - ":openmax_dl_armv7" - ] + deps += [ ":openmax_dl_armv7" ] } configs -= [ "//build/config/compiler:compiler_arm_fpu" ] - cflags += [ - "-mfpu=neon" - ] + cflags += [ "-mfpu=neon" ] if (arm_use_neon || is_android) { sources += [ @@ -95,10 +88,12 @@ "sp/src/arm/neon/armSP_FFT_CToC_SC32_Radix8_fs_unsafe_s.S", "sp/src/arm/neon/omxSP_FFTFwd_CToC_SC32_Sfs_s.S", "sp/src/arm/neon/omxSP_FFTInv_CToC_SC32_Sfs_s.S", + # Real 32-bit fixed-point FFT "sp/src/arm/neon/armSP_FFTInv_CCSToR_S32_preTwiddleRadix2_unsafe_s.S", "sp/src/arm/neon/omxSP_FFTFwd_RToCCS_S32_Sfs_s.S", "sp/src/arm/neon/omxSP_FFTInv_CCSToR_S32_Sfs_s.S", + # Complex 16-bit fixed-point FFT "sp/src/arm/neon/armSP_FFTInv_CCSToR_S16_preTwiddleRadix2_unsafe_s.S", "sp/src/arm/neon/armSP_FFT_CToC_SC16_Radix2_fs_unsafe_s.S", @@ -111,11 +106,13 @@ "sp/src/arm/neon/armSP_FFT_CToC_SC16_Radix8_fs_unsafe_s.S", "sp/src/arm/neon/omxSP_FFTFwd_CToC_SC16_Sfs_s.S", "sp/src/arm/neon/omxSP_FFTInv_CToC_SC16_Sfs_s.S", + # Real 16-bit fixed-point FFT "sp/src/arm/neon/omxSP_FFTFwd_RToCCS_S16_Sfs_s.S", "sp/src/arm/neon/omxSP_FFTInv_CCSToR_S16_Sfs_s.S", "sp/src/arm/neon/omxSP_FFTFwd_RToCCS_S16S32_Sfs_s.S", "sp/src/arm/neon/omxSP_FFTInv_CCSToR_S32S16_Sfs_s.S", + # Complex floating-point FFT "sp/src/arm/neon/armSP_FFT_CToC_FC32_Radix2_fs_unsafe_s.S", "sp/src/arm/neon/armSP_FFT_CToC_FC32_Radix2_ls_unsafe_s.S", @@ -126,6 +123,7 @@ "sp/src/arm/neon/armSP_FFT_CToC_FC32_Radix8_fs_unsafe_s.S", "sp/src/arm/neon/omxSP_FFTFwd_CToC_FC32_Sfs_s.S", "sp/src/arm/neon/omxSP_FFTInv_CToC_FC32_Sfs_s.S", + # Real floating-point FFT "sp/src/arm/neon/armSP_FFTInv_CCSToR_F32_preTwiddleRadix2_unsafe_s.S", "sp/src/arm/neon/omxSP_FFTFwd_RToCCS_F32_Sfs_s.S", @@ -135,9 +133,7 @@ } if (cpu_arch == "ia32" || cpu_arch == "x64") { - cflags += [ - "-msse2" - ] + cflags += [ "-msse2" ] sources += [ # Real 32-bit floating-point FFT. @@ -185,6 +181,7 @@ "sp/src/arm/arm64/armSP_FFT_CToC_FC32_Radix8_fs_s.S", "sp/src/arm/arm64/omxSP_FFTInv_CToC_FC32.c", "sp/src/arm/arm64/omxSP_FFTFwd_CToC_FC32.c", + # Real floating-point FFT "sp/src/arm/arm64/armSP_FFTInv_CCSToR_F32_preTwiddleRadix2_s.S", "sp/src/arm/arm64/omxSP_FFTFwd_RToCCS_F32.c", @@ -193,12 +190,8 @@ ] } if (cpu_arch == "mipsel") { - cflags += [ - "-std=c99", - ] - sources -= [ - "sp/src/armSP_FFT_F32TwiddleTable.c", - ] + cflags += [ "-std=c99" ] + sources -= [ "sp/src/armSP_FFT_F32TwiddleTable.c" ] sources += [ "sp/api/mipsSP.h", @@ -236,6 +229,7 @@ "sp/src/arm/armv7/armSP_FFT_CToC_FC32_Radix8_fs_unsafe_s.S", "sp/src/arm/armv7/omxSP_FFTInv_CToC_FC32_Sfs_s.S", "sp/src/arm/armv7/omxSP_FFTFwd_CToC_FC32_Sfs_s.S", + # Real floating-point FFT "sp/src/arm/armv7/armSP_FFTInv_CCSToR_F32_preTwiddleRadix2_unsafe_s.S", "sp/src/arm/armv7/omxSP_FFTFwd_RToCCS_F32_Sfs_s.S", @@ -243,8 +237,11 @@ ] if (is_android) { # We only do run-time NEON detection on Android. - deps = [ "//third_party/android_tools:cpu_features" ] + deps = [ + "//third_party/android_tools:cpu_features", + ] libs = [ "log" ] + # Detection routine sources += [ "sp/src/arm/detect.c" ] }
diff --git a/build/secondary/third_party/sfntly/BUILD.gn b/build/secondary/third_party/sfntly/BUILD.gn index 74107afb..a4dbd23a 100644 --- a/build/secondary/third_party/sfntly/BUILD.gn +++ b/build/secondary/third_party/sfntly/BUILD.gn
@@ -125,5 +125,7 @@ configs -= [ "//build/config/compiler:chromium_code" ] configs += [ "//build/config/compiler:no_chromium_code" ] - deps = [ "//third_party/icu:icuuc" ] + deps = [ + "//third_party/icu:icuuc", + ] }
diff --git a/build/secondary/tools/grit/BUILD.gn b/build/secondary/tools/grit/BUILD.gn index f9545374..dee3d06a 100644 --- a/build/secondary/tools/grit/BUILD.gn +++ b/build/secondary/tools/grit/BUILD.gn
@@ -9,7 +9,9 @@ depfile = "$target_out_dir/grit_sources.d" script = "//build/secondary/tools/grit/stamp_grit_sources.py" - inputs = [ "grit.py" ] + inputs = [ + "grit.py", + ] # Note that we can't call this "grit_sources.stamp" because that file is # implicitly created by GN for script actions. @@ -18,6 +20,6 @@ args = [ rebase_path("//tools/grit", root_build_dir), rebase_path(outputs[0], root_build_dir), - rebase_path(depfile, root_build_dir) + rebase_path(depfile, root_build_dir), ] }
diff --git a/build/secondary/tools/grit/grit_rule.gni b/build/secondary/tools/grit/grit_rule.gni index 8726927..9010abc 100644 --- a/build/secondary/tools/grit/grit_rule.gni +++ b/build/secondary/tools/grit/grit_rule.gni
@@ -71,130 +71,215 @@ # # You can also put deps here if the grit source depends on generated # # files. # } -import ("//build/config/crypto.gni") -import ("//build/config/features.gni") -import ("//build/config/ui.gni") +import("//build/config/crypto.gni") +import("//build/config/features.gni") +import("//build/config/ui.gni") grit_defines = [] # Mac and iOS want Title Case strings. use_titlecase_in_grd_files = is_mac || is_ios if (use_titlecase_in_grd_files) { - grit_defines += [ "-D", "use_titlecase" ] + grit_defines += [ + "-D", + "use_titlecase", + ] } if (is_chrome_branded) { grit_defines += [ - "-D", "_google_chrome", - "-E", "CHROMIUM_BUILD=google_chrome", + "-D", + "_google_chrome", + "-E", + "CHROMIUM_BUILD=google_chrome", ] } else { grit_defines += [ - "-D", "_chromium", - "-E", "CHROMIUM_BUILD=chromium", + "-D", + "_chromium", + "-E", + "CHROMIUM_BUILD=chromium", ] } if (is_chromeos) { grit_defines += [ - "-D", "chromeos", - "-D", "scale_factors=2x" + "-D", + "chromeos", + "-D", + "scale_factors=2x", ] } if (is_desktop_linux) { - grit_defines += [ "-D", "desktop_linux" ] + grit_defines += [ + "-D", + "desktop_linux", + ] } if (toolkit_views) { - grit_defines += [ "-D", "toolkit_views" ] + grit_defines += [ + "-D", + "toolkit_views", + ] } if (use_aura) { - grit_defines += [ "-D", "use_aura" ] + grit_defines += [ + "-D", + "use_aura", + ] } if (use_ash) { - grit_defines += [ "-D", "use_ash" ] + grit_defines += [ + "-D", + "use_ash", + ] } if (use_nss_certs) { - grit_defines += [ "-D", "use_nss" ] + grit_defines += [ + "-D", + "use_nss", + ] } if (use_ozone) { - grit_defines += [ "-D", "use_ozone" ] + grit_defines += [ + "-D", + "use_ozone", + ] } if (enable_image_loader_extension) { - grit_defines += [ "-D", "image_loader_extension" ] + grit_defines += [ + "-D", + "image_loader_extension", + ] } if (enable_remoting) { - grit_defines += [ "-D", "remoting" ] + grit_defines += [ + "-D", + "remoting", + ] } if (is_android) { grit_defines += [ - "-t", "android", - "-E", "ANDROID_JAVA_TAGGED_ONLY=true", + "-t", + "android", + "-E", + "ANDROID_JAVA_TAGGED_ONLY=true", ] } if (is_mac || is_ios) { - grit_defines += [ "-D", "scale_factors=2x" ] + grit_defines += [ + "-D", + "scale_factors=2x", + ] } if (is_ios) { grit_defines += [ - "-t", "ios", + "-t", + "ios", + # iOS uses a whitelist to filter resources. - "-w", rebase_path("//build/ios/grit_whitelist.txt", root_build_dir), + "-w", + rebase_path("//build/ios/grit_whitelist.txt", root_build_dir), ] } if (enable_extensions) { - grit_defines += [ "-D", "enable_extensions" ] + grit_defines += [ + "-D", + "enable_extensions", + ] } if (enable_plugins) { - grit_defines += [ "-D", "enable_plugins" ] + grit_defines += [ + "-D", + "enable_plugins", + ] } if (enable_basic_printing || enable_print_preview) { - grit_defines += [ "-D", "enable_printing" ] + grit_defines += [ + "-D", + "enable_printing", + ] if (enable_print_preview) { - grit_defines += [ "-D", "enable_print_preview" ] + grit_defines += [ + "-D", + "enable_print_preview", + ] } } if (enable_themes) { - grit_defines += [ "-D", "enable_themes" ] + grit_defines += [ + "-D", + "enable_themes", + ] } if (enable_app_list) { - grit_defines += [ "-D", "enable_app_list" ] + grit_defines += [ + "-D", + "enable_app_list", + ] } if (enable_settings_app) { - grit_defines += [ "-D", "enable_settings_app" ] + grit_defines += [ + "-D", + "enable_settings_app", + ] } if (enable_google_now) { - grit_defines += [ "-D", "enable_google_now" ] + grit_defines += [ + "-D", + "enable_google_now", + ] } + # Note: use_concatenated_impulse_responses is omitted. It is never used and # should probably be removed from GYP build. if (enable_webrtc) { - grit_defines += [ "-D", "enable_webrtc" ] + grit_defines += [ + "-D", + "enable_webrtc", + ] } -# Note: enable_hangout_services_extension is omitted. It is never set in the -# GYP build. Need to figure out what it's for. +if (enable_hangout_services_extension) { + grit_defines += [ + "-D", + "enable_hangout_services_extension", + ] +} if (enable_task_manager) { - grit_defines += [ "-D", "enable_task_manager" ] + grit_defines += [ + "-D", + "enable_task_manager", + ] } if (enable_notifications) { - grit_defines += [ "-D", "enable_notifications" ] + grit_defines += [ + "-D", + "enable_notifications", + ] } if (enable_wifi_bootstrapping) { - grit_defines += [ "-D", "enable_wifi_bootstrapping" ] + grit_defines += [ + "-D", + "enable_wifi_bootstrapping", + ] } if (enable_service_discovery) { - grit_defines += [ "-D", "enable_service_discovery" ] + grit_defines += [ + "-D", + "enable_service_discovery", + ] } grit_resource_id_file = "//tools/gritsettings/resource_ids" @@ -248,12 +333,10 @@ "$target_out_dir/${grit_output_name}_expected_outputs.txt" write_file(asserted_list_file, rebase_path(invoker.outputs, root_build_dir, output_dir)) - assert_files_flags += [ - "--assert-file-list=" + rebase_path(asserted_list_file, root_build_dir), - ] - grit_outputs = get_path_info( - rebase_path(invoker.outputs, ".", output_dir), - "abspath") + assert_files_flags += [ "--assert-file-list=" + + rebase_path(asserted_list_file, root_build_dir) ] + grit_outputs = + get_path_info(rebase_path(invoker.outputs, ".", output_dir), "abspath") # The config and the action below get this visibility son only the generated # source set can depend on them. The variable "target_name" will get @@ -281,21 +364,32 @@ depfile = "$output_dir/${grit_output_name}.d" args = [ - "-i", source_path, "build", + "-i", + source_path, + "build", ] if (resource_ids != "") { - args += [ "-f", resource_ids ] + args += [ + "-f", + resource_ids, + ] } args += [ - "-o", rebased_output_dir, - "--depdir", ".", - "--depfile", rebase_path(depfile, root_build_dir), - ] + grit_defines + "-o", + rebased_output_dir, + "--depdir", + ".", + "--depfile", + rebase_path(depfile, root_build_dir), + ] + grit_defines # Add extra defines with -D flags. if (defined(invoker.defines)) { - foreach (i, invoker.defines) { - args += [ "-D", i ] + foreach(i, invoker.defines) { + args += [ + "-D", + i, + ] } } @@ -312,7 +406,9 @@ visibility = target_visibility + invoker.visibility } - deps = [ "//tools/grit:grit_sources" ] + deps = [ + "//tools/grit:grit_sources", + ] if (defined(invoker.deps)) { deps += invoker.deps } @@ -327,7 +423,9 @@ # Deps set on the template invocation will go on the grit script running # target rather than this library. - deps = [ ":$grit_custom_target" ] + deps = [ + ":$grit_custom_target", + ] public_configs = [ ":$grit_config" ] if (defined(invoker.public_configs)) {
diff --git a/build/toolchain/android/BUILD.gn b/build/toolchain/android/BUILD.gn index 78ef8477..e074333 100644 --- a/build/toolchain/android/BUILD.gn +++ b/build/toolchain/android/BUILD.gn
@@ -24,8 +24,8 @@ gcc_toolchain(target_name) { # Make our manually injected libs relative to the build dir. android_ndk_lib = rebase_path( - invoker.android_ndk_sysroot + "/" + invoker.android_ndk_lib_dir, - root_build_dir) + invoker.android_ndk_sysroot + "/" + invoker.android_ndk_lib_dir, + root_build_dir) libs_section_prefix = "$android_ndk_lib/crtbegin_dynamic.o" libs_section_postfix = "$android_ndk_lib/crtend_android.o" @@ -63,8 +63,10 @@ android_strip = "${tool_prefix}strip" mkdir_command = "mkdir -p lib.stripped" - strip_command = "$android_strip --strip-unneeded -o $temp_stripped_soname $soname" - replace_command = "if ! cmp -s $temp_stripped_soname $stripped_soname; then mv $temp_stripped_soname $stripped_soname; fi" + strip_command = + "$android_strip --strip-unneeded -o $temp_stripped_soname $soname" + replace_command = + "if ! cmp -s $temp_stripped_soname $stripped_soname; then mv $temp_stripped_soname $stripped_soname; fi" postsolink = "$mkdir_command && $strip_command && $replace_command" solink_outputs = [ stripped_soname ]
diff --git a/build/toolchain/gcc_toolchain.gni b/build/toolchain/gcc_toolchain.gni index e415459e..4a4ef45 100644 --- a/build/toolchain/gcc_toolchain.gni +++ b/build/toolchain/gcc_toolchain.gni
@@ -84,33 +84,33 @@ tool("cc") { depfile = "{{output}}.d" - command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}" + command = + "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}" depsformat = "gcc" description = "CC {{output}}" - outputs = [ - "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o", - ] + outputs = + [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ] } tool("cxx") { depfile = "{{output}}.d" - command = "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}" + command = + "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}" depsformat = "gcc" description = "CXX {{output}}" - outputs = [ - "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o", - ] + outputs = + [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ] } tool("asm") { # For GCC we can just use the C compiler to compile assembly. depfile = "{{output}}.d" - command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}" + command = + "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}" depsformat = "gcc" description = "ASM {{output}}" - outputs = [ - "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o", - ] + outputs = + [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ] } tool("alink") { @@ -118,9 +118,8 @@ command = "rm -f {{output}} && $ar rcs {{output}} @$rspfile" description = "AR {{output}}" rspfile_content = "{{inputs}}" - outputs = [ - "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" - ] + outputs = + [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ] default_output_extension = ".a" output_prefix = "lib" } @@ -136,15 +135,19 @@ # existing .TOC file, overwrite it, otherwise, don't change it. tocfile = sofile + ".TOC" temporary_tocname = sofile + ".tmp" - link_command = "$ld -shared {{ldflags}} -o $sofile -Wl,-soname=$soname @$rspfile" - toc_command = "{ readelf -d $sofile | grep SONAME ; nm -gD -f p $soname | cut -f1-2 -d' '; } > $temporary_tocname" - replace_command = "if ! cmp -s $temporary_tocname $tocfile; then mv $temporary_tocname $tocfile; fi" + link_command = + "$ld -shared {{ldflags}} -o $sofile -Wl,-soname=$soname @$rspfile" + toc_command = + "{ readelf -d $sofile | grep SONAME ; nm -gD -f p $soname | cut -f1-2 -d' '; } > $temporary_tocname" + replace_command = + "if ! cmp -s $temporary_tocname $tocfile; then mv $temporary_tocname $tocfile; fi" command = "$link_command && $toc_command && $replace_command" if (defined(invoker.postsolink)) { command += " && " + invoker.postsolink } - rspfile_content = "-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive $solink_libs_section_prefix {{libs}} $solink_libs_section_postfix" + rspfile_content = + "-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive $solink_libs_section_prefix {{libs}} $solink_libs_section_postfix" description = "SOLINK $sofile" @@ -176,7 +179,8 @@ tool("link") { outfile = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}" rspfile = "$outfile.rsp" - command = "$ld {{ldflags}} -o $outfile -Wl,--start-group @$rspfile {{solibs}} -Wl,--end-group $libs_section_prefix {{libs}} $libs_section_postfix" + command = + "$ld {{ldflags}} -o $outfile -Wl,--start-group @$rspfile {{solibs}} -Wl,--end-group $libs_section_prefix {{libs}} $libs_section_postfix" if (defined(invoker.postlink)) { command += " && " + invoker.postlink } @@ -194,7 +198,8 @@ } tool("copy") { - command = "ln -f {{source}} {{output}} 2>/dev/null || (rm -rf {{output}} && cp -af {{source}} {{output}})" + command = + "ln -f {{source}} {{output}} 2>/dev/null || (rm -rf {{output}} && cp -af {{source}} {{output}})" description = "COPY {{source}} {{output}}" }
diff --git a/build/toolchain/mac/BUILD.gn b/build/toolchain/mac/BUILD.gn index b1cd36b..052e76c2 100644 --- a/build/toolchain/mac/BUILD.gn +++ b/build/toolchain/mac/BUILD.gn
@@ -28,7 +28,7 @@ # This will copy the gyp-mac-tool to the build directory. We pass in the source # file of the win tool. gyp_mac_tool_source = - rebase_path("//tools/gyp/pylib/gyp/mac_tool.py", root_build_dir) + rebase_path("//tools/gyp/pylib/gyp/mac_tool.py", root_build_dir) exec_script("setup_toolchain.py", [ gyp_mac_tool_source ]) # Shared toolchain definition. Invocations should set toolchain_os to set the @@ -57,61 +57,61 @@ tool("cc") { depfile = "{{output}}.d" - command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}" + command = + "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}" depsformat = "gcc" description = "CC {{output}}" - outputs = [ - "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o", - ] + outputs = + [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ] } tool("cxx") { depfile = "{{output}}.d" - command = "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}" + command = + "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}" depsformat = "gcc" description = "CXX {{output}}" - outputs = [ - "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o", - ] + outputs = + [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ] } tool("asm") { # For GCC we can just use the C compiler to compile assembly. depfile = "{{output}}.d" - command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}" + command = + "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}" depsformat = "gcc" description = "ASM {{output}}" - outputs = [ - "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o", - ] + outputs = + [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ] } tool("objc") { depfile = "{{output}}.d" - command = "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} {{cflags_objc}} -c {{source}} -o {{output}}" + command = + "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} {{cflags_objc}} -c {{source}} -o {{output}}" depsformat = "gcc" description = "OBJC {{output}}" - outputs = [ - "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o", - ] + outputs = + [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ] } tool("objcxx") { depfile = "{{output}}.d" - command = "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} {{cflags_objcc}} -c {{source}} -o {{output}}" + command = + "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} {{cflags_objcc}} -c {{source}} -o {{output}}" depsformat = "gcc" description = "OBJCXX {{output}}" - outputs = [ - "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o", - ] + outputs = + [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ] } tool("alink") { - command = "rm -f {{output}} && ./gyp-mac-tool filter-libtool libtool -static -o {{output}} {{inputs}}" + command = + "rm -f {{output}} && ./gyp-mac-tool filter-libtool libtool -static -o {{output}} {{inputs}}" description = "LIBTOOL-STATIC {{output}}" - outputs = [ - "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" - ] + outputs = + [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ] default_output_extension = ".a" output_prefix = "lib" } @@ -131,12 +131,17 @@ tocname = dylib + ".TOC" temporary_tocname = dylib + ".tmp" - does_reexport_command = "[ ! -e $dylib -o ! -e $tocname ] || otool -l $dylib | grep -q LC_REEXPORT_DYLIB" - link_command = "$ld -shared {{ldflags}} -o $dylib -Wl,-filelist,$rspfile {{solibs}} {{libs}}" - replace_command = "if ! cmp -s $temporary_tocname $tocname; then mv $temporary_tocname $tocname" - extract_toc_command = "{ otool -l $dylib | grep LC_ID_DYLIB -A 5; nm -gP $dylib | cut -f1-2 -d' ' | grep -v U\$\$; true; }" + does_reexport_command = + "[ ! -e $dylib -o ! -e $tocname ] || otool -l $dylib | grep -q LC_REEXPORT_DYLIB" + link_command = + "$ld -shared {{ldflags}} -o $dylib -Wl,-filelist,$rspfile {{solibs}} {{libs}}" + replace_command = + "if ! cmp -s $temporary_tocname $tocname; then mv $temporary_tocname $tocname" + extract_toc_command = + "{ otool -l $dylib | grep LC_ID_DYLIB -A 5; nm -gP $dylib | cut -f1-2 -d' ' | grep -v U\$\$; true; }" - command = "if $does_reexport_command ; then $link_command && $extract_toc_command > $tocname; else $link_command && $extract_toc_command > $temporary_tocname && $replace_command ; fi; fi" + command = + "if $does_reexport_command ; then $link_command && $extract_toc_command > $tocname; else $link_command && $extract_toc_command > $temporary_tocname && $replace_command ; fi; fi" rspfile_content = "{{inputs_newline}}" @@ -167,7 +172,8 @@ tool("link") { outfile = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}" rspfile = "$outfile.rsp" - command = "$ld {{ldflags}} -o $outfile -Wl,-filelist,$rspfile {{solibs}} {{libs}}" + command = + "$ld {{ldflags}} -o $outfile -Wl,-filelist,$rspfile {{solibs}} {{libs}}" description = "LINK $outfile" rspfile_content = "{{inputs_newline}}" outputs = [ outfile ] @@ -179,7 +185,8 @@ } tool("copy") { - command = "ln -f {{source}} {{output}} 2>/dev/null || (rm -rf {{output}} && cp -af {{source}} {{output}})" + command = + "ln -f {{source}} {{output}} 2>/dev/null || (rm -rf {{output}} && cp -af {{source}} {{output}})" description = "COPY {{source}} {{output}}" }
diff --git a/build/toolchain/nacl/BUILD.gn b/build/toolchain/nacl/BUILD.gn index 8c76f5a9..bea30e0 100644 --- a/build/toolchain/nacl/BUILD.gn +++ b/build/toolchain/nacl/BUILD.gn
@@ -9,14 +9,16 @@ ld = toolprefix + "g++" tool("cc") { - command = "$cc -MMD -MF \$out.d \$defines \$includes \$cflags \$cflags_c -c \$in -o \$out" + command = + "$cc -MMD -MF \$out.d \$defines \$includes \$cflags \$cflags_c -c \$in -o \$out" description = "CC(NaCl x86 Newlib) \$out" depfile = "\$out.d" depsformat = "gcc" } tool("cxx") { # cflags_pch_cc - command = "$cxx -MMD -MF \$out.d \$defines \$includes \$cflags \$cflags_cc -c \$in -o \$out" + command = + "$cxx -MMD -MF \$out.d \$defines \$includes \$cflags \$cflags_cc -c \$in -o \$out" description = "CXX(NaCl x86 Newlib) \$out" depfile = "\$out.d" depsformat = "gcc" @@ -26,14 +28,18 @@ description = "AR(NaCl x86 Newlib) \$out" } tool("solink") { - command = "if [ ! -e \$lib -o ! -e \${lib}.TOC ]; then $ld -shared \$ldflags -o \$lib -Wl,-soname=\$soname -Wl,--whole-archive \$in \$solibs -Wl,--no-whole-archive \$libs && { readelf -d \${lib} | grep SONAME ; nm -gD -f p \${lib} | cut -f1-2 -d' '; } > \${lib}.TOC; else $ld -shared \$ldflags -o \$lib -Wl,-soname=\$soname -Wl,--whole-archive \$in \$solibs -Wl,--no-whole-archive \$libs && { readelf -d \${lib} | grep SONAME ; nm -gD -f p \${lib} | cut -f1-2 -d' '; } > \${lib}.tmp && if ! cmp -s \${lib}.tmp \${lib}.TOC; then mv \${lib}.tmp \${lib}.TOC ; fi; fi" + command = + "if [ ! -e \$lib -o ! -e \${lib}.TOC ]; then $ld -shared \$ldflags -o \$lib -Wl,-soname=\$soname -Wl,--whole-archive \$in \$solibs -Wl,--no-whole-archive \$libs && { readelf -d \${lib} | grep SONAME ; nm -gD -f p \${lib} | cut -f1-2 -d' '; } > \${lib}.TOC; else $ld -shared \$ldflags -o \$lib -Wl,-soname=\$soname -Wl,--whole-archive \$in \$solibs -Wl,--no-whole-archive \$libs && { readelf -d \${lib} | grep SONAME ; nm -gD -f p \${lib} | cut -f1-2 -d' '; } > \${lib}.tmp && if ! cmp -s \${lib}.tmp \${lib}.TOC; then mv \${lib}.tmp \${lib}.TOC ; fi; fi" description = "SOLINK(NaCl x86 Newlib) \$lib" + #pool = "link_pool" restat = "1" } tool("link") { - command = "$ld \$ldflags -o \$out -Wl,--start-group \$in \$solibs -Wl,--end-group \$libs" + command = + "$ld \$ldflags -o \$out -Wl,--start-group \$in \$solibs -Wl,--end-group \$libs" description = "LINK(NaCl x86 Newlib) \$out" + #pool = "link_pool" }
diff --git a/build/toolchain/win/BUILD.gn b/build/toolchain/win/BUILD.gn index 87bd254..1be1cf4 100644 --- a/build/toolchain/win/BUILD.gn +++ b/build/toolchain/win/BUILD.gn
@@ -2,6 +2,15 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +declare_args() { + # Path to the directory containing the VC binaries for the right + # combination of host and target architectures. Currently only the + # 64-bit host toolchain is supported, with either 32-bit or 64-bit targets. + # If vc_bin_dir is not specified on the command line (and it normally + # isn't), we will dynamically determine the right value to use at runtime. + vc_bin_dir = "" +} + import("//build/config/win/visual_studio_version.gni") import("//build/toolchain/goma.gni") @@ -13,15 +22,22 @@ # Its arguments are the VS path and the compiler wrapper tool. It will write # "environment.x86" and "environment.x64" to the build directory and return a # list to us. -gyp_win_tool_path = rebase_path("//tools/gyp/pylib/gyp/win_tool.py", - root_build_dir) -exec_script("setup_toolchain.py", - [ - visual_studio_path, - gyp_win_tool_path, - windows_sdk_path, - visual_studio_runtime_dirs - ]) +gyp_win_tool_path = + rebase_path("//tools/gyp/pylib/gyp/win_tool.py", root_build_dir) + +toolchain_data = exec_script("setup_toolchain.py", + [ + visual_studio_path, + gyp_win_tool_path, + windows_sdk_path, + visual_studio_runtime_dirs, + cpu_arch, + ], + "scope") + +if (vc_bin_dir == "") { + vc_bin_dir = toolchain_data.vc_bin_dir +} # This value will be inherited in the toolchain below. concurrent_links = exec_script("../get_concurrent_links.py", [], "value") @@ -41,62 +57,75 @@ } else { configuration = "Release" } - exec_script("../../vs_toolchain.py", ["copy_dlls", - rebase_path(root_build_dir), - configuration, - invoker.cpu_arch]) + exec_script("../../vs_toolchain.py", + [ + "copy_dlls", + rebase_path(root_build_dir), + configuration, + invoker.cpu_arch, + ]) + + if (use_goma) { + goma_prefix = "$goma_dir/gomacc.exe " + } else { + goma_prefix = "" + } + + cl = "${goma_prefix}\"${vc_bin_dir}/cl.exe\"" toolchain(target_name) { # Make these apply to all tools below. lib_switch = "" - lib_dir_switch="/LIBPATH:" + lib_dir_switch = "/LIBPATH:" tool("cc") { rspfile = "{{output}}.rsp" pdbname = "{{target_out_dir}}/{{target_output_name}}_c.pdb" - command = "ninja -t msvc -e $env -- cl.exe /nologo /showIncludes /FC @$rspfile /c {{source}} /Fo{{output}} /Fd$pdbname" + command = + "ninja -t msvc -e $env -- $cl /nologo /showIncludes /FC @$rspfile /c {{source}} /Fo{{output}} /Fd$pdbname" depsformat = "msvc" description = "CC {{output}}" - outputs = [ - "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.obj", - ] + outputs = + [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.obj" ] rspfile_content = "{{defines}} {{include_dirs}} {{cflags}} {{cflags_c}}" } tool("cxx") { rspfile = "{{output}}.rsp" + # The PDB name needs to be different between C and C++ compiled files. pdbname = "{{target_out_dir}}/{{target_output_name}}_cc.pdb" - command = "ninja -t msvc -e $env -- cl.exe /nologo /showIncludes /FC @$rspfile /c {{source}} /Fo{{output}} /Fd$pdbname" + command = + "ninja -t msvc -e $env -- $cl /nologo /showIncludes /FC @$rspfile /c {{source}} /Fo{{output}} /Fd$pdbname" depsformat = "msvc" description = "CXX {{output}}" - outputs = [ - "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.obj", - ] + outputs = + [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.obj" ] rspfile_content = "{{defines}} {{include_dirs}} {{cflags}} {{cflags_c}}" } tool("rc") { - command = "$python_path gyp-win-tool rc-wrapper $env rc.exe {{defines}} {{include_dirs}} /fo{{output}} {{source}}" - outputs = [ - "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.res", - ] + command = + "$python_path gyp-win-tool rc-wrapper $env rc.exe {{defines}} {{include_dirs}} /fo{{output}} {{source}}" + outputs = + [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.res" ] description = "RC {{output}}" } tool("asm") { # TODO(brettw): "/safeseh" assembler argument is hardcoded here. Extract # assembler flags to a variable like cflags. crbug.com/418613 - command = "$python_path gyp-win-tool asm-wrapper $env ml.exe {{defines}} {{include_dirs}} /safeseh /c /Fo {{output}} {{source}}" + command = + "$python_path gyp-win-tool asm-wrapper $env ml.exe {{defines}} {{include_dirs}} /safeseh /c /Fo {{output}} {{source}}" description = "ASM {{output}}" - outputs = [ - "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.obj", - ] + outputs = + [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.obj" ] } tool("alink") { rspfile = "{{output}}.rsp" - command = "$python_path gyp-win-tool link-wrapper $env False lib.exe /nologo /ignore:4221 /OUT:{{output}} @$rspfile" + command = + "$python_path gyp-win-tool link-wrapper $env False lib.exe /nologo /ignore:4221 /OUT:{{output}} @$rspfile" description = "LIB {{output}}" outputs = [ # Ignore {{output_extension}} and always use .lib, there's no reason to @@ -104,6 +133,7 @@ "{{target_out_dir}}/{{target_output_name}}.lib", ] default_output_extension = ".lib" + # The use of inputs_newline is to work around a fixed per-line buffer # size in the linker. rspfile_content = "{{inputs_newline}}" @@ -111,10 +141,12 @@ tool("solink") { dllname = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}" # e.g. foo.dll - libname = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}.lib" # e.g. foo.dll.lib + libname = + "{{root_out_dir}}/{{target_output_name}}{{output_extension}}.lib" # e.g. foo.dll.lib rspfile = "${dllname}.rsp" - link_command = "$python_path gyp-win-tool link-wrapper $env False link.exe /nologo /IMPLIB:$libname /DLL /OUT:$dllname /PDB:${dllname}.pdb @$rspfile" + link_command = + "$python_path gyp-win-tool link-wrapper $env False link.exe /nologo /IMPLIB:$libname /DLL /OUT:$dllname /PDB:${dllname}.pdb @$rspfile" # TODO(brettw) support manifests #manifest_command = "$python_path gyp-win-tool manifest-wrapper $env mt.exe -nologo -manifest $manifests -out:${dllname}.manifest" @@ -129,6 +161,7 @@ ] link_output = libname depend_output = libname + # The use of inputs_newline is to work around a fixed per-line buffer # size in the linker. rspfile_content = "{{libs}} {{solibs}} {{inputs_newline}} {{ldflags}}" @@ -137,7 +170,8 @@ tool("link") { rspfile = "{{output}}.rsp" - link_command = "$python_path gyp-win-tool link-wrapper $env False link.exe /nologo /OUT:{{output}} /PDB:{{output}}.pdb @$rspfile" + link_command = + "$python_path gyp-win-tool link-wrapper $env False link.exe /nologo /OUT:{{output}} /PDB:{{output}}.pdb @$rspfile" # TODO(brettw) support manifests #manifest_command = "$python_path gyp-win-tool manifest-wrapper $env mt.exe -nologo -manifest $manifests -out:{{output}}.manifest" @@ -146,9 +180,9 @@ default_output_extension = ".exe" description = "LINK {{output}}" - outputs = [ - "{{root_out_dir}}/{{target_output_name}}{{output_extension}}", - ] + outputs = + [ "{{root_out_dir}}/{{target_output_name}}{{output_extension}}" ] + # The use of inputs_newline is to work around a fixed per-line buffer # size in the linker. rspfile_content = "{{inputs_newline}} {{libs}} {{solibs}} {{ldflags}}" @@ -160,7 +194,8 @@ } tool("copy") { - command = "$python_path gyp-win-tool recursive-mirror {{source}} {{output}}" + command = + "$python_path gyp-win-tool recursive-mirror {{source}} {{output}}" description = "COPY {{source}} {{output}}" }
diff --git a/build/toolchain/win/midl.gni b/build/toolchain/win/midl.gni index 7f068d01..9fda96b 100644 --- a/build/toolchain/win/midl.gni +++ b/build/toolchain/win/midl.gni
@@ -67,7 +67,8 @@ } args = [ - "midl-wrapper", win_tool_arch, + "midl-wrapper", + win_tool_arch, rebase_path(out_dir, root_build_dir), type_library_file, header_file, @@ -75,13 +76,18 @@ interface_identifier_file, proxy_file, "{{source}}", - "/char", "signed", - "/env", idl_target_platform, + "/char", + "signed", + "/env", + idl_target_platform, "/Oicf", ] foreach(include, system_include_dirs) { - args += [ "/I", include ] + args += [ + "/I", + include, + ] } } @@ -91,10 +97,11 @@ } # We only compile the IID files from the IDL tool rather than all outputs. - sources = process_file_template( - invoker.sources, - [ "$out_dir/$interface_identifier_file" ]) + sources = process_file_template(invoker.sources, + [ "$out_dir/$interface_identifier_file" ]) - deps = [ ":$action_name" ] + deps = [ + ":$action_name", + ] } }
diff --git a/build/toolchain/win/setup_toolchain.py b/build/toolchain/win/setup_toolchain.py index 42c3af1..6b7ea7a 100644 --- a/build/toolchain/win/setup_toolchain.py +++ b/build/toolchain/win/setup_toolchain.py
@@ -98,20 +98,26 @@ def main(): - if len(sys.argv) != 5: + if len(sys.argv) != 6: print('Usage setup_toolchain.py ' - '<visual studio path> <win tool path> <win sdk path> <runtime dirs>') + '<visual studio path> <win tool path> <win sdk path> ' + '<runtime dirs> <cpu_arch>') sys.exit(2) vs_path = sys.argv[1] tool_source = sys.argv[2] win_sdk_path = sys.argv[3] runtime_dirs = sys.argv[4] + cpu_arch = sys.argv[5] _CopyTool(tool_source) archs = ('x86', 'x64') + assert cpu_arch in archs + vc_bin_dir = '' + # TODO(scottmg|goma): Do we need an equivalent of # ninja_use_custom_environment_files? + for arch in archs: # Extract environment variables for subprocesses. args = _SetupScript(arch, win_sdk_path) @@ -122,6 +128,12 @@ env = _ExtractImportantEnvironment(variables) env['PATH'] = runtime_dirs + ';' + env['PATH'] + if arch == cpu_arch: + for path in env['PATH'].split(os.pathsep): + if os.path.exists(os.path.join(path, 'cl.exe')): + vc_bin_dir = os.path.realpath(path) + break + # TODO(scottmg|thakis|dpranke): Is there an equivalent to # msvs_system_include_dirs that we need to inject into INCLUDE here? @@ -129,6 +141,9 @@ with open('environment.' + arch, 'wb') as f: f.write(env_block) + assert vc_bin_dir + print 'vc_bin_dir = "%s"' % vc_bin_dir + if __name__ == '__main__': main()
diff --git a/build/util/BUILD.gn b/build/util/BUILD.gn index 320c5ee..3fc7757 100644 --- a/build/util/BUILD.gn +++ b/build/util/BUILD.gn
@@ -6,15 +6,20 @@ script = "version.py" lastchange_file = "LASTCHANGE.blink" + # TODO(brettw) move from content to this directory. template_file = "//content/webkit_version.h.in" - inputs = [ lastchange_file, template_file ] + inputs = [ + lastchange_file, + template_file, + ] output_file = "$root_gen_dir/webkit_version.h" outputs = [ output_file ] args = [ - "-f", rebase_path(lastchange_file, root_build_dir), + "-f", + rebase_path(lastchange_file, root_build_dir), rebase_path(template_file, root_build_dir), rebase_path(output_file, root_build_dir), ]
diff --git a/cc/base/rolling_time_delta_history.cc b/cc/base/rolling_time_delta_history.cc index 0f95cc5..db04f58 100644 --- a/cc/base/rolling_time_delta_history.cc +++ b/cc/base/rolling_time_delta_history.cc
@@ -26,10 +26,6 @@ chronological_sample_deque_.push_back(it); } -size_t RollingTimeDeltaHistory::SampleCount() { - return sample_set_.size(); -} - void RollingTimeDeltaHistory::Clear() { chronological_sample_deque_.clear(); sample_set_.clear();
diff --git a/cc/base/rolling_time_delta_history.h b/cc/base/rolling_time_delta_history.h index 603c813..e51fb86 100644 --- a/cc/base/rolling_time_delta_history.h +++ b/cc/base/rolling_time_delta_history.h
@@ -23,8 +23,6 @@ void InsertSample(base::TimeDelta time); - size_t SampleCount(); - void Clear(); // Returns the smallest sample that is greater than or equal to the specified
diff --git a/cc/debug/rasterize_and_record_benchmark.cc b/cc/debug/rasterize_and_record_benchmark.cc index a2052ab..41d6210 100644 --- a/cc/debug/rasterize_and_record_benchmark.cc +++ b/cc/debug/rasterize_and_record_benchmark.cc
@@ -18,6 +18,7 @@ #include "cc/resources/picture_pile.h" #include "cc/trees/layer_tree_host.h" #include "cc/trees/layer_tree_host_common.h" +#include "third_party/skia/include/utils/SkPictureUtils.h" #include "ui/gfx/geometry/rect.h" namespace cc { @@ -64,6 +65,7 @@ DCHECK(!results_.get()); results_ = make_scoped_ptr(new base::DictionaryValue); results_->SetInteger("pixels_recorded", record_results_.pixels_recorded); + results_->SetInteger("picture_memory_usage", record_results_.bytes_used); for (int i = 0; i < Picture::RECORDING_MODE_COUNT; i++) { std::string name = base::StringPrintf("record_time%s_ms", kModeSuffixes[i]); @@ -119,6 +121,7 @@ Picture::RecordingMode mode = static_cast<Picture::RecordingMode>(mode_index); base::TimeDelta min_time = base::TimeDelta::Max(); + size_t memory_used = 0; // Parameters for LapTimer. const int kTimeLimitMillis = 1; @@ -131,18 +134,21 @@ LapTimer timer(kWarmupRuns, base::TimeDelta::FromMilliseconds(kTimeLimitMillis), kTimeCheckInterval); + scoped_refptr<Picture> picture; do { - scoped_refptr<Picture> picture = Picture::Create( - visible_content_rect, painter, tile_grid_info, false, mode); + picture = Picture::Create(visible_content_rect, painter, tile_grid_info, + false, mode); timer.NextLap(); } while (!timer.HasTimeLimitExpired()); base::TimeDelta duration = base::TimeDelta::FromMillisecondsD(timer.MsPerLap()); if (duration < min_time) min_time = duration; + memory_used = picture->ApproximateMemoryUsage(); } if (mode == Picture::RECORD_NORMALLY) { + record_results_.bytes_used += memory_used; record_results_.pixels_recorded += visible_content_rect.width() * visible_content_rect.height(); } @@ -151,7 +157,8 @@ } RasterizeAndRecordBenchmark::RecordResults::RecordResults() - : pixels_recorded(0) {} + : pixels_recorded(0), bytes_used(0) { +} RasterizeAndRecordBenchmark::RecordResults::~RecordResults() {}
diff --git a/cc/debug/rasterize_and_record_benchmark.h b/cc/debug/rasterize_and_record_benchmark.h index 68d5d05f..8a23292 100644 --- a/cc/debug/rasterize_and_record_benchmark.h +++ b/cc/debug/rasterize_and_record_benchmark.h
@@ -46,6 +46,7 @@ ~RecordResults(); int pixels_recorded; + size_t bytes_used; base::TimeDelta total_best_time[Picture::RECORDING_MODE_COUNT]; };
diff --git a/cc/debug/rasterize_and_record_benchmark_impl.cc b/cc/debug/rasterize_and_record_benchmark_impl.cc index e276a41..c1fc809 100644 --- a/cc/debug/rasterize_and_record_benchmark_impl.cc +++ b/cc/debug/rasterize_and_record_benchmark_impl.cc
@@ -173,6 +173,8 @@ scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue()); result->SetDouble("rasterize_time_ms", rasterize_results_.total_best_time.InMillisecondsF()); + result->SetDouble("total_pictures_in_pile_size", + rasterize_results_.total_memory_usage); result->SetInteger("pixels_rasterized", rasterize_results_.pixels_rasterized); result->SetInteger("pixels_rasterized_with_non_solid_color", rasterize_results_.pixels_rasterized_with_non_solid_color); @@ -263,16 +265,22 @@ rasterize_results_.pixels_rasterized += tile_size; rasterize_results_.total_best_time += min_time; } + + const RasterSource* layer_raster_source = layer->GetRasterSource(); + rasterize_results_.total_memory_usage += + layer_raster_source->GetPictureMemoryUsage(); } RasterizeAndRecordBenchmarkImpl::RasterizeResults::RasterizeResults() : pixels_rasterized(0), pixels_rasterized_with_non_solid_color(0), pixels_rasterized_as_opaque(0), + total_memory_usage(0), total_layers(0), total_picture_layers(0), total_picture_layers_with_no_content(0), - total_picture_layers_off_screen(0) {} + total_picture_layers_off_screen(0) { +} RasterizeAndRecordBenchmarkImpl::RasterizeResults::~RasterizeResults() {}
diff --git a/cc/debug/rasterize_and_record_benchmark_impl.h b/cc/debug/rasterize_and_record_benchmark_impl.h index c0f26fd3..7ca471a 100644 --- a/cc/debug/rasterize_and_record_benchmark_impl.h +++ b/cc/debug/rasterize_and_record_benchmark_impl.h
@@ -41,6 +41,7 @@ int pixels_rasterized_with_non_solid_color; int pixels_rasterized_as_opaque; base::TimeDelta total_best_time; + int total_memory_usage; int total_layers; int total_picture_layers; int total_picture_layers_with_no_content;
diff --git a/cc/layers/picture_layer_impl.h b/cc/layers/picture_layer_impl.h index d8ab036..52d8433 100644 --- a/cc/layers/picture_layer_impl.h +++ b/cc/layers/picture_layer_impl.h
@@ -129,6 +129,9 @@ bool AllTilesRequiredForActivationAreReadyToDraw() const; bool AllTilesRequiredForDrawAreReadyToDraw() const; + // Used for benchmarking + const RasterSource* GetRasterSource() const { return raster_source_.get(); } + protected: friend class LayerRasterTileIterator; using TileRequirementCheck = bool (PictureLayerTiling::*)(const Tile*) const;
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc index d18e97a..ce66675 100644 --- a/cc/layers/picture_layer_impl_unittest.cc +++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -330,7 +330,7 @@ base::TimeTicks time_ticks; time_ticks += base::TimeDelta::FromMilliseconds(1); host_impl_.SetCurrentBeginFrameArgs( - CreateBeginFrameArgsForTesting(time_ticks)); + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks)); gfx::Size tile_size(100, 100); gfx::Size layer_bounds(400, 400); @@ -347,7 +347,7 @@ time_ticks += base::TimeDelta::FromMilliseconds(200); host_impl_.SetCurrentBeginFrameArgs( - CreateBeginFrameArgsForTesting(time_ticks)); + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks)); // Update tiles with viewport for tile priority as (0, 0, 100, 100) and the // identify transform for tile priority. @@ -385,7 +385,7 @@ // should be (200, 200, 100, 100) applied with the said transform. time_ticks += base::TimeDelta::FromMilliseconds(200); host_impl_.SetCurrentBeginFrameArgs( - CreateBeginFrameArgsForTesting(time_ticks)); + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks)); viewport_rect_for_tile_priority = gfx::Rect(200, 200, 100, 100); transform_for_tile_priority.Translate(100, 100); @@ -426,7 +426,7 @@ base::TimeTicks time_ticks; time_ticks += base::TimeDelta::FromMilliseconds(1); host_impl_.SetCurrentBeginFrameArgs( - CreateBeginFrameArgsForTesting(time_ticks)); + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks)); gfx::Size tile_size(100, 100); gfx::Size layer_bounds(400, 400); @@ -468,7 +468,7 @@ // Should update viewport and transform, but not update visible rect. time_ticks += base::TimeDelta::FromMilliseconds(200); host_impl_.SetCurrentBeginFrameArgs( - CreateBeginFrameArgsForTesting(time_ticks)); + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks)); resourceless_software_draw = true; viewport = gfx::ScaleToEnclosingRect(viewport, 2); transform.Translate(1.f, 1.f); @@ -492,7 +492,7 @@ // Keep expanded viewport but mark it valid. Should update tile viewport. time_ticks += base::TimeDelta::FromMilliseconds(200); host_impl_.SetCurrentBeginFrameArgs( - CreateBeginFrameArgsForTesting(time_ticks)); + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks)); resourceless_software_draw = false; host_impl_.SetExternalDrawConstraints(transform, viewport, @@ -1561,7 +1561,7 @@ base::TimeTicks time_ticks; time_ticks += base::TimeDelta::FromMilliseconds(1); host_impl_.SetCurrentBeginFrameArgs( - CreateBeginFrameArgsForTesting(time_ticks)); + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks)); pending_layer_->UpdateTiles(Occlusion(), resourceless_software_draw); EXPECT_EQ(HIGH_RESOLUTION, tiling->resolution()); @@ -1589,7 +1589,7 @@ base::TimeTicks time_ticks; time_ticks += base::TimeDelta::FromMilliseconds(1); host_impl_.SetCurrentBeginFrameArgs( - CreateBeginFrameArgsForTesting(time_ticks)); + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks)); gfx::Size tile_size(100, 100); gfx::Size layer_bounds(400, 400); @@ -1625,7 +1625,7 @@ pending_layer_->draw_properties().visible_content_rect = visible_content_rect; time_ticks += base::TimeDelta::FromMilliseconds(200); host_impl_.SetCurrentBeginFrameArgs( - CreateBeginFrameArgsForTesting(time_ticks)); + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks)); pending_layer_->UpdateTiles(Occlusion(), resourceless_software_draw); // Intersect the two rects. Any tile outside should not be required for @@ -1678,7 +1678,7 @@ base::TimeTicks time_ticks; time_ticks += base::TimeDelta::FromMilliseconds(1); host_impl_.SetCurrentBeginFrameArgs( - CreateBeginFrameArgsForTesting(time_ticks)); + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks)); gfx::Size tile_size(100, 100); gfx::Size layer_bounds(200, 200); @@ -1714,7 +1714,7 @@ base::TimeTicks time_ticks; time_ticks += base::TimeDelta::FromMilliseconds(1); host_impl_.SetCurrentBeginFrameArgs( - CreateBeginFrameArgsForTesting(time_ticks)); + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks)); gfx::Size tile_size(100, 100); gfx::Size layer_bounds(200, 200); @@ -1745,7 +1745,7 @@ base::TimeTicks time_ticks; time_ticks += base::TimeDelta::FromMilliseconds(1); host_impl_.SetCurrentBeginFrameArgs( - CreateBeginFrameArgsForTesting(time_ticks)); + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks)); gfx::Size tile_size(100, 100); gfx::Size layer_bounds(200, 200); @@ -1779,7 +1779,7 @@ base::TimeTicks time_ticks; time_ticks += base::TimeDelta::FromMilliseconds(1); host_impl_.SetCurrentBeginFrameArgs( - CreateBeginFrameArgsForTesting(time_ticks)); + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks)); gfx::Size tile_size(100, 100); gfx::Size layer_bounds(200, 200); @@ -1822,7 +1822,7 @@ base::TimeTicks time_ticks; time_ticks += base::TimeDelta::FromMilliseconds(1); host_impl_.SetCurrentBeginFrameArgs( - CreateBeginFrameArgsForTesting(time_ticks)); + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks)); gfx::Size tile_size(100, 100); gfx::Size layer_bounds(200, 200); @@ -1890,6 +1890,9 @@ TEST_F(PictureLayerImplTest, HighResRequiredWhenUnsharedActiveAllReady) { gfx::Size layer_bounds(400, 400); gfx::Size tile_size(100, 100); + + host_impl_.SetViewportSize(layer_bounds); + SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size); // No tiles shared. @@ -1911,6 +1914,9 @@ TEST_F(PictureLayerImplTest, HighResRequiredWhenMissingHighResFlagOn) { gfx::Size layer_bounds(400, 400); gfx::Size tile_size(100, 100); + + host_impl_.SetViewportSize(layer_bounds); + SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size); // All tiles shared (no invalidation). @@ -1935,6 +1941,9 @@ TEST_F(PictureLayerImplTest, AllHighResRequiredEvenIfShared) { gfx::Size layer_bounds(400, 400); gfx::Size tile_size(100, 100); + + host_impl_.SetViewportSize(layer_bounds); + SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size); CreateHighLowResAndSetAllTilesVisible(); @@ -2009,6 +2018,9 @@ TEST_F(PictureLayerImplTest, HighResRequiredIfActiveCantHaveTiles) { gfx::Size layer_bounds(400, 400); gfx::Size tile_size(100, 100); + + host_impl_.SetViewportSize(layer_bounds); + scoped_refptr<FakePicturePileImpl> pending_pile = FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); scoped_refptr<FakePicturePileImpl> active_pile = @@ -2767,7 +2779,7 @@ base::TimeTicks time_ticks; time_ticks += base::TimeDelta::FromMilliseconds(1); host_impl_.SetCurrentBeginFrameArgs( - CreateBeginFrameArgsForTesting(time_ticks)); + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks)); gfx::Size tile_size(100, 100); gfx::Size layer_bounds(1000, 1000); @@ -2837,7 +2849,7 @@ // No NOW tiles. time_ticks += base::TimeDelta::FromMilliseconds(200); host_impl_.SetCurrentBeginFrameArgs( - CreateBeginFrameArgsForTesting(time_ticks)); + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks)); pending_layer_->draw_properties().visible_content_rect = gfx::Rect(1100, 1100, 500, 500); @@ -2868,7 +2880,7 @@ time_ticks += base::TimeDelta::FromMilliseconds(200); host_impl_.SetCurrentBeginFrameArgs( - CreateBeginFrameArgsForTesting(time_ticks)); + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks)); pending_layer_->draw_properties().visible_content_rect = gfx::Rect(0, 0, 500, 500); @@ -3151,6 +3163,8 @@ gfx::Size tile_size(100, 100); gfx::Size layer_bounds(1000, 1000); + host_impl_.SetViewportSize(layer_bounds); + SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size); // Make sure some tiles are not shared. @@ -3178,6 +3192,8 @@ gfx::Size tile_size(100, 100); gfx::Size layer_bounds(1000, 1000); + host_impl_.SetViewportSize(layer_bounds); + SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size); // Make sure some tiles are not shared. @@ -3201,6 +3217,8 @@ gfx::Size tile_size(100, 100); gfx::Size layer_bounds(1000, 1000); + host_impl_.SetViewportSize(layer_bounds); + SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size); // Make sure some tiles are not shared. @@ -3225,6 +3243,8 @@ gfx::Size tile_size(100, 100); gfx::Size layer_bounds(1000, 1000); + host_impl_.SetViewportSize(layer_bounds); + SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size); // Make sure some tiles are not shared. @@ -3312,6 +3332,9 @@ TEST_F(NoLowResPictureLayerImplTest, AllHighResRequiredEvenIfShared) { gfx::Size layer_bounds(400, 400); gfx::Size tile_size(100, 100); + + host_impl_.SetViewportSize(layer_bounds); + SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size); CreateHighLowResAndSetAllTilesVisible(); @@ -3370,7 +3393,7 @@ base::TimeTicks time_ticks; time_ticks += base::TimeDelta::FromMilliseconds(1); host_impl_.SetCurrentBeginFrameArgs( - CreateBeginFrameArgsForTesting(time_ticks)); + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks)); gfx::Size tile_size(100, 100); gfx::Size layer_bounds(400, 400); @@ -3412,7 +3435,7 @@ // Should update viewport and transform, but not update visible rect. time_ticks += base::TimeDelta::FromMilliseconds(200); host_impl_.SetCurrentBeginFrameArgs( - CreateBeginFrameArgsForTesting(time_ticks)); + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks)); resourceless_software_draw = true; viewport = gfx::ScaleToEnclosingRect(viewport, 2); transform.Translate(1.f, 1.f); @@ -3436,7 +3459,7 @@ // Keep expanded viewport but mark it valid. Should update tile viewport. time_ticks += base::TimeDelta::FromMilliseconds(200); host_impl_.SetCurrentBeginFrameArgs( - CreateBeginFrameArgsForTesting(time_ticks)); + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks)); resourceless_software_draw = false; host_impl_.SetExternalDrawConstraints(transform, viewport, @@ -3673,6 +3696,8 @@ gfx::Size tile_size(400, 400); gfx::Size layer_bounds(1000, 2000); + host_impl_.SetViewportSize(layer_bounds); + scoped_refptr<FakePicturePileImpl> pending_pile = FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); scoped_refptr<FakePicturePileImpl> active_pile = @@ -3881,7 +3906,7 @@ base::TimeTicks time_ticks; time_ticks += base::TimeDelta::FromMilliseconds(1); host_impl_.SetCurrentBeginFrameArgs( - CreateBeginFrameArgsForTesting(time_ticks)); + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks)); gfx::Size tile_size(102, 102); gfx::Size layer_bounds(1000, 1000); @@ -3927,7 +3952,7 @@ time_ticks += base::TimeDelta::FromMilliseconds(200); host_impl_.SetCurrentBeginFrameArgs( - CreateBeginFrameArgsForTesting(time_ticks)); + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks)); host_impl_.pending_tree()->UpdateDrawProperties(); unoccluded_tile_count = 0; @@ -3951,7 +3976,7 @@ time_ticks += base::TimeDelta::FromMilliseconds(200); host_impl_.SetCurrentBeginFrameArgs( - CreateBeginFrameArgsForTesting(time_ticks)); + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks)); host_impl_.pending_tree()->UpdateDrawProperties(); unoccluded_tile_count = 0; @@ -3976,7 +4001,7 @@ base::TimeTicks time_ticks; time_ticks += base::TimeDelta::FromMilliseconds(1); host_impl_.SetCurrentBeginFrameArgs( - CreateBeginFrameArgsForTesting(time_ticks)); + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks)); gfx::Size tile_size(102, 102); gfx::Size layer_bounds(1000, 1000); @@ -4027,7 +4052,7 @@ time_ticks += base::TimeDelta::FromMilliseconds(200); host_impl_.SetCurrentBeginFrameArgs( - CreateBeginFrameArgsForTesting(time_ticks)); + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks)); host_impl_.pending_tree()->UpdateDrawProperties(); for (size_t i = 0; i < pending_layer_->num_tilings(); ++i) { @@ -4067,7 +4092,7 @@ time_ticks += base::TimeDelta::FromMilliseconds(200); host_impl_.SetCurrentBeginFrameArgs( - CreateBeginFrameArgsForTesting(time_ticks)); + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks)); host_impl_.pending_tree()->UpdateDrawProperties(); for (size_t i = 0; i < pending_layer_->num_tilings(); ++i) { @@ -4496,7 +4521,7 @@ base::TimeTicks time_ticks; time_ticks += base::TimeDelta::FromMilliseconds(1); host_impl_.SetCurrentBeginFrameArgs( - CreateBeginFrameArgsForTesting(time_ticks)); + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks)); gfx::Size tile_size(100, 100); gfx::Size layer_bounds(200, 200); @@ -4563,7 +4588,7 @@ base::TimeTicks time_ticks; time_ticks += base::TimeDelta::FromMilliseconds(1); host_impl_.SetCurrentBeginFrameArgs( - CreateBeginFrameArgsForTesting(time_ticks)); + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks)); gfx::Size tile_size(100, 100); gfx::Size layer_bounds(200, 200); @@ -4620,7 +4645,7 @@ base::TimeTicks time_ticks; time_ticks += base::TimeDelta::FromMilliseconds(1); host_impl_.SetCurrentBeginFrameArgs( - CreateBeginFrameArgsForTesting(time_ticks)); + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks)); gfx::Size tile_size(100, 100); gfx::Size layer_bounds(400, 4000);
diff --git a/cc/layers/tiled_layer_unittest.cc b/cc/layers/tiled_layer_unittest.cc index 908d428b..512fa51 100644 --- a/cc/layers/tiled_layer_unittest.cc +++ b/cc/layers/tiled_layer_unittest.cc
@@ -261,6 +261,8 @@ }; TEST_F(TiledLayerTest, PushDirtyTiles) { + layer_tree_host_->SetViewportSize(gfx::Size(1000, 1000)); + scoped_refptr<FakeTiledLayer> layer = make_scoped_refptr(new FakeTiledLayer(resource_manager_.get())); scoped_ptr<FakeTiledLayerImpl> layer_impl = @@ -290,6 +292,8 @@ } TEST_F(TiledLayerTest, Scale) { + layer_tree_host_->SetViewportSize(gfx::Size(1000, 1000)); + layer_tree_host_->SetDeviceScaleFactor(1.5); scoped_refptr<FakeTiledLayer> layer = @@ -352,6 +356,8 @@ } TEST_F(TiledLayerTest, PushDeletedTiles) { + layer_tree_host_->SetViewportSize(gfx::Size(1000, 1000)); + scoped_refptr<FakeTiledLayer> layer = make_scoped_refptr(new FakeTiledLayer(resource_manager_.get())); scoped_ptr<FakeTiledLayerImpl> layer_impl = @@ -1201,6 +1207,8 @@ } TEST_F(TiledLayerTest, TilesPaintedWithoutOcclusion) { + layer_tree_host_->SetViewportSize(gfx::Size(1000, 1000)); + scoped_refptr<FakeTiledLayer> layer = make_scoped_refptr(new FakeTiledLayer(resource_manager_.get())); RenderSurfaceLayerList render_surface_layer_list;
diff --git a/cc/output/begin_frame_args.cc b/cc/output/begin_frame_args.cc index 0be9318..5744d9d 100644 --- a/cc/output/begin_frame_args.cc +++ b/cc/output/begin_frame_args.cc
@@ -41,12 +41,19 @@ type(type) { } -BeginFrameArgs BeginFrameArgs::Create(base::TimeTicks frame_time, +BeginFrameArgs BeginFrameArgs::Create(BeginFrameArgs::CreationLocation location, + base::TimeTicks frame_time, base::TimeTicks deadline, base::TimeDelta interval, BeginFrameArgs::BeginFrameArgsType type) { DCHECK_NE(type, BeginFrameArgs::INVALID); +#ifdef NDEBUG return BeginFrameArgs(frame_time, deadline, interval, type); +#else + BeginFrameArgs args = BeginFrameArgs(frame_time, deadline, interval, type); + args.created_from = location; + return args; +#endif } scoped_refptr<base::debug::ConvertableToTraceFormat> BeginFrameArgs::AsValue() @@ -63,6 +70,9 @@ state->SetDouble("frame_time_us", frame_time.ToInternalValue()); state->SetDouble("deadline_us", deadline.ToInternalValue()); state->SetDouble("interval_us", interval.InMicroseconds()); +#ifndef NDEBUG + state->SetString("created_from", created_from.ToString()); +#endif } // This is a hard-coded deadline adjustment that assumes 60Hz, to be used in
diff --git a/cc/output/begin_frame_args.h b/cc/output/begin_frame_args.h index 0be5241d..ba29523 100644 --- a/cc/output/begin_frame_args.h +++ b/cc/output/begin_frame_args.h
@@ -5,6 +5,7 @@ #ifndef CC_OUTPUT_BEGIN_FRAME_ARGS_H_ #define CC_OUTPUT_BEGIN_FRAME_ARGS_H_ +#include "base/location.h" #include "base/memory/ref_counted.h" #include "base/time/time.h" #include "base/values.h" @@ -17,6 +18,22 @@ } } +/** + * In debug builds we trace the creation origin of BeginFrameArgs objects. We + * reuse the tracked_objects::Location system to do that. + * + * However, in release builds we don't want this as it doubles the size of the + * BeginFrameArgs object. As well it adds a number of largish strings to the + * binary. Despite the argument being unused, most compilers are unable to + * optimise it away even when unused. Instead we use the BEGINFRAME_FROM_HERE + * macro to prevent the data even getting referenced. + */ +#ifdef NDEBUG +#define BEGINFRAME_FROM_HERE nullptr +#else +#define BEGINFRAME_FROM_HERE FROM_HERE +#endif + namespace cc { struct CC_EXPORT BeginFrameArgs { @@ -31,9 +48,18 @@ // Creates an invalid set of values. BeginFrameArgs(); +#ifdef NDEBUG + typedef const void* CreationLocation; +#else + typedef const tracked_objects::Location& CreationLocation; + tracked_objects::Location created_from; +#endif + // You should be able to find all instances where a BeginFrame has been // created by searching for "BeginFrameArgs::Create". - static BeginFrameArgs Create(base::TimeTicks frame_time, + // The location argument should **always** be BEGINFRAME_FROM_HERE macro. + static BeginFrameArgs Create(CreationLocation location, + base::TimeTicks frame_time, base::TimeTicks deadline, base::TimeDelta interval, BeginFrameArgsType type);
diff --git a/cc/output/begin_frame_args_unittest.cc b/cc/output/begin_frame_args_unittest.cc index 9d77a45d..877a857 100644 --- a/cc/output/begin_frame_args_unittest.cc +++ b/cc/output/begin_frame_args_unittest.cc
@@ -15,26 +15,29 @@ TEST(BeginFrameArgsTest, Helpers) { // Quick create methods work - BeginFrameArgs args0 = CreateBeginFrameArgsForTesting(); + BeginFrameArgs args0 = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE); EXPECT_TRUE(args0.IsValid()) << args0; - BeginFrameArgs args1 = CreateBeginFrameArgsForTesting(0, 0, -1); + BeginFrameArgs args1 = + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 0, -1); EXPECT_FALSE(args1.IsValid()) << args1; - BeginFrameArgs args2 = CreateBeginFrameArgsForTesting(1, 2, 3); + BeginFrameArgs args2 = + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 1, 2, 3); EXPECT_TRUE(args2.IsValid()) << args2; EXPECT_EQ(1, args2.frame_time.ToInternalValue()); EXPECT_EQ(2, args2.deadline.ToInternalValue()); EXPECT_EQ(3, args2.interval.ToInternalValue()); EXPECT_EQ(BeginFrameArgs::NORMAL, args2.type); - BeginFrameArgs args3 = CreateExpiredBeginFrameArgsForTesting(); + BeginFrameArgs args3 = + CreateExpiredBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE); EXPECT_TRUE(args3.IsValid()) << args3; EXPECT_GT(gfx::FrameTime::Now(), args3.deadline); EXPECT_EQ(BeginFrameArgs::NORMAL, args3.type); - BeginFrameArgs args4 = - CreateBeginFrameArgsForTesting(1, 2, 3, BeginFrameArgs::MISSED); + BeginFrameArgs args4 = CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, 1, 2, 3, BeginFrameArgs::MISSED); EXPECT_TRUE(args4.IsValid()) << args4; EXPECT_EQ(1, args4.frame_time.ToInternalValue()); EXPECT_EQ(2, args4.deadline.ToInternalValue()); @@ -42,16 +45,19 @@ EXPECT_EQ(BeginFrameArgs::MISSED, args4.type); // operator== - EXPECT_EQ(CreateBeginFrameArgsForTesting(4, 5, 6), - CreateBeginFrameArgsForTesting(4, 5, 6)); + EXPECT_EQ(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 4, 5, 6), + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 4, 5, 6)); EXPECT_NONFATAL_FAILURE( - EXPECT_EQ(CreateBeginFrameArgsForTesting(7, 8, 9, BeginFrameArgs::MISSED), - CreateBeginFrameArgsForTesting(7, 8, 9)), + EXPECT_EQ(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 7, 8, 9, + BeginFrameArgs::MISSED), + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 7, 8, 9)), ""); - EXPECT_NONFATAL_FAILURE(EXPECT_EQ(CreateBeginFrameArgsForTesting(4, 5, 6), - CreateBeginFrameArgsForTesting(7, 8, 9)), - ""); + + EXPECT_NONFATAL_FAILURE( + EXPECT_EQ(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 4, 5, 6), + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 7, 8, 9)), + ""); // operator<< std::stringstream out1; @@ -74,7 +80,7 @@ EXPECT_FALSE(args1.IsValid()) << args1; BeginFrameArgs args2 = BeginFrameArgs::Create( - base::TimeTicks::FromInternalValue(1), + BEGINFRAME_FROM_HERE, base::TimeTicks::FromInternalValue(1), base::TimeTicks::FromInternalValue(2), base::TimeDelta::FromInternalValue(3), BeginFrameArgs::NORMAL); EXPECT_TRUE(args2.IsValid()) << args2; @@ -84,5 +90,14 @@ EXPECT_EQ(BeginFrameArgs::NORMAL, args2.type) << args2; } +#ifndef NDEBUG +TEST(BeginFrameArgsTest, Location) { + tracked_objects::Location expected_location = BEGINFRAME_FROM_HERE; + + BeginFrameArgs args = CreateBeginFrameArgsForTesting(expected_location); + EXPECT_EQ(expected_location.ToString(), args.created_from.ToString()); +} +#endif + } // namespace } // namespace cc
diff --git a/cc/output/renderer_settings.cc b/cc/output/renderer_settings.cc index bacde5b..2277af3e 100644 --- a/cc/output/renderer_settings.cc +++ b/cc/output/renderer_settings.cc
@@ -15,6 +15,7 @@ force_antialiasing(false), force_blending_with_shaders(false), partial_swap_enabled(false), + finish_rendering_on_resize(false), should_clear_root_render_pass(true), refresh_rate(60.0), highp_threshold_min(0),
diff --git a/cc/output/renderer_settings.h b/cc/output/renderer_settings.h index 748d230..6da0238 100644 --- a/cc/output/renderer_settings.h +++ b/cc/output/renderer_settings.h
@@ -19,6 +19,7 @@ bool force_antialiasing; bool force_blending_with_shaders; bool partial_swap_enabled; + bool finish_rendering_on_resize; bool should_clear_root_render_pass; double refresh_rate; int highp_threshold_min;
diff --git a/cc/resources/clip_display_item.cc b/cc/resources/clip_display_item.cc index 9277eea..731c6059 100644 --- a/cc/resources/clip_display_item.cc +++ b/cc/resources/clip_display_item.cc
@@ -40,6 +40,14 @@ return 1; } +size_t ClipDisplayItem::PictureMemoryUsage() const { + size_t total_size = sizeof(gfx::Rect); + for (size_t i = 0; i < rounded_clip_rects_.size(); ++i) { + total_size += sizeof(rounded_clip_rects_[i]); + } + return total_size; +} + EndClipDisplayItem::EndClipDisplayItem() { } @@ -59,4 +67,8 @@ return 0; } +size_t EndClipDisplayItem::PictureMemoryUsage() const { + return 0; +} + } // namespace cc
diff --git a/cc/resources/clip_display_item.h b/cc/resources/clip_display_item.h index 82deefd..55c1ffd 100644 --- a/cc/resources/clip_display_item.h +++ b/cc/resources/clip_display_item.h
@@ -32,6 +32,7 @@ bool IsSuitableForGpuRasterization() const override; int ApproximateOpCount() const override; + size_t PictureMemoryUsage() const override; protected: ClipDisplayItem(gfx::Rect clip_rect, @@ -54,6 +55,7 @@ bool IsSuitableForGpuRasterization() const override; int ApproximateOpCount() const override; + size_t PictureMemoryUsage() const override; protected: EndClipDisplayItem();
diff --git a/cc/resources/display_item.h b/cc/resources/display_item.h index e0802676..6f1b5f75 100644 --- a/cc/resources/display_item.h +++ b/cc/resources/display_item.h
@@ -23,6 +23,7 @@ virtual bool IsSuitableForGpuRasterization() const = 0; virtual int ApproximateOpCount() const = 0; + virtual size_t PictureMemoryUsage() const = 0; protected: DisplayItem();
diff --git a/cc/resources/display_item_list.cc b/cc/resources/display_item_list.cc index bd93e49..2ead28d0 100644 --- a/cc/resources/display_item_list.cc +++ b/cc/resources/display_item_list.cc
@@ -49,6 +49,16 @@ return approximate_op_count_; } +size_t DisplayItemList::PictureMemoryUsage() const { + size_t total_size = 0; + + for (const auto& item : items_) { + total_size += item->PictureMemoryUsage(); + } + + return total_size; +} + scoped_refptr<base::debug::ConvertableToTraceFormat> DisplayItemList::AsValue() const { scoped_refptr<base::debug::TracedValue> state =
diff --git a/cc/resources/display_item_list.h b/cc/resources/display_item_list.h index fe258806..10d052f 100644 --- a/cc/resources/display_item_list.h +++ b/cc/resources/display_item_list.h
@@ -31,6 +31,7 @@ bool IsSuitableForGpuRasterization() const; int ApproximateOpCount() const; + size_t PictureMemoryUsage() const; scoped_refptr<base::debug::ConvertableToTraceFormat> AsValue() const;
diff --git a/cc/resources/display_list_raster_source.cc b/cc/resources/display_list_raster_source.cc index 9f47e0e..f3ff8167 100644 --- a/cc/resources/display_list_raster_source.cc +++ b/cc/resources/display_list_raster_source.cc
@@ -119,6 +119,10 @@ return picture; } +size_t DisplayListRasterSource::GetPictureMemoryUsage() const { + return display_list_->PictureMemoryUsage(); +} + void DisplayListRasterSource::PerformSolidColorAnalysis( const gfx::Rect& content_rect, float contents_scale,
diff --git a/cc/resources/display_list_raster_source.h b/cc/resources/display_list_raster_source.h index 80f8868..8f1fd12 100644 --- a/cc/resources/display_list_raster_source.h +++ b/cc/resources/display_list_raster_source.h
@@ -52,6 +52,7 @@ void DidBeginTracing() override; void AsValueInto(base::debug::TracedValue* array) const override; skia::RefPtr<SkPicture> GetFlattenedPicture() override; + size_t GetPictureMemoryUsage() const override; bool CanUseLCDText() const override; protected:
diff --git a/cc/resources/drawing_display_item.cc b/cc/resources/drawing_display_item.cc index 94e3787..ecf7a754 100644 --- a/cc/resources/drawing_display_item.cc +++ b/cc/resources/drawing_display_item.cc
@@ -7,6 +7,7 @@ #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkMatrix.h" #include "third_party/skia/include/core/SkPicture.h" +#include "third_party/skia/include/utils/SkPictureUtils.h" namespace cc { @@ -34,7 +35,12 @@ } int DrawingDisplayItem::ApproximateOpCount() const { - return picture_->approximateOpCount(); + return picture_->approximateOpCount() + sizeof(gfx::PointF); +} + +size_t DrawingDisplayItem::PictureMemoryUsage() const { + DCHECK(picture_); + return SkPictureUtils::ApproximateBytesUsed(picture_.get()); } } // namespace cc
diff --git a/cc/resources/drawing_display_item.h b/cc/resources/drawing_display_item.h index 672a417..544e4eb 100644 --- a/cc/resources/drawing_display_item.h +++ b/cc/resources/drawing_display_item.h
@@ -30,6 +30,7 @@ bool IsSuitableForGpuRasterization() const override; int ApproximateOpCount() const override; + size_t PictureMemoryUsage() const override; protected: DrawingDisplayItem(skia::RefPtr<SkPicture> picture, gfx::PointF location);
diff --git a/cc/resources/filter_display_item.cc b/cc/resources/filter_display_item.cc index a2c29c9..63bfeee9 100644 --- a/cc/resources/filter_display_item.cc +++ b/cc/resources/filter_display_item.cc
@@ -44,6 +44,10 @@ return 1; } +size_t FilterDisplayItem::PictureMemoryUsage() const { + return sizeof(skia::RefPtr<SkImageFilter>) + sizeof(gfx::RectF); +} + EndFilterDisplayItem::EndFilterDisplayItem() { } @@ -64,4 +68,8 @@ return 0; } +size_t EndFilterDisplayItem::PictureMemoryUsage() const { + return 0; +} + } // namespace cc
diff --git a/cc/resources/filter_display_item.h b/cc/resources/filter_display_item.h index 3c8c669..4c1b2651 100644 --- a/cc/resources/filter_display_item.h +++ b/cc/resources/filter_display_item.h
@@ -31,6 +31,7 @@ bool IsSuitableForGpuRasterization() const override; int ApproximateOpCount() const override; + size_t PictureMemoryUsage() const override; protected: FilterDisplayItem(skia::RefPtr<SkImageFilter> filter, gfx::RectF bounds); @@ -52,6 +53,7 @@ bool IsSuitableForGpuRasterization() const override; int ApproximateOpCount() const override; + size_t PictureMemoryUsage() const override; protected: EndFilterDisplayItem();
diff --git a/cc/resources/picture.cc b/cc/resources/picture.cc index 9a45ad1..5b90571 100644 --- a/cc/resources/picture.cc +++ b/cc/resources/picture.cc
@@ -25,6 +25,7 @@ #include "third_party/skia/include/core/SkPictureRecorder.h" #include "third_party/skia/include/core/SkStream.h" #include "third_party/skia/include/utils/SkNullCanvas.h" +#include "third_party/skia/include/utils/SkPictureUtils.h" #include "ui/gfx/codec/jpeg_codec.h" #include "ui/gfx/codec/png_codec.h" #include "ui/gfx/geometry/rect_conversions.h" @@ -192,6 +193,11 @@ return picture_->approximateOpCount(); } +size_t Picture::ApproximateMemoryUsage() const { + DCHECK(picture_); + return SkPictureUtils::ApproximateBytesUsed(picture_.get()); +} + bool Picture::HasText() const { DCHECK(picture_); return picture_->hasText();
diff --git a/cc/resources/picture.h b/cc/resources/picture.h index 1677309..771d715 100644 --- a/cc/resources/picture.h +++ b/cc/resources/picture.h
@@ -67,6 +67,7 @@ bool IsSuitableForGpuRasterization() const; int ApproximateOpCount() const; + size_t ApproximateMemoryUsage() const; bool HasText() const;
diff --git a/cc/resources/picture_pile_impl.cc b/cc/resources/picture_pile_impl.cc index 834f32d..5cd7bd6 100644 --- a/cc/resources/picture_pile_impl.cc +++ b/cc/resources/picture_pile_impl.cc
@@ -4,6 +4,7 @@ #include <algorithm> #include <limits> +#include <set> #include "base/debug/trace_event.h" #include "cc/base/region.h" @@ -267,6 +268,19 @@ return picture; } +size_t PicturePileImpl::GetPictureMemoryUsage() const { + // Place all pictures in a set to de-dupe. + size_t total_size = 0; + std::set<const Picture*> pictures_seen; + for (const auto& map_value : picture_map_) { + const Picture* picture = map_value.second.GetPicture(); + if (picture && pictures_seen.insert(picture).second) + total_size += picture->ApproximateMemoryUsage(); + } + + return total_size; +} + void PicturePileImpl::PerformSolidColorAnalysis( const gfx::Rect& content_rect, float contents_scale,
diff --git a/cc/resources/picture_pile_impl.h b/cc/resources/picture_pile_impl.h index d7d0399..3e0dd787 100644 --- a/cc/resources/picture_pile_impl.h +++ b/cc/resources/picture_pile_impl.h
@@ -67,6 +67,7 @@ void DidBeginTracing() override; void AsValueInto(base::debug::TracedValue* array) const override; skia::RefPtr<SkPicture> GetFlattenedPicture() override; + size_t GetPictureMemoryUsage() const override; // Iterator used to return SkPixelRefs from this picture pile. // Public for testing.
diff --git a/cc/resources/raster_source.h b/cc/resources/raster_source.h index 35844364..88c9962 100644 --- a/cc/resources/raster_source.h +++ b/cc/resources/raster_source.h
@@ -18,6 +18,8 @@ namespace cc { +class Picture; + class CC_EXPORT RasterSource : public base::RefCountedThreadSafe<RasterSource> { public: struct CC_EXPORT SolidColorAnalysis { @@ -92,6 +94,7 @@ virtual void DidBeginTracing() = 0; virtual void AsValueInto(base::debug::TracedValue* array) const = 0; virtual skia::RefPtr<SkPicture> GetFlattenedPicture() = 0; + virtual size_t GetPictureMemoryUsage() const = 0; // Return true if LCD anti-aliasing may be used when rastering text. virtual bool CanUseLCDText() const = 0;
diff --git a/cc/resources/raster_worker_pool.cc b/cc/resources/raster_worker_pool.cc index 4511f9d..ca951f6 100644 --- a/cc/resources/raster_worker_pool.cc +++ b/cc/resources/raster_worker_pool.cc
@@ -206,6 +206,7 @@ case LUMINANCE_8: case RGB_565: case ETC1: + case RED_8: return false; } NOTREACHED();
diff --git a/cc/resources/resource_format.cc b/cc/resources/resource_format.cc index 6cd0a93..45581b8 100644 --- a/cc/resources/resource_format.cc +++ b/cc/resources/resource_format.cc
@@ -17,6 +17,7 @@ case ALPHA_8: case LUMINANCE_8: case RGB_565: + case RED_8: NOTREACHED(); break; }
diff --git a/cc/resources/resource_format.h b/cc/resources/resource_format.h index b51ac7c..d785ab7 100644 --- a/cc/resources/resource_format.h +++ b/cc/resources/resource_format.h
@@ -19,7 +19,8 @@ LUMINANCE_8, RGB_565, ETC1, - RESOURCE_FORMAT_MAX = ETC1, + RED_8, + RESOURCE_FORMAT_MAX = RED_8, }; SkColorType ResourceFormatToSkColorType(ResourceFormat format);
diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc index 636e797..fe7cc00 100644 --- a/cc/resources/resource_provider.cc +++ b/cc/resources/resource_provider.cc
@@ -76,6 +76,7 @@ case LUMINANCE_8: case RGB_565: case ETC1: + case RED_8: NOTREACHED(); break; } @@ -94,6 +95,7 @@ case LUMINANCE_8: case RGB_565: case ETC1: + case RED_8: return false; } return false; @@ -125,6 +127,7 @@ case LUMINANCE_8: case RGB_565: case ETC1: + case RED_8: break; } NOTREACHED(); @@ -1216,6 +1219,7 @@ use_texture_format_bgra_(false), use_texture_usage_hint_(false), use_compressed_texture_etc1_(false), + yuv_resource_format_(LUMINANCE_8), max_texture_size_(0), best_texture_format_(RGBA_8888), use_rgba_4444_texture_format_(use_rgba_4444_texture_format), @@ -1254,6 +1258,7 @@ use_texture_format_bgra_ = caps.gpu.texture_format_bgra8888; use_texture_usage_hint_ = caps.gpu.texture_usage; use_compressed_texture_etc1_ = caps.gpu.texture_format_etc1; + yuv_resource_format_ = caps.gpu.texture_rg ? RED_8 : LUMINANCE_8; use_sync_query_ = caps.gpu.sync_query; GLES2Interface* gl = ContextGL();
diff --git a/cc/resources/resource_provider.h b/cc/resources/resource_provider.h index bfd3ebb..3a8d2e0 100644 --- a/cc/resources/resource_provider.h +++ b/cc/resources/resource_provider.h
@@ -99,6 +99,7 @@ return use_rgba_4444_texture_format_ ? RGBA_4444 : best_texture_format_; } ResourceFormat best_texture_format() const { return best_texture_format_; } + ResourceFormat yuv_resource_format() const { return yuv_resource_format_; } bool use_sync_query() const { return use_sync_query_; } size_t num_resources() const { return resources_.size(); } @@ -578,6 +579,7 @@ bool use_texture_format_bgra_; bool use_texture_usage_hint_; bool use_compressed_texture_etc1_; + ResourceFormat yuv_resource_format_; scoped_ptr<TextureUploader> texture_uploader_; int max_texture_size_; ResourceFormat best_texture_format_; @@ -610,6 +612,7 @@ return 16; case ALPHA_8: case LUMINANCE_8: + case RED_8: return 8; case ETC1: return 4; @@ -621,13 +624,14 @@ inline GLenum GLDataType(ResourceFormat format) { DCHECK_LE(format, RESOURCE_FORMAT_MAX); static const unsigned format_gl_data_type[RESOURCE_FORMAT_MAX + 1] = { - GL_UNSIGNED_BYTE, // RGBA_8888 - GL_UNSIGNED_SHORT_4_4_4_4, // RGBA_4444 - GL_UNSIGNED_BYTE, // BGRA_8888 - GL_UNSIGNED_BYTE, // ALPHA_8 - GL_UNSIGNED_BYTE, // LUMINANCE_8 - GL_UNSIGNED_SHORT_5_6_5, // RGB_565, - GL_UNSIGNED_BYTE // ETC1 + GL_UNSIGNED_BYTE, // RGBA_8888 + GL_UNSIGNED_SHORT_4_4_4_4, // RGBA_4444 + GL_UNSIGNED_BYTE, // BGRA_8888 + GL_UNSIGNED_BYTE, // ALPHA_8 + GL_UNSIGNED_BYTE, // LUMINANCE_8 + GL_UNSIGNED_SHORT_5_6_5, // RGB_565, + GL_UNSIGNED_BYTE, // ETC1 + GL_UNSIGNED_BYTE // RED_8 }; return format_gl_data_type[format]; } @@ -635,13 +639,14 @@ inline GLenum GLDataFormat(ResourceFormat format) { DCHECK_LE(format, RESOURCE_FORMAT_MAX); static const unsigned format_gl_data_format[RESOURCE_FORMAT_MAX + 1] = { - GL_RGBA, // RGBA_8888 - GL_RGBA, // RGBA_4444 - GL_BGRA_EXT, // BGRA_8888 - GL_ALPHA, // ALPHA_8 - GL_LUMINANCE, // LUMINANCE_8 - GL_RGB, // RGB_565 - GL_ETC1_RGB8_OES // ETC1 + GL_RGBA, // RGBA_8888 + GL_RGBA, // RGBA_4444 + GL_BGRA_EXT, // BGRA_8888 + GL_ALPHA, // ALPHA_8 + GL_LUMINANCE, // LUMINANCE_8 + GL_RGB, // RGB_565 + GL_ETC1_RGB8_OES, // ETC1 + GL_RED_EXT // RED_8 }; return format_gl_data_format[format]; }
diff --git a/cc/resources/texture_uploader_unittest.cc b/cc/resources/texture_uploader_unittest.cc index 72491727..b168962 100644 --- a/cc/resources/texture_uploader_unittest.cc +++ b/cc/resources/texture_uploader_unittest.cc
@@ -111,6 +111,14 @@ EXPECT_EQ(static_cast<unsigned>(GL_UNSIGNED_BYTE), type); bytes_per_pixel = 2; break; + case GL_RED_EXT: + EXPECT_EQ(static_cast<unsigned>(GL_UNSIGNED_BYTE), type); + bytes_per_pixel = 1; + break; + case GL_RG_EXT: + EXPECT_EQ(static_cast<unsigned>(GL_UNSIGNED_BYTE), type); + bytes_per_pixel = 2; + break; } // If NULL, we aren't checking texture contents. @@ -232,6 +240,15 @@ buffer[(i + 1) * 82 - 1] = 0x2; } UploadTexture(uploader.get(), LUMINANCE_8, gfx::Size(82, 86), buffer); + + // Upload a tightly packed 82x86 RED texture. + memset(buffer, 0, sizeof(buffer)); + for (int i = 0; i < 86; ++i) { + // Mark the beginning and end of each row, for the test. + buffer[i * 1 * 82] = 0x1; + buffer[(i + 1) * 82 - 1] = 0x2; + } + UploadTexture(uploader.get(), RED_8, gfx::Size(82, 86), buffer); } } // namespace
diff --git a/cc/resources/tile_manager_perftest.cc b/cc/resources/tile_manager_perftest.cc index 7b096bd..2204ab80 100644 --- a/cc/resources/tile_manager_perftest.cc +++ b/cc/resources/tile_manager_perftest.cc
@@ -400,7 +400,8 @@ timer_.Reset(); bool resourceless_software_draw = false; do { - BeginFrameArgs args = CreateBeginFrameArgsForTesting(); + BeginFrameArgs args = + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE); host_impl_.UpdateCurrentBeginFrameArgs(args); for (unsigned i = 0; i < layers.size(); ++i) { layers[i]->UpdateTiles(Occlusion(), resourceless_software_draw);
diff --git a/cc/resources/tile_manager_unittest.cc b/cc/resources/tile_manager_unittest.cc index 49a93d3..fdd876e 100644 --- a/cc/resources/tile_manager_unittest.cc +++ b/cc/resources/tile_manager_unittest.cc
@@ -149,7 +149,9 @@ }; TEST_F(TileManagerTilePriorityQueueTest, RasterTilePriorityQueue) { - SetupDefaultTrees(gfx::Size(1000, 1000)); + const gfx::Size layer_bounds(1000, 1000); + host_impl_.SetViewportSize(layer_bounds); + SetupDefaultTrees(layer_bounds); active_layer_->CreateDefaultTilingsAndTiles(); pending_layer_->CreateDefaultTilingsAndTiles(); @@ -391,7 +393,9 @@ } TEST_F(TileManagerTilePriorityQueueTest, EvictionTilePriorityQueue) { - SetupDefaultTrees(gfx::Size(1000, 1000)); + const gfx::Size layer_bounds(1000, 1000); + host_impl_.SetViewportSize(layer_bounds); + SetupDefaultTrees(layer_bounds); active_layer_->CreateDefaultTilingsAndTiles(); pending_layer_->CreateDefaultTilingsAndTiles(); @@ -560,6 +564,8 @@ gfx::Size tile_size(102, 102); gfx::Size layer_bounds(1000, 1000); + host_impl_.SetViewportSize(layer_bounds); + scoped_refptr<FakePicturePileImpl> pending_pile = FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); SetupPendingTree(pending_pile); @@ -768,7 +774,9 @@ } TEST_F(TileManagerTilePriorityQueueTest, RasterTilePriorityQueueEmptyLayers) { - SetupDefaultTrees(gfx::Size(1000, 1000)); + const gfx::Size layer_bounds(1000, 1000); + host_impl_.SetViewportSize(layer_bounds); + SetupDefaultTrees(layer_bounds); active_layer_->CreateDefaultTilingsAndTiles(); pending_layer_->CreateDefaultTilingsAndTiles(); @@ -815,7 +823,9 @@ } TEST_F(TileManagerTilePriorityQueueTest, EvictionTilePriorityQueueEmptyLayers) { - SetupDefaultTrees(gfx::Size(1000, 1000)); + const gfx::Size layer_bounds(1000, 1000); + host_impl_.SetViewportSize(layer_bounds); + SetupDefaultTrees(layer_bounds); active_layer_->CreateDefaultTilingsAndTiles(); pending_layer_->CreateDefaultTilingsAndTiles();
diff --git a/cc/resources/transform_display_item.cc b/cc/resources/transform_display_item.cc index 62528da0..c7f4d60 100644 --- a/cc/resources/transform_display_item.cc +++ b/cc/resources/transform_display_item.cc
@@ -30,6 +30,10 @@ return 1; } +size_t TransformDisplayItem::PictureMemoryUsage() const { + return sizeof(gfx::Transform); +} + EndTransformDisplayItem::EndTransformDisplayItem() { } @@ -49,4 +53,8 @@ return 0; } +size_t EndTransformDisplayItem::PictureMemoryUsage() const { + return 0; +} + } // namespace cc
diff --git a/cc/resources/transform_display_item.h b/cc/resources/transform_display_item.h index 9d289c2a..1671f49 100644 --- a/cc/resources/transform_display_item.h +++ b/cc/resources/transform_display_item.h
@@ -28,6 +28,7 @@ bool IsSuitableForGpuRasterization() const override; int ApproximateOpCount() const override; + size_t PictureMemoryUsage() const override; protected: explicit TransformDisplayItem(const gfx::Transform& transform); @@ -48,6 +49,7 @@ bool IsSuitableForGpuRasterization() const override; int ApproximateOpCount() const override; + size_t PictureMemoryUsage() const override; protected: EndTransformDisplayItem();
diff --git a/cc/resources/transparency_display_item.cc b/cc/resources/transparency_display_item.cc index 2d8d492..0401d90 100644 --- a/cc/resources/transparency_display_item.cc +++ b/cc/resources/transparency_display_item.cc
@@ -35,6 +35,10 @@ return 1; } +size_t TransparencyDisplayItem::PictureMemoryUsage() const { + return sizeof(float) + sizeof(SkXfermode::Mode); +} + EndTransparencyDisplayItem::EndTransparencyDisplayItem() { } @@ -54,4 +58,8 @@ return 0; } +size_t EndTransparencyDisplayItem::PictureMemoryUsage() const { + return 0; +} + } // namespace cc
diff --git a/cc/resources/transparency_display_item.h b/cc/resources/transparency_display_item.h index f0cc40bc..6766d91d 100644 --- a/cc/resources/transparency_display_item.h +++ b/cc/resources/transparency_display_item.h
@@ -31,6 +31,7 @@ bool IsSuitableForGpuRasterization() const override; int ApproximateOpCount() const override; + size_t PictureMemoryUsage() const override; protected: TransparencyDisplayItem(float opacity, SkXfermode::Mode blend_mode); @@ -52,6 +53,7 @@ bool IsSuitableForGpuRasterization() const override; int ApproximateOpCount() const override; + size_t PictureMemoryUsage() const override; protected: EndTransparencyDisplayItem();
diff --git a/cc/resources/video_resource_updater.cc b/cc/resources/video_resource_updater.cc index 7a775d9..2c9a688 100644 --- a/cc/resources/video_resource_updater.cc +++ b/cc/resources/video_resource_updater.cc
@@ -20,7 +20,6 @@ namespace { -const ResourceFormat kYUVResourceFormat = LUMINANCE_8; const ResourceFormat kRGBResourceFormat = RGBA_8888; class SyncPointClientImpl : public media::VideoFrame::SyncPointClient { @@ -40,6 +39,37 @@ } // namespace +VideoResourceUpdater::PlaneResource::PlaneResource( + unsigned int resource_id, + const gfx::Size& resource_size, + ResourceFormat resource_format, + gpu::Mailbox mailbox) + : resource_id(resource_id), + resource_size(resource_size), + resource_format(resource_format), + mailbox(mailbox), + frame_ptr(nullptr), + plane_index(0) { +} + +bool VideoResourceUpdater::PlaneResourceMatchesUniqueID( + const PlaneResource& plane_resource, + const media::VideoFrame* video_frame, + int plane_index) { + return plane_resource.frame_ptr == video_frame && + plane_resource.plane_index == plane_index && + plane_resource.timestamp == video_frame->timestamp(); +} + +void VideoResourceUpdater::SetPlaneResourceUniqueId( + const media::VideoFrame* video_frame, + int plane_index, + PlaneResource* plane_resource) { + plane_resource->frame_ptr = video_frame; + plane_resource->plane_index = plane_index; + plane_resource->timestamp = video_frame->timestamp(); +} + VideoFrameExternalResources::VideoFrameExternalResources() : type(NONE) {} VideoFrameExternalResources::~VideoFrameExternalResources() {} @@ -104,14 +134,12 @@ // each plane in the frame. static gfx::Size SoftwarePlaneDimension( const scoped_refptr<media::VideoFrame>& input_frame, - ResourceFormat output_resource_format, + bool software_compositor, size_t plane_index) { - if (output_resource_format == kYUVResourceFormat) { + if (!software_compositor) { return media::VideoFrame::PlaneSize( input_frame->format(), plane_index, input_frame->coded_size()); } - - DCHECK_EQ(output_resource_format, kRGBResourceFormat); return input_frame->coded_size(); } @@ -145,7 +173,8 @@ bool software_compositor = context_provider_ == NULL; - ResourceFormat output_resource_format = kYUVResourceFormat; + ResourceFormat output_resource_format = + resource_provider_->yuv_resource_format(); size_t output_plane_count = media::VideoFrame::NumPlanes(input_frame_format); // TODO(skaslev): If we're in software compositing mode, we do the YUV -> RGB @@ -163,7 +192,7 @@ for (size_t i = 0; i < output_plane_count; ++i) { gfx::Size output_plane_resource_size = - SoftwarePlaneDimension(video_frame, output_resource_format, i); + SoftwarePlaneDimension(video_frame, software_compositor, i); if (output_plane_resource_size.IsEmpty() || output_plane_resource_size.width() > max_resource_size || output_plane_resource_size.height() > max_resource_size) { @@ -171,57 +200,56 @@ break; } - ResourceProvider::ResourceId resource_id = 0; - gpu::Mailbox mailbox; - // Try recycle a previously-allocated resource. - for (size_t i = 0; i < recycled_resources_.size(); ++i) { - bool resource_matches = - recycled_resources_[i].resource_format == output_resource_format && - recycled_resources_[i].resource_size == output_plane_resource_size; - bool not_in_use = - !software_compositor || !resource_provider_->InUseByConsumer( - recycled_resources_[i].resource_id); - if (resource_matches && not_in_use) { - resource_id = recycled_resources_[i].resource_id; - mailbox = recycled_resources_[i].mailbox; - recycled_resources_.erase(recycled_resources_.begin() + i); - break; + auto recycled_it = recycled_resources_.end(); + for (auto it = recycled_resources_.begin(); it != recycled_resources_.end(); + ++it) { + const bool resource_matches = + it->resource_format == output_resource_format && + it->resource_size == output_plane_resource_size; + const bool in_use = software_compositor && + resource_provider_->InUseByConsumer(it->resource_id); + if (resource_matches && !in_use) { + // We found a recycled resource with the allocation size and format we + // are looking for. + recycled_it = it; + // Keep looking for a recycled resource that also contains the data we + // are planning to put in it. + if (PlaneResourceMatchesUniqueID(*it, video_frame.get(), i)) + break; } } - if (resource_id == 0) { - // TODO(danakj): Abstract out hw/sw resource create/delete from - // ResourceProvider and stop using ResourceProvider in this class. - resource_id = resource_provider_->CreateResource( - output_plane_resource_size, - GL_CLAMP_TO_EDGE, - ResourceProvider::TextureHintImmutable, - output_resource_format); - - DCHECK(mailbox.IsZero()); - - if (!software_compositor) { - DCHECK(context_provider_); - - gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); - - GLC(gl, gl->GenMailboxCHROMIUM(mailbox.name)); - ResourceProvider::ScopedWriteLockGL lock(resource_provider_, - resource_id); - GLC(gl, - gl->ProduceTextureDirectCHROMIUM( - lock.texture_id(), GL_TEXTURE_2D, mailbox.name)); - } - - if (resource_id) - all_resources_.push_back(resource_id); + // Check if we can avoid allocating a new resource. + if (recycled_it != recycled_resources_.end()) { + plane_resources.push_back(*recycled_it); + recycled_resources_.erase(recycled_it); + continue; } + // TODO(danakj): Abstract out hw/sw resource create/delete from + // ResourceProvider and stop using ResourceProvider in this class. + const ResourceProvider::ResourceId resource_id = + resource_provider_->CreateResource( + output_plane_resource_size, GL_CLAMP_TO_EDGE, + ResourceProvider::TextureHintImmutable, output_resource_format); if (resource_id == 0) { allocation_success = false; break; } + all_resources_.push_back(resource_id); + + gpu::Mailbox mailbox; + if (!software_compositor) { + DCHECK(context_provider_); + + gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); + + GLC(gl, gl->GenMailboxCHROMIUM(mailbox.name)); + ResourceProvider::ScopedWriteLockGL lock(resource_provider_, resource_id); + GLC(gl, gl->ProduceTextureDirectCHROMIUM(lock.texture_id(), GL_TEXTURE_2D, + mailbox.name)); + } DCHECK(software_compositor || !mailbox.IsZero()); plane_resources.push_back(PlaneResource(resource_id, @@ -243,26 +271,23 @@ DCHECK_EQ(plane_resources[0].resource_format, kRGBResourceFormat); DCHECK(plane_resources[0].mailbox.IsZero()); - if (!video_renderer_) - video_renderer_.reset(new media::SkCanvasVideoRenderer); + if (!PlaneResourceMatchesUniqueID(plane_resources[0], video_frame.get(), + 0)) { + // We need to transfer data from |video_frame| to the plane resource. + if (!video_renderer_) + video_renderer_.reset(new media::SkCanvasVideoRenderer); - { ResourceProvider::ScopedWriteLockSoftware lock( resource_provider_, plane_resources[0].resource_id); SkCanvas canvas(lock.sk_bitmap()); video_renderer_->Copy(video_frame, &canvas); + SetPlaneResourceUniqueId(video_frame.get(), 0, &plane_resources[0]); } - RecycleResourceData recycle_data = { - plane_resources[0].resource_id, - plane_resources[0].resource_size, - plane_resources[0].resource_format, - gpu::Mailbox() - }; external_resources.software_resources.push_back( plane_resources[0].resource_id); external_resources.software_release_callback = - base::Bind(&RecycleResource, AsWeakPtr(), recycle_data); + base::Bind(&RecycleResource, AsWeakPtr(), plane_resources[0]); external_resources.type = VideoFrameExternalResources::SOFTWARE_RESOURCE; return external_resources; @@ -270,32 +295,27 @@ for (size_t i = 0; i < plane_resources.size(); ++i) { // Update each plane's resource id with its content. - DCHECK_EQ(plane_resources[i].resource_format, kYUVResourceFormat); + DCHECK_EQ(plane_resources[i].resource_format, + resource_provider_->yuv_resource_format()); - const uint8_t* input_plane_pixels = video_frame->data(i); + if (!PlaneResourceMatchesUniqueID(plane_resources[i], video_frame.get(), + i)) { + // We need to transfer data from |video_frame| to the plane resource. + const uint8_t* input_plane_pixels = video_frame->data(i); - gfx::Rect image_rect(0, - 0, - video_frame->stride(i), - plane_resources[i].resource_size.height()); - gfx::Rect source_rect(plane_resources[i].resource_size); - resource_provider_->SetPixels(plane_resources[i].resource_id, - input_plane_pixels, - image_rect, - source_rect, - gfx::Vector2d()); - - RecycleResourceData recycle_data = { - plane_resources[i].resource_id, - plane_resources[i].resource_size, - plane_resources[i].resource_format, - plane_resources[i].mailbox - }; + gfx::Rect image_rect(0, 0, video_frame->stride(i), + plane_resources[i].resource_size.height()); + gfx::Rect source_rect(plane_resources[i].resource_size); + resource_provider_->SetPixels(plane_resources[i].resource_id, + input_plane_pixels, image_rect, source_rect, + gfx::Vector2d()); + SetPlaneResourceUniqueId(video_frame.get(), i, &plane_resources[i]); + } external_resources.mailboxes.push_back( TextureMailbox(plane_resources[i].mailbox, GL_TEXTURE_2D, 0)); external_resources.release_callbacks.push_back( - base::Bind(&RecycleResource, AsWeakPtr(), recycle_data)); + base::Bind(&RecycleResource, AsWeakPtr(), plane_resources[i])); } external_resources.type = VideoFrameExternalResources::YUV_RESOURCE; @@ -362,7 +382,7 @@ // static void VideoResourceUpdater::RecycleResource( base::WeakPtr<VideoResourceUpdater> updater, - RecycleResourceData data, + PlaneResource data, uint32 sync_point, bool lost_resource, BlockingTaskRunner* main_thread_task_runner) { @@ -385,16 +405,12 @@ // Drop recycled resources that are the wrong format. while (!updater->recycled_resources_.empty() && updater->recycled_resources_.back().resource_format != - data.resource_format) { + data.resource_format) { updater->DeleteResource(updater->recycled_resources_.back().resource_id); updater->recycled_resources_.pop_back(); } - PlaneResource recycled_resource(data.resource_id, - data.resource_size, - data.resource_format, - data.mailbox); - updater->recycled_resources_.push_back(recycled_resource); + updater->recycled_resources_.push_back(data); } } // namespace cc
diff --git a/cc/resources/video_resource_updater.h b/cc/resources/video_resource_updater.h index 99800b4c..38f6033 100644 --- a/cc/resources/video_resource_updater.h +++ b/cc/resources/video_resource_updater.h
@@ -10,6 +10,7 @@ #include "base/basictypes.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" +#include "base/time/time.h" #include "cc/base/cc_export.h" #include "cc/resources/release_callback_impl.h" #include "cc/resources/resource_format.h" @@ -77,17 +78,28 @@ gfx::Size resource_size; ResourceFormat resource_format; gpu::Mailbox mailbox; + // These last three members will be used for identifying the data stored in + // this resource, and uniquely identifies a media::VideoFrame plane. The + // frame pointer will only be used for pointer comparison, i.e. the + // underlying data will not be accessed. + const void* frame_ptr; + int plane_index; + base::TimeDelta timestamp; PlaneResource(unsigned resource_id, const gfx::Size& resource_size, ResourceFormat resource_format, - gpu::Mailbox mailbox) - : resource_id(resource_id), - resource_size(resource_size), - resource_format(resource_format), - mailbox(mailbox) {} + gpu::Mailbox mailbox); }; + static bool PlaneResourceMatchesUniqueID(const PlaneResource& plane_resource, + const media::VideoFrame* video_frame, + int plane_index); + + static void SetPlaneResourceUniqueId(const media::VideoFrame* video_frame, + int plane_index, + PlaneResource* plane_resource); + void DeleteResource(unsigned resource_id); bool VerifyFrame(const scoped_refptr<media::VideoFrame>& video_frame); VideoFrameExternalResources CreateForHardwarePlanes( @@ -95,14 +107,8 @@ VideoFrameExternalResources CreateForSoftwarePlanes( const scoped_refptr<media::VideoFrame>& video_frame); - struct RecycleResourceData { - unsigned resource_id; - gfx::Size resource_size; - ResourceFormat resource_format; - gpu::Mailbox mailbox; - }; static void RecycleResource(base::WeakPtr<VideoResourceUpdater> updater, - RecycleResourceData data, + PlaneResource data, uint32 sync_point, bool lost_resource, BlockingTaskRunner* main_thread_task_runner); @@ -117,6 +123,8 @@ scoped_ptr<media::SkCanvasVideoRenderer> video_renderer_; std::vector<unsigned> all_resources_; + // Recycle resources so that we can reduce the number of allocations and + // data transfers. std::vector<PlaneResource> recycled_resources_; DISALLOW_COPY_AND_ASSIGN(VideoResourceUpdater);
diff --git a/cc/resources/video_resource_updater_unittest.cc b/cc/resources/video_resource_updater_unittest.cc index c0a4af4..1e3481b 100644 --- a/cc/resources/video_resource_updater_unittest.cc +++ b/cc/resources/video_resource_updater_unittest.cc
@@ -17,11 +17,33 @@ namespace cc { namespace { +class WebGraphicsContext3DUploadCounter : public TestWebGraphicsContext3D { + public: + void texSubImage2D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + const void* pixels) override { + ++upload_count_; + } + + int UploadCount() { return upload_count_; } + void ResetUploadCount() { upload_count_ = 0; } + + private: + int upload_count_; +}; + class VideoResourceUpdaterTest : public testing::Test { protected: VideoResourceUpdaterTest() { - scoped_ptr<TestWebGraphicsContext3D> context3d = - TestWebGraphicsContext3D::Create(); + scoped_ptr<WebGraphicsContext3DUploadCounter> context3d( + new WebGraphicsContext3DUploadCounter()); + context3d_ = context3d.get(); output_surface3d_ = @@ -60,7 +82,7 @@ base::Closure()); // no_longer_needed_cb } - TestWebGraphicsContext3D* context3d_; + WebGraphicsContext3DUploadCounter* context3d_; FakeOutputSurfaceClient client_; scoped_ptr<FakeOutputSurface> output_surface3d_; scoped_ptr<TestSharedBitmapManager> shared_bitmap_manager_; @@ -77,5 +99,52 @@ EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type); } +TEST_F(VideoResourceUpdaterTest, ReuseResource) { + VideoResourceUpdater updater(output_surface3d_->context_provider(), + resource_provider3d_.get()); + scoped_refptr<media::VideoFrame> video_frame = CreateTestYUVVideoFrame(); + video_frame->set_timestamp(base::TimeDelta::FromSeconds(1234)); + + // Allocate the resources for a YUV video frame. + context3d_->ResetUploadCount(); + VideoFrameExternalResources resources = + updater.CreateExternalResourcesFromVideoFrame(video_frame); + EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type); + EXPECT_EQ(size_t(3), resources.mailboxes.size()); + EXPECT_EQ(size_t(3), resources.release_callbacks.size()); + // Expect exactly three texture uploads, one for each plane. + EXPECT_EQ(3, context3d_->UploadCount()); + + const ResourceProvider::ResourceId y_resource = + resource_provider3d_->CreateResourceFromTextureMailbox( + resources.mailboxes[media::VideoFrame::kYPlane], + SingleReleaseCallbackImpl::Create( + resources.release_callbacks[media::VideoFrame::kYPlane])); + const ResourceProvider::ResourceId u_resource = + resource_provider3d_->CreateResourceFromTextureMailbox( + resources.mailboxes[media::VideoFrame::kUPlane], + SingleReleaseCallbackImpl::Create( + resources.release_callbacks[media::VideoFrame::kUPlane])); + const ResourceProvider::ResourceId v_resource = + resource_provider3d_->CreateResourceFromTextureMailbox( + resources.mailboxes[media::VideoFrame::kVPlane], + SingleReleaseCallbackImpl::Create( + resources.release_callbacks[media::VideoFrame::kVPlane])); + + // Delete the resources. + resource_provider3d_->DeleteResource(y_resource); + resource_provider3d_->DeleteResource(u_resource); + resource_provider3d_->DeleteResource(v_resource); + + // Allocate resources for the same frame. + context3d_->ResetUploadCount(); + resources = updater.CreateExternalResourcesFromVideoFrame(video_frame); + EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type); + EXPECT_EQ(size_t(3), resources.mailboxes.size()); + EXPECT_EQ(size_t(3), resources.release_callbacks.size()); + // The data should be reused so expect no texture uploads. + EXPECT_EQ(0, context3d_->UploadCount()); +} + } // namespace } // namespace cc
diff --git a/cc/scheduler/begin_frame_source.cc b/cc/scheduler/begin_frame_source.cc index 5252dcc0..89b794e 100644 --- a/cc/scheduler/begin_frame_source.cc +++ b/cc/scheduler/begin_frame_source.cc
@@ -7,6 +7,7 @@ #include "base/auto_reset.h" #include "base/debug/trace_event.h" #include "base/debug/trace_event_argument.h" +#include "base/location.h" #include "base/logging.h" #include "base/strings/string_number_conversions.h" #include "cc/scheduler/delay_based_time_source.h" @@ -182,7 +183,7 @@ base::TimeTicks now = Now(); BeginFrameArgs args = BeginFrameArgs::Create( - now, now + BeginFrameArgs::DefaultInterval(), + BEGINFRAME_FROM_HERE, now, now + BeginFrameArgs::DefaultInterval(), BeginFrameArgs::DefaultInterval(), BeginFrameArgs::NORMAL); CallOnBeginFrame(args); } @@ -242,8 +243,8 @@ base::TimeTicks frame_time, BeginFrameArgs::BeginFrameArgsType type) { base::TimeTicks deadline = time_source_->NextTickTime(); - return BeginFrameArgs::Create(frame_time, deadline, time_source_->Interval(), - type); + return BeginFrameArgs::Create(BEGINFRAME_FROM_HERE, frame_time, deadline, + time_source_->Interval(), type); } // TimeSourceClient support
diff --git a/cc/scheduler/begin_frame_source_unittest.cc b/cc/scheduler/begin_frame_source_unittest.cc index 498d10b2..0972762c 100644 --- a/cc/scheduler/begin_frame_source_unittest.cc +++ b/cc/scheduler/begin_frame_source_unittest.cc
@@ -15,19 +15,18 @@ #include "testing/gtest/include/gtest/gtest.h" // Macros to help set up expected calls on the MockBeginFrameObserver. -#define EXPECT_BEGIN_FRAME_DROP(obs, frame_time, deadline, interval) \ - { \ - ::testing::Expectation exp = \ - EXPECT_CALL((obs), \ - OnBeginFrame(CreateBeginFrameArgsForTesting( \ - frame_time, deadline, interval))) \ - .InSequence((obs).sequence); \ +#define EXPECT_BEGIN_FRAME_DROP(obs, frame_time, deadline, interval) \ + { \ + ::testing::Expectation exp = \ + EXPECT_CALL((obs), OnBeginFrame(CreateBeginFrameArgsForTesting( \ + BEGINFRAME_FROM_HERE, frame_time, deadline, \ + interval))).InSequence((obs).sequence); \ } #define EXPECT_BEGIN_FRAME_USED(obs, frame_time, deadline, interval) \ { \ - BeginFrameArgs args = \ - CreateBeginFrameArgsForTesting(frame_time, deadline, interval); \ + BeginFrameArgs args = CreateBeginFrameArgsForTesting( \ + BEGINFRAME_FROM_HERE, frame_time, deadline, interval); \ ::testing::Expectation exp = \ EXPECT_CALL((obs), OnBeginFrame(args)).InSequence((obs).sequence); \ EXPECT_CALL((obs), LastUsedBeginFrameArgs()) \ @@ -38,15 +37,15 @@ // Macros to send BeginFrameArgs on a FakeBeginFrameSink (and verify resulting // observer behaviour). -#define SEND_BEGIN_FRAME(args_equal_to, source, frame_time, deadline, \ - interval) \ - { \ - BeginFrameArgs old_args = (source).TestLastUsedBeginFrameArgs(); \ - BeginFrameArgs new_args = \ - CreateBeginFrameArgsForTesting(frame_time, deadline, interval); \ - ASSERT_FALSE(old_args == new_args); \ - (source).TestOnBeginFrame(new_args); \ - EXPECT_EQ(args_equal_to, (source).TestLastUsedBeginFrameArgs()); \ +#define SEND_BEGIN_FRAME(args_equal_to, source, frame_time, deadline, \ + interval) \ + { \ + BeginFrameArgs old_args = (source).TestLastUsedBeginFrameArgs(); \ + BeginFrameArgs new_args = CreateBeginFrameArgsForTesting( \ + BEGINFRAME_FROM_HERE, frame_time, deadline, interval); \ + ASSERT_FALSE(old_args == new_args); \ + (source).TestOnBeginFrame(new_args); \ + EXPECT_EQ(args_equal_to, (source).TestLastUsedBeginFrameArgs()); \ } // When dropping LastUsedBeginFrameArgs **shouldn't** change. @@ -99,19 +98,25 @@ MockBeginFrameObserver::kDefaultBeginFrameArgs); obs.OnBeginFrame(CreateBeginFrameArgsForTesting( - 100, 200, 300)); // One call to LastUsedBeginFrameArgs - EXPECT_EQ(obs.LastUsedBeginFrameArgs(), - CreateBeginFrameArgsForTesting(100, 200, 300)); + BEGINFRAME_FROM_HERE, 100, 200, + 300)); // One call to LastUsedBeginFrameArgs + EXPECT_EQ( + obs.LastUsedBeginFrameArgs(), + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300)); obs.OnBeginFrame(CreateBeginFrameArgsForTesting( - 400, 600, 300)); // Multiple calls to LastUsedBeginFrameArgs - EXPECT_EQ(obs.LastUsedBeginFrameArgs(), - CreateBeginFrameArgsForTesting(400, 600, 300)); - EXPECT_EQ(obs.LastUsedBeginFrameArgs(), - CreateBeginFrameArgsForTesting(400, 600, 300)); + BEGINFRAME_FROM_HERE, 400, 600, + 300)); // Multiple calls to LastUsedBeginFrameArgs + EXPECT_EQ( + obs.LastUsedBeginFrameArgs(), + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 400, 600, 300)); + EXPECT_EQ( + obs.LastUsedBeginFrameArgs(), + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 400, 600, 300)); obs.OnBeginFrame(CreateBeginFrameArgsForTesting( - 700, 900, 300)); // No calls to LastUsedBeginFrameArgs + BEGINFRAME_FROM_HERE, 700, 900, + 300)); // No calls to LastUsedBeginFrameArgs } TEST(MockBeginFrameObserverTest, ExpectOnBeginFrameStatus) { @@ -125,28 +130,45 @@ MockBeginFrameObserver::kDefaultBeginFrameArgs); // Used - obs.OnBeginFrame(CreateBeginFrameArgsForTesting(100, 200, 300)); - EXPECT_EQ(obs.LastUsedBeginFrameArgs(), - CreateBeginFrameArgsForTesting(100, 200, 300)); + obs.OnBeginFrame( + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300)); + EXPECT_EQ( + obs.LastUsedBeginFrameArgs(), + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300)); // Dropped - obs.OnBeginFrame(CreateBeginFrameArgsForTesting(400, 600, 300)); - EXPECT_EQ(obs.LastUsedBeginFrameArgs(), - CreateBeginFrameArgsForTesting(100, 200, 300)); + obs.OnBeginFrame( + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 400, 600, 300)); + EXPECT_EQ( + obs.LastUsedBeginFrameArgs(), + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300)); // Dropped - obs.OnBeginFrame(CreateBeginFrameArgsForTesting(450, 650, 300)); - EXPECT_EQ(obs.LastUsedBeginFrameArgs(), - CreateBeginFrameArgsForTesting(100, 200, 300)); + obs.OnBeginFrame( + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 450, 650, 300)); + EXPECT_EQ( + obs.LastUsedBeginFrameArgs(), + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300)); // Used - obs.OnBeginFrame(CreateBeginFrameArgsForTesting(700, 900, 300)); - EXPECT_EQ(obs.LastUsedBeginFrameArgs(), - CreateBeginFrameArgsForTesting(700, 900, 300)); + obs.OnBeginFrame( + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 700, 900, 300)); + EXPECT_EQ( + obs.LastUsedBeginFrameArgs(), + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 700, 900, 300)); } const BeginFrameArgs MockBeginFrameObserver::kDefaultBeginFrameArgs = - CreateBeginFrameArgsForTesting(-1, -1, -1); + CreateBeginFrameArgsForTesting( +#ifdef NDEBUG + nullptr, +#else + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "MockBeginFrameObserver::kDefaultBeginFrameArgs"), +#endif + -1, + -1, + -1); // BeginFrameObserverMixIn testing --------------------------------------- class MockMinimalBeginFrameObserverMixIn : public BeginFrameObserverMixIn { @@ -168,25 +190,31 @@ EXPECT_DEATH({ obs.OnBeginFrame(BeginFrameArgs()); }, ""); #endif - BeginFrameArgs args1 = CreateBeginFrameArgsForTesting(100, 200, 300); + BeginFrameArgs args1 = + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300); EXPECT_CALL(obs, OnBeginFrameMixInDelegate(args1)).WillOnce(Return(true)); obs.OnBeginFrame(args1); EXPECT_EQ(args1, obs.LastUsedBeginFrameArgs()); EXPECT_EQ(0, obs.dropped_begin_frame_args()); #ifndef NDEBUG - EXPECT_DEATH( - { obs.OnBeginFrame(CreateBeginFrameArgsForTesting(50, 200, 300)); }, ""); + EXPECT_DEATH({ + obs.OnBeginFrame(CreateBeginFrameArgsForTesting( + BEGINFRAME_FROM_HERE, 50, 200, 300)); + }, + ""); #endif // Returning false shouldn't update the LastUsedBeginFrameArgs value. - BeginFrameArgs args2 = CreateBeginFrameArgsForTesting(200, 300, 400); + BeginFrameArgs args2 = + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 200, 300, 400); EXPECT_CALL(obs, OnBeginFrameMixInDelegate(args2)).WillOnce(Return(false)); obs.OnBeginFrame(args2); EXPECT_EQ(args1, obs.LastUsedBeginFrameArgs()); EXPECT_EQ(1, obs.dropped_begin_frame_args()); - BeginFrameArgs args3 = CreateBeginFrameArgsForTesting(150, 300, 400); + BeginFrameArgs args3 = + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 150, 300, 400); EXPECT_CALL(obs, OnBeginFrameMixInDelegate(args3)).WillOnce(Return(true)); obs.OnBeginFrame(args3); EXPECT_EQ(args3, obs.LastUsedBeginFrameArgs()); @@ -495,7 +523,8 @@ SetNeedsBeginFramesCallsOnBeginFrameWithMissedTick) { now_src_->SetNowMicroseconds(10010); EXPECT_CALL((*obs_), OnBeginFrame(CreateBeginFrameArgsForTesting( - 10000, 20000, 10000, BeginFrameArgs::MISSED))); + BEGINFRAME_FROM_HERE, 10000, 20000, 10000, + BeginFrameArgs::MISSED))); source_->SetNeedsBeginFrames(true); // Should cause the last tick to be sent // No tasks should need to be run for this to occur. }
diff --git a/cc/scheduler/scheduler_state_machine_unittest.cc b/cc/scheduler/scheduler_state_machine_unittest.cc index af6d83a..2e40b72e 100644 --- a/cc/scheduler/scheduler_state_machine_unittest.cc +++ b/cc/scheduler/scheduler_state_machine_unittest.cc
@@ -122,7 +122,8 @@ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); EXPECT_FALSE(state.BeginFrameNeeded()); - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame( + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadline(); @@ -140,7 +141,8 @@ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); EXPECT_FALSE(state.BeginFrameNeeded()); - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame( + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadline(); } @@ -158,7 +160,8 @@ EXPECT_TRUE(state.BeginFrameNeeded()); - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame( + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); } @@ -195,7 +198,7 @@ EXPECT_TRUE(state.BeginFrameNeeded()); // Commit to the pending tree. - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -211,7 +214,7 @@ // Verify that the next commit starts while there is still a pending tree. state.SetNeedsCommit(); - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -252,7 +255,7 @@ state.SetNeedsRedraw(true); EXPECT_TRUE(state.RedrawPending()); EXPECT_TRUE(state.BeginFrameNeeded()); - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadline(); @@ -269,7 +272,7 @@ // Failing the draw makes us require a commit. state.DidDrawIfPossibleCompleted(DRAW_ABORTED_CHECKERBOARD_ANIMATIONS); - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); @@ -289,7 +292,7 @@ EXPECT_TRUE(state.RedrawPending()); EXPECT_TRUE(state.BeginFrameNeeded()); - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadline(); @@ -303,7 +306,7 @@ // Missing high res content requires a commit (but not a redraw) state.DidDrawIfPossibleCompleted(DRAW_ABORTED_MISSING_HIGH_RES_CONTENT); - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); EXPECT_FALSE(state.RedrawPending()); @@ -323,7 +326,7 @@ state.SetNeedsRedraw(true); EXPECT_TRUE(state.RedrawPending()); EXPECT_TRUE(state.BeginFrameNeeded()); - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadline(); @@ -344,7 +347,7 @@ // Failing the draw for animation checkerboards makes us require a commit. state.DidDrawIfPossibleCompleted(DRAW_ABORTED_CHECKERBOARD_ANIMATIONS); - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); @@ -365,7 +368,7 @@ // Start a commit. state.SetNeedsCommit(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -395,7 +398,7 @@ EXPECT_TRUE(state.RedrawPending()); // The redraw should be forced at the end of the next BeginImplFrame. - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); @@ -423,7 +426,7 @@ // Start a commit. state.SetNeedsCommit(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -480,7 +483,7 @@ // Start a draw. state.SetNeedsRedraw(true); EXPECT_TRUE(state.BeginFrameNeeded()); - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadline(); @@ -497,7 +500,7 @@ // We should not be trying to draw again now, but we have a commit pending. EXPECT_TRUE(state.BeginFrameNeeded()); - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -523,7 +526,7 @@ // Draw the first frame. EXPECT_TRUE(state.BeginFrameNeeded()); - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -542,7 +545,7 @@ // Move to another frame. This should now draw. EXPECT_TRUE(state.BeginFrameNeeded()); - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -680,7 +683,8 @@ state.SetVisible(false); state.SetNeedsRedraw(true); if (j == 1) - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame( + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); state.SetCanDraw(false); EXPECT_NE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE, @@ -702,7 +706,7 @@ state.SetNeedsRedraw(true); state.SetVisible(true); state.SetCanDraw(false); - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT); EXPECT_ACTION_UPDATE_STATE( @@ -730,7 +734,7 @@ EXPECT_TRUE(state.BeginFrameNeeded()); // Begin the frame. - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT, @@ -766,7 +770,7 @@ state.begin_impl_frame_state()); EXPECT_EQ(SchedulerStateMachine::ACTION_COMMIT, state.NextAction()); - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING, state.begin_impl_frame_state()); EXPECT_EQ(SchedulerStateMachine::ACTION_COMMIT, state.NextAction()); @@ -803,7 +807,7 @@ state.SetNeedsCommit(); // Begin the frame. - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT, @@ -853,7 +857,7 @@ state.SetNeedsCommit(); // Begin the frame. - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT, @@ -894,7 +898,7 @@ EXPECT_FALSE(state.needs_redraw()); // Next BeginImplFrame should initiate second commit. - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); } @@ -922,7 +926,7 @@ state.SetNeedsCommit(); // Begin the frame while visible. - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT, @@ -952,7 +956,7 @@ EXPECT_TRUE(state.NeedsCommit()); // Start a new frame. - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); @@ -991,7 +995,7 @@ // Start a new frame; draw because this is the first frame since output // surface init'd. - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadline(); @@ -1043,7 +1047,7 @@ // Become visible and start a new frame. state.SetVisible(true); - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -1108,7 +1112,7 @@ EXPECT_TRUE(state.NeedsCommit()); // We should get that commit when we begin the next frame. - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); @@ -1145,7 +1149,7 @@ EXPECT_TRUE(state.NeedsCommit()); // Begin a frame when not visible, the scheduler animates but does not commit. - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState()); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction()); @@ -1171,14 +1175,14 @@ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); // Check that the first init does not SetNeedsCommit. - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadline(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); // Check that a needs commit initiates a BeginMainFrame. state.SetNeedsCommit(); - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); } @@ -1208,7 +1212,7 @@ state.CreateAndInitializeOutputSurfaceWithActivatedCommit(); // When the context is recreated, we should begin a commit. - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); } @@ -1232,14 +1236,14 @@ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); // Once context recreation begins, nothing should happen. - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadline(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); // While context is recreating, commits shouldn't begin. state.SetNeedsCommit(); - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadline(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -1265,7 +1269,7 @@ // Once the context is recreated, whether we draw should be based on // SetCanDraw. - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadline(); @@ -1293,7 +1297,7 @@ // Set damage and expect a draw. state.SetNeedsRedraw(true); - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); @@ -1328,7 +1332,7 @@ EXPECT_EQ(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION, state.NextAction()); - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING, state.begin_impl_frame_state()); EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction()); @@ -1360,7 +1364,7 @@ // Set damage and expect a draw. state.SetNeedsRedraw(true); - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); @@ -1395,7 +1399,7 @@ EXPECT_EQ(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION, state.NextAction()); - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING, state.begin_impl_frame_state()); EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction()); @@ -1416,7 +1420,7 @@ // After we get a new output surface, the commit flow should start. state.CreateAndInitializeOutputSurfaceWithActivatedCommit(); - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -1452,7 +1456,7 @@ state.DidCreateAndInitializeOutputSurface(); EXPECT_FALSE(state.RedrawPending()); - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_EQ(SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME, state.NextAction()); } @@ -1584,7 +1588,7 @@ // This test mirrors what happens during the first frame of a scroll gesture. // First we get the input event and a BeginFrame. - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); // As a response the compositor requests a redraw and a commit to tell the // main thread about the new scroll offset. @@ -1619,7 +1623,7 @@ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -1644,7 +1648,7 @@ // in prefer impl latency mode. state.SetNeedsRedraw(true); state.SetNeedsCommit(); - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); @@ -1681,7 +1685,7 @@ // and did not just swap. state.SetNeedsCommit(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineEarly()); state.OnBeginImplFrameDeadline(); @@ -1699,7 +1703,7 @@ state.SetNeedsCommit(); - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -1726,7 +1730,7 @@ EXPECT_TRUE(state.BeginFrameNeeded()); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); state.OnBeginImplFrameDeadlinePending(); @@ -1752,7 +1756,7 @@ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); EXPECT_TRUE(state.BeginFrameNeeded()); - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); @@ -1780,7 +1784,7 @@ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); EXPECT_TRUE(state.BeginFrameNeeded()); - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); @@ -1812,7 +1816,7 @@ EXPECT_TRUE(state.BeginFrameNeeded()); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - state.OnBeginImplFrame(CreateBeginFrameArgsForTesting()); + state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); state.SetNeedsAnimate();
diff --git a/cc/scheduler/scheduler_unittest.cc b/cc/scheduler/scheduler_unittest.cc index deea726..2992dbc1 100644 --- a/cc/scheduler/scheduler_unittest.cc +++ b/cc/scheduler/scheduler_unittest.cc
@@ -191,7 +191,7 @@ // last one otherwise we violate the BeginFrameSource contract. now_src_->AdvanceNow(BeginFrameArgs::DefaultInterval()); fake_external_begin_frame_source_->TestOnBeginFrame( - CreateBeginFrameArgsForTesting(now_src_)); + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, now_src_)); } OrderedSimpleTaskRunner& task_runner() { return *task_runner_; } @@ -1180,7 +1180,8 @@ scheduler->NotifyReadyToCommit(); scheduler->SetNeedsRedraw(); - BeginFrameArgs frame_args = CreateBeginFrameArgsForTesting(client.now_src()); + BeginFrameArgs frame_args = + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, client.now_src()); frame_args.interval = base::TimeDelta::FromMilliseconds(1000); client.fake_external_begin_frame_source()->TestOnBeginFrame(frame_args); @@ -1253,7 +1254,8 @@ // Create a BeginFrame with a long deadline to avoid race conditions. // This is the first BeginFrame, which will be handled immediately. - BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src()); + BeginFrameArgs args = + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, client.now_src()); args.deadline += base::TimeDelta::FromHours(1); client.fake_external_begin_frame_source()->TestOnBeginFrame(args); EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); @@ -1331,7 +1333,8 @@ // Create a BeginFrame with a long deadline to avoid race conditions. // This is the first BeginFrame, which will be handled immediately. - BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src()); + BeginFrameArgs args = + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, client.now_src()); args.deadline += base::TimeDelta::FromHours(1); client.fake_external_begin_frame_source()->TestOnBeginFrame(args); EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); @@ -1931,7 +1934,8 @@ // Create a BeginFrame with a long deadline to avoid race conditions. // This is the first BeginFrame, which will be handled immediately. client.Reset(); - BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src()); + BeginFrameArgs args = + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, client.now_src()); args.deadline += base::TimeDelta::FromHours(1); client.fake_external_begin_frame_source()->TestOnBeginFrame(args); EXPECT_ACTION("WillBeginImplFrame", client, 0, 2); @@ -1990,7 +1994,8 @@ // Create a BeginFrame with a long deadline to avoid race conditions. // This is the first BeginFrame, which will be handled immediately. client.Reset(); - BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src()); + BeginFrameArgs args = + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, client.now_src()); args.deadline += base::TimeDelta::FromHours(1); client.fake_external_begin_frame_source()->TestOnBeginFrame(args); EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
diff --git a/cc/surfaces/display.cc b/cc/surfaces/display.cc index a8ae27a..9257446 100644 --- a/cc/surfaces/display.cc +++ b/cc/surfaces/display.cc
@@ -49,15 +49,23 @@ return output_surface_->BindToClient(this); } -void Display::Resize(SurfaceId id, - const gfx::Size& size, - float device_scale_factor) { +void Display::SetSurfaceId(SurfaceId id, float device_scale_factor) { current_surface_id_ = id; - current_surface_size_ = size; device_scale_factor_ = device_scale_factor; client_->DisplayDamaged(); } +void Display::Resize(const gfx::Size& size) { + if (size == current_surface_size_) + return; + // Need to ensure all pending swaps have executed before the window is + // resized, or D3D11 will scale the swap output. + if (renderer_ && settings_.finish_rendering_on_resize) + renderer_->Finish(); + current_surface_size_ = size; + client_->DisplayDamaged(); +} + void Display::InitializeRenderer() { if (resource_provider_) return; @@ -112,6 +120,9 @@ benchmark_instrumentation::IssueDisplayRenderingStatsEvent(); DelegatedFrameData* frame_data = frame->delegated_frame_data.get(); + gfx::Size surface_size = + frame_data->render_pass_list.back()->output_rect.size(); + gfx::Rect device_viewport_rect = gfx::Rect(current_surface_size_); gfx::Rect device_clip_rect = device_viewport_rect; bool disable_picture_quad_image_filtering = false; @@ -122,7 +133,14 @@ device_viewport_rect, device_clip_rect, disable_picture_quad_image_filtering); - renderer_->SwapBuffers(frame->metadata); + + bool disable_swap = surface_size != current_surface_size_; + if (disable_swap) { + DidSwapBuffers(); + } else { + renderer_->SwapBuffers(frame->metadata); + } + for (SurfaceAggregator::SurfaceIndexMap::iterator it = aggregator_->previous_contained_surfaces().begin(); it != aggregator_->previous_contained_surfaces().end(); @@ -131,6 +149,8 @@ if (surface) surface->RunDrawCallbacks(); } + if (disable_swap) + DidSwapBuffersComplete(); return true; }
diff --git a/cc/surfaces/display.h b/cc/surfaces/display.h index a0bb62ad..47c55bb 100644 --- a/cc/surfaces/display.h +++ b/cc/surfaces/display.h
@@ -51,9 +51,8 @@ // device_scale_factor is used to communicate to the external window system // what scale this was rendered at. - void Resize(SurfaceId id, - const gfx::Size& new_size, - float device_scale_factor); + void SetSurfaceId(SurfaceId id, float device_scale_factor); + void Resize(const gfx::Size& new_size); bool Draw(); SurfaceId CurrentSurfaceId();
diff --git a/cc/surfaces/surface_aggregator.cc b/cc/surfaces/surface_aggregator.cc index 35a1c1d..2334d141 100644 --- a/cc/surfaces/surface_aggregator.cc +++ b/cc/surfaces/surface_aggregator.cc
@@ -416,6 +416,9 @@ referenced_surfaces_.erase(it); DCHECK(referenced_surfaces_.empty()); + if (dest_pass_list_->empty()) + return nullptr; + dest_pass_list_ = NULL; RemoveUnreferencedChildren(); contained_surfaces_.swap(previous_contained_surfaces_);
diff --git a/cc/test/begin_frame_args_test.cc b/cc/test/begin_frame_args_test.cc index f70d0c57..7b29748 100644 --- a/cc/test/begin_frame_args_test.cc +++ b/cc/test/begin_frame_args_test.cc
@@ -10,57 +10,67 @@ namespace cc { -BeginFrameArgs CreateBeginFrameArgsForTesting() { - return CreateBeginFrameArgsForTesting(gfx::FrameTime::Now()); -} - -BeginFrameArgs CreateBeginFrameArgsForTesting(base::TimeTicks frame_time) { - return BeginFrameArgs::Create( - frame_time, frame_time + (BeginFrameArgs::DefaultInterval() / 2), - BeginFrameArgs::DefaultInterval(), BeginFrameArgs::NORMAL); -} - -BeginFrameArgs CreateBeginFrameArgsForTesting(int64 frame_time, - int64 deadline, - int64 interval) { - return BeginFrameArgs::Create(base::TimeTicks::FromInternalValue(frame_time), - base::TimeTicks::FromInternalValue(deadline), - base::TimeDelta::FromInternalValue(interval), - BeginFrameArgs::NORMAL); +BeginFrameArgs CreateBeginFrameArgsForTesting( + BeginFrameArgs::CreationLocation location) { + return CreateBeginFrameArgsForTesting(location, gfx::FrameTime::Now()); } BeginFrameArgs CreateBeginFrameArgsForTesting( + BeginFrameArgs::CreationLocation location, + base::TimeTicks frame_time) { + return BeginFrameArgs::Create( + location, frame_time, + frame_time + (BeginFrameArgs::DefaultInterval() / 2), + BeginFrameArgs::DefaultInterval(), BeginFrameArgs::NORMAL); +} + +BeginFrameArgs CreateBeginFrameArgsForTesting( + BeginFrameArgs::CreationLocation location, + int64 frame_time, + int64 deadline, + int64 interval) { + return BeginFrameArgs::Create( + location, base::TimeTicks::FromInternalValue(frame_time), + base::TimeTicks::FromInternalValue(deadline), + base::TimeDelta::FromInternalValue(interval), BeginFrameArgs::NORMAL); +} + +BeginFrameArgs CreateBeginFrameArgsForTesting( + BeginFrameArgs::CreationLocation location, int64 frame_time, int64 deadline, int64 interval, BeginFrameArgs::BeginFrameArgsType type) { - return BeginFrameArgs::Create(base::TimeTicks::FromInternalValue(frame_time), - base::TimeTicks::FromInternalValue(deadline), - base::TimeDelta::FromInternalValue(interval), - type); + return BeginFrameArgs::Create( + location, base::TimeTicks::FromInternalValue(frame_time), + base::TimeTicks::FromInternalValue(deadline), + base::TimeDelta::FromInternalValue(interval), type); } -BeginFrameArgs CreateExpiredBeginFrameArgsForTesting() { +BeginFrameArgs CreateExpiredBeginFrameArgsForTesting( + BeginFrameArgs::CreationLocation location) { base::TimeTicks now = gfx::FrameTime::Now(); - return BeginFrameArgs::Create(now, now - BeginFrameArgs::DefaultInterval(), - BeginFrameArgs::DefaultInterval(), - BeginFrameArgs::NORMAL); + return BeginFrameArgs::Create( + location, now, now - BeginFrameArgs::DefaultInterval(), + BeginFrameArgs::DefaultInterval(), BeginFrameArgs::NORMAL); } BeginFrameArgs CreateBeginFrameArgsForTesting( + BeginFrameArgs::CreationLocation location, scoped_refptr<TestNowSource> now_src) { base::TimeTicks now = now_src->Now(); return BeginFrameArgs::Create( - now, now + (BeginFrameArgs::DefaultInterval() / 2), + location, now, now + (BeginFrameArgs::DefaultInterval() / 2), BeginFrameArgs::DefaultInterval(), BeginFrameArgs::NORMAL); } BeginFrameArgs CreateExpiredBeginFrameArgsForTesting( + BeginFrameArgs::CreationLocation location, scoped_refptr<TestNowSource> now_src) { base::TimeTicks now = now_src->Now(); - return BeginFrameArgs::Create(now, now - BeginFrameArgs::DefaultInterval(), - BeginFrameArgs::DefaultInterval(), - BeginFrameArgs::NORMAL); + return BeginFrameArgs::Create( + location, now, now - BeginFrameArgs::DefaultInterval(), + BeginFrameArgs::DefaultInterval(), BeginFrameArgs::NORMAL); } bool operator==(const BeginFrameArgs& lhs, const BeginFrameArgs& rhs) {
diff --git a/cc/test/begin_frame_args_test.h b/cc/test/begin_frame_args_test.h index ca4aa45c..73aaf02 100644 --- a/cc/test/begin_frame_args_test.h +++ b/cc/test/begin_frame_args_test.h
@@ -15,23 +15,32 @@ namespace cc { // Functions for quickly creating BeginFrameArgs -BeginFrameArgs CreateBeginFrameArgsForTesting(); -BeginFrameArgs CreateBeginFrameArgsForTesting(base::TimeTicks frame_time); -BeginFrameArgs CreateBeginFrameArgsForTesting(int64 frame_time, - int64 deadline, - int64 interval); BeginFrameArgs CreateBeginFrameArgsForTesting( + BeginFrameArgs::CreationLocation location); +BeginFrameArgs CreateBeginFrameArgsForTesting( + BeginFrameArgs::CreationLocation location, + base::TimeTicks frame_time); +BeginFrameArgs CreateBeginFrameArgsForTesting( + BeginFrameArgs::CreationLocation location, + int64 frame_time, + int64 deadline, + int64 interval); +BeginFrameArgs CreateBeginFrameArgsForTesting( + BeginFrameArgs::CreationLocation location, int64 frame_time, int64 deadline, int64 interval, BeginFrameArgs::BeginFrameArgsType type); -BeginFrameArgs CreateExpiredBeginFrameArgsForTesting(); +BeginFrameArgs CreateExpiredBeginFrameArgsForTesting( + BeginFrameArgs::CreationLocation location); // Creates a BeginFrameArgs using the fake Now value stored on the // OrderSimpleTaskRunner. BeginFrameArgs CreateBeginFrameArgsForTesting( + BeginFrameArgs::CreationLocation location, scoped_refptr<TestNowSource> now_src); BeginFrameArgs CreateExpiredBeginFrameArgsForTesting( + BeginFrameArgs::CreationLocation location, scoped_refptr<TestNowSource> now_src); // gtest helpers -- these *must* be in the same namespace as the types they
diff --git a/cc/test/fake_layer_tree_host_impl.cc b/cc/test/fake_layer_tree_host_impl.cc index ea19e141..305b856 100644 --- a/cc/test/fake_layer_tree_host_impl.cc +++ b/cc/test/fake_layer_tree_host_impl.cc
@@ -24,7 +24,8 @@ // Avoid using Now() as the frame time in unit tests. base::TimeTicks time_ticks = base::TimeTicks::FromInternalValue(1); - SetCurrentBeginFrameArgs(CreateBeginFrameArgsForTesting(time_ticks)); + SetCurrentBeginFrameArgs( + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks)); } FakeLayerTreeHostImpl::FakeLayerTreeHostImpl(const LayerTreeSettings& settings, @@ -42,7 +43,8 @@ // Avoid using Now() as the frame time in unit tests. base::TimeTicks time_ticks = base::TimeTicks::FromInternalValue(1); - SetCurrentBeginFrameArgs(CreateBeginFrameArgsForTesting(time_ticks)); + SetCurrentBeginFrameArgs( + CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks)); } FakeLayerTreeHostImpl::~FakeLayerTreeHostImpl() {}
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc index 80e9f11..fb16917 100644 --- a/cc/test/layer_tree_test.cc +++ b/cc/test/layer_tree_test.cc
@@ -91,7 +91,7 @@ void TestOnBeginFrame() { DCHECK(CalledOnValidThread()); - CallOnBeginFrame(CreateBeginFrameArgsForTesting()); + CallOnBeginFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); } private:
diff --git a/cc/trees/layer_tree_host_common.cc b/cc/trees/layer_tree_host_common.cc index 6863850..6d75687 100644 --- a/cc/trees/layer_tree_host_common.cc +++ b/cc/trees/layer_tree_host_common.cc
@@ -392,7 +392,7 @@ gfx::Rect visible_rect_in_target_surface_space = layer->drawable_content_rect(); - if (!layer->render_target()->render_surface()->clip_rect().IsEmpty()) { + if (layer->render_target()->render_surface()->is_clipped()) { // The |layer| L has a target T which owns a surface Ts. The surface Ts // has a target TsT. //
diff --git a/cc/trees/layer_tree_host_common_unittest.cc b/cc/trees/layer_tree_host_common_unittest.cc index b9acf5af..8c02bd33 100644 --- a/cc/trees/layer_tree_host_common_unittest.cc +++ b/cc/trees/layer_tree_host_common_unittest.cc
@@ -2826,6 +2826,56 @@ } TEST_F(LayerTreeHostCommonTest, + VisibleContentRectsForClippedSurfaceWithEmptyClip) { + scoped_refptr<Layer> root = Layer::Create(); + scoped_refptr<LayerWithForcedDrawsContent> child1 = + make_scoped_refptr(new LayerWithForcedDrawsContent()); + scoped_refptr<LayerWithForcedDrawsContent> child2 = + make_scoped_refptr(new LayerWithForcedDrawsContent()); + scoped_refptr<LayerWithForcedDrawsContent> child3 = + make_scoped_refptr(new LayerWithForcedDrawsContent()); + root->AddChild(child1); + root->AddChild(child2); + root->AddChild(child3); + + scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost()); + host->SetRootLayer(root); + + gfx::Transform identity_matrix; + SetLayerPropertiesForTesting(root.get(), identity_matrix, gfx::Point3F(), + gfx::PointF(), gfx::Size(100, 100), true, false); + SetLayerPropertiesForTesting(child1.get(), identity_matrix, gfx::Point3F(), + gfx::PointF(5.f, 5.f), gfx::Size(50, 50), true, + false); + SetLayerPropertiesForTesting(child2.get(), identity_matrix, gfx::Point3F(), + gfx::PointF(75.f, 75.f), gfx::Size(50, 50), true, + false); + SetLayerPropertiesForTesting(child3.get(), identity_matrix, gfx::Point3F(), + gfx::PointF(125.f, 125.f), gfx::Size(50, 50), + true, false); + + RenderSurfaceLayerList render_surface_layer_list; + // Now set the root render surface an empty clip. + LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs( + root.get(), gfx::Size(), &render_surface_layer_list); + + LayerTreeHostCommon::CalculateDrawProperties(&inputs); + ASSERT_TRUE(root->render_surface()); + EXPECT_FALSE(root->is_clipped()); + + gfx::Rect empty; + EXPECT_EQ(empty, root->render_surface()->clip_rect()); + EXPECT_TRUE(root->render_surface()->is_clipped()); + + // Visible content rect calculation will check if the target surface is + // clipped or not. An empty clip rect does not indicate the render surface + // is unclipped. + EXPECT_EQ(empty, child1->visible_content_rect()); + EXPECT_EQ(empty, child2->visible_content_rect()); + EXPECT_EQ(empty, child3->visible_content_rect()); +} + +TEST_F(LayerTreeHostCommonTest, DrawableAndVisibleContentRectsForLayersWithUninvertibleTransform) { scoped_refptr<Layer> root = Layer::Create(); scoped_refptr<LayerWithForcedDrawsContent> child =
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index 7593965..10b0685 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc
@@ -2551,10 +2551,14 @@ return actual_viewport_end_point - viewport_point; } -static gfx::Vector2dF ScrollLayerWithLocalDelta(LayerImpl* layer_impl, - const gfx::Vector2dF& local_delta) { +static gfx::Vector2dF ScrollLayerWithLocalDelta( + LayerImpl* layer_impl, + const gfx::Vector2dF& local_delta, + float page_scale_factor) { gfx::Vector2dF previous_delta(layer_impl->ScrollDelta()); - layer_impl->ScrollBy(local_delta); + gfx::Vector2dF delta = local_delta; + delta.Scale(1.f / page_scale_factor); + layer_impl->ScrollBy(delta); return layer_impl->ScrollDelta() - previous_delta; } @@ -2632,7 +2636,8 @@ // Gesture events need to be transformed from viewport coordinates to local // layer coordinates so that the scrolling contents exactly follow the // user's finger. In contrast, wheel events represent a fixed amount of - // scrolling so we can just apply them directly. + // scrolling so we can just apply them directly, but the page scale factor + // is applied to the scroll delta. if (!wheel_scrolling_) { float scale_from_viewport_to_screen_space = device_scale_factor_; applied_delta = @@ -2640,7 +2645,8 @@ scale_from_viewport_to_screen_space, viewport_point, pending_delta); } else { - applied_delta = ScrollLayerWithLocalDelta(layer_impl, pending_delta); + applied_delta = ScrollLayerWithLocalDelta( + layer_impl, pending_delta, active_tree_->total_page_scale_factor()); } const float kEpsilon = 0.1f; @@ -2762,7 +2768,8 @@ gfx::Vector2dF delta = gfx::Vector2dF(0.f, page); - gfx::Vector2dF applied_delta = ScrollLayerWithLocalDelta(layer_impl, delta); + gfx::Vector2dF applied_delta = + ScrollLayerWithLocalDelta(layer_impl, delta, 1.f); if (!applied_delta.IsZero()) { client_->SetNeedsCommitOnImplThread(); @@ -3239,9 +3246,9 @@ // task), fall back to physical time. This should still be monotonic. if (current_begin_frame_args_.IsValid()) return current_begin_frame_args_; - return BeginFrameArgs::Create(gfx::FrameTime::Now(), base::TimeTicks(), - BeginFrameArgs::DefaultInterval(), - BeginFrameArgs::NORMAL); + return BeginFrameArgs::Create( + BEGINFRAME_FROM_HERE, gfx::FrameTime::Now(), base::TimeTicks(), + BeginFrameArgs::DefaultInterval(), BeginFrameArgs::NORMAL); } scoped_refptr<base::debug::ConvertableToTraceFormat>
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc index 8d0ee39a..f31cde0 100644 --- a/cc/trees/layer_tree_host_impl_unittest.cc +++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -950,7 +950,7 @@ } // Scrolling after a pinch gesture should always be in local space. The - // scroll deltas do not have the page scale factor applied. + // scroll deltas have the page scale factor applied. { host_impl_->active_tree()->SetPageScaleFactorAndLimits( page_scale_factor, min_page_scale, max_page_scale); @@ -973,9 +973,8 @@ scoped_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas(); - ExpectContains(*scroll_info.get(), - scroll_layer->id(), - scroll_delta); + ExpectContains(*scroll_info.get(), scroll_layer->id(), + gfx::Vector2d(0, scroll_delta.y() / page_scale_delta)); } } @@ -1400,7 +1399,8 @@ 0) {} BeginFrameArgs CurrentBeginFrameArgs() const override { - return CreateBeginFrameArgsForTesting(fake_current_physical_time_); + return CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, + fake_current_physical_time_); } void SetCurrentPhysicalTimeTicksForTest(base::TimeTicks fake_now) { @@ -3601,7 +3601,7 @@ host_impl_->ScrollBy(gfx::Point(), wheel_scroll_delta); host_impl_->ScrollEnd(); - // The scale should not have been applied to the scroll delta. + // It should apply the scale factor to the scroll delta for the wheel event. scroll_info = host_impl_->ProcessScrollDeltas(); ExpectContains(*scroll_info.get(), scroll_layer->id(), @@ -7827,6 +7827,41 @@ EXPECT_EQ(1u, raw_replica_mask_layer->did_become_active_call_count()); } +TEST_F(LayerTreeHostImplTest, WheelScrollWithPageScaleFactorOnInnerLayer) { + LayerImpl* scroll_layer = SetupScrollAndContentsLayers(gfx::Size(100, 100)); + host_impl_->SetViewportSize(gfx::Size(50, 50)); + DrawFrame(); + + EXPECT_EQ(scroll_layer, host_impl_->InnerViewportScrollLayer()); + + float min_page_scale = 1.f, max_page_scale = 4.f; + float page_scale_factor = 1.f; + + // The scroll deltas should have the page scale factor applied. + { + host_impl_->active_tree()->SetPageScaleFactorAndLimits( + page_scale_factor, min_page_scale, max_page_scale); + host_impl_->active_tree()->SetPageScaleDelta(1.f); + scroll_layer->SetScrollDelta(gfx::Vector2d()); + + float page_scale_delta = 2.f; + host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture); + host_impl_->PinchGestureBegin(); + host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point()); + host_impl_->PinchGestureEnd(); + host_impl_->ScrollEnd(); + + gfx::Vector2dF scroll_delta(0, 5); + EXPECT_EQ(InputHandler::ScrollStarted, + host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel)); + EXPECT_VECTOR_EQ(gfx::Vector2dF(), scroll_layer->TotalScrollOffset()); + + host_impl_->ScrollBy(gfx::Point(), scroll_delta); + host_impl_->ScrollEnd(); + EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 2.5), scroll_layer->TotalScrollOffset()); + } +} + class LayerTreeHostImplCountingLostSurfaces : public LayerTreeHostImplTest { public: LayerTreeHostImplCountingLostSurfaces() : num_lost_surfaces_(0) {}
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc index 5a40d7e..9995a97 100644 --- a/cc/trees/single_thread_proxy.cc +++ b/cc/trees/single_thread_proxy.cc
@@ -493,8 +493,8 @@ { BeginFrameArgs begin_frame_args(BeginFrameArgs::Create( - frame_begin_time, base::TimeTicks(), BeginFrameArgs::DefaultInterval(), - BeginFrameArgs::SYNCHRONOUS)); + BEGINFRAME_FROM_HERE, frame_begin_time, base::TimeTicks(), + BeginFrameArgs::DefaultInterval(), BeginFrameArgs::SYNCHRONOUS)); DoBeginMainFrame(begin_frame_args); DoCommit();
diff --git a/chrome/VERSION b/chrome/VERSION index 835a9f5..fda70be 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=41 MINOR=0 -BUILD=2236 +BUILD=2238 PATCH=0
diff --git a/chrome/android/java/res/layout/spinner.xml b/chrome/android/java/res/layout/spinner.xml new file mode 100644 index 0000000..988e422c --- /dev/null +++ b/chrome/android/java/res/layout/spinner.xml
@@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2014 The Chromium Authors. All rights reserved. + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. --> + +<!-- A plain old Spinner. + + Why is this needed? Because spinners must be inflated from a resource for the AppCompat theme + to work. Simply calling new Spinner() will result in a missing spinner arrow on pre-L devices. + + See the FAQ on this page: + http://android-developers.blogspot.com/2014/10/appcompat-v21-material-design-for-pre.html --> +<Spinner />
diff --git a/chrome/android/java/res/values-sw600dp/values.xml b/chrome/android/java/res/values-sw600dp/values.xml new file mode 100644 index 0000000..3676be5 --- /dev/null +++ b/chrome/android/java/res/values-sw600dp/values.xml
@@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<resources xmlns:android="http://schemas.android.com/apk/res/android"> + <!-- Full Screen Constants --> + <!-- These constants were chosen empirically for their visually pleasant behavior. + Contact tedchoc@chromium.org or dtrainor@chromium.org for questions about + changing these values. --> + <item name="top_controls_show_threshold" format="float" type="floats">0.27</item> + <item name="top_controls_hide_threshold" format="float" type="floats">0.17</item> +</resources>
diff --git a/chrome/android/java/res/values/values.xml b/chrome/android/java/res/values/values.xml index 836a3022..d59b0b43 100644 --- a/chrome/android/java/res/values/values.xml +++ b/chrome/android/java/res/values/values.xml
@@ -14,4 +14,11 @@ <!-- Menu Animation Constants --> <item type="fraction" format="fraction" name="menu_animation_pivot_x">95%</item> + + <!-- Full Screen Constants --> + <!-- These constants were chosen empirically for their visually pleasant behavior. + Contact tedchoc@chromium.org or dtrainor@chromium.org for questions about + changing these values. --> + <item name="top_controls_show_threshold" format="float" type="floats">0.5</item> + <item name="top_controls_hide_threshold" format="float" type="floats">0.5</item> </resources>
diff --git a/chrome/android/java/src/org/chromium/chrome/ChromeSwitches.java b/chrome/android/java/src/org/chromium/chrome/ChromeSwitches.java index 59a6d83b..ab882a8 100644 --- a/chrome/android/java/src/org/chromium/chrome/ChromeSwitches.java +++ b/chrome/android/java/src/org/chromium/chrome/ChromeSwitches.java
@@ -9,6 +9,9 @@ * portion of Chromium on Android. */ public abstract class ChromeSwitches { + // Switches used from Java. Please continue switch style used Chrome where + // options-have-hypens and are_not_split_with_underscores. + // Disables the new Website Settings dialog, which replaces the old one. // TODO(sashab): Once the new WebsiteSettingsPopup is ready to be permanent, // remove this flag and delete WebsiteSettingsLegacyPopup and all it's @@ -29,6 +32,91 @@ public static final String ENABLE_TOOLBAR_SWIPE_IN_DOCUMENT_MODE = "enable-toolbar-swipe-in-document-mode"; + /** Whether instant is disabled. */ + public static final String DISABLE_INSTANT = "disable-instant"; + + /** Whether force-enable the "hardware acceleration" preference. */ + public static final String HARDWARE_ACCELERATION = "hardware-acceleration"; + + /** If specified, enables notification center verbose logging. */ + public static final String NOTIFICATION_CENTER_LOGGING = "notification-center-logging"; + + /** Enables StrictMode violation detection. By default this logs violations to logcat. */ + public static final String STRICT_MODE = "strict-mode"; + + /** Don't restore persistent state from saved files on startup. */ + public static final String NO_RESTORE_STATE = "no-restore-state"; + + /** Disable the First Run Experience. */ + public static final String DISABLE_FIRST_RUN_EXPERIENCE = "disable-fre"; + + /** Force the crash dump to be uploaded regardless of preferences. */ + public static final String FORCE_CRASH_DUMP_UPLOAD = "force-dump-upload"; + + /** Do not use OAuth2 tokens for communication with Cloud Print service for Chrome to Mobile. */ + public static final String DISABLE_CHROME_TO_MOBILE_OAUTH2 = "disable-chrome-to-mobile-oauth2"; + + /** Enable debug logs for the video casting feature. */ + public static final String ENABLE_CAST_DEBUG_LOGS = "enable-cast-debug"; + + /** Prevent automatic reconnection to current Cast video when Chrome restarts. */ + public static final String DISABLE_CAST_RECONNECTION = "disable-cast-reconnection"; + + /** Whether site/user triggered persistent fullscreen is supported. */ + public static final String DISABLE_PERSISTENT_FULLSCREEN = "disable-persistent-fullscreen"; + + /** Whether or not to enable the experimental tablet tab stack. */ + public static final String ENABLE_TABLET_TAB_STACK = "enable-tablet-tab-stack"; + + /** Disables support for playing videos remotely via Android MediaRouter API. */ + public static final String DISABLE_CAST = "disable-cast"; + + /** Never forward URL requests to external intents. */ + public static final String DISABLE_EXTERNAL_INTENT_REQUESTS = + "disable-external-intent-requests"; + + /** Disable document mode. */ + public static final String DISABLE_DOCUMENT_MODE = "disable-document-mode"; + + /** Disable Contextual Search. */ + public static final String DISABLE_CONTEXTUAL_SEARCH = "disable-contextual-search"; + + /** Enable Contextual Search. */ + public static final String ENABLE_CONTEXTUAL_SEARCH = "enable-contextual-search"; + + /** Disable Contextual Search first-run flow, for testing. Not exposed to user. */ + public static final String DISABLE_CONTEXTUAL_SEARCH_PROMO_FOR_TESTING = + "disable-contextual-search-promo-for-testing"; + + /////////////////////////////////////////////////////////////////////////////////////////////// + // Native Switches + /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Sets the max number of render processes to use. + * Native switch - content_switches::kRendererProcessLimit. + */ + public static final String RENDER_PROCESS_LIMIT = "renderer-process-limit"; + + /** Enable begin frame scheduling. */ + public static final String ENABLE_BEGIN_FRAME_SCHEDULING = "enable-begin-frame-scheduling"; + + /** Enable the DOM Distiller. */ + public static final String ENABLE_DOM_DISTILLER = "enable-dom-distiller"; + + /** Enable experimental web-platform features, such as Push Messaging. */ + public static final String EXPERIMENTAL_WEB_PLAFTORM_FEATURES = + "enable-experimental-web-platform-features"; + + /** Enable the Reader Mode icon in toolbar. */ + public static final String ENABLE_READER_MODE_TOOLBAR_ICON = "enable-reader-mode-toolbar-icon"; + + /** + * Use sandbox Wallet environment for requestAutocomplete. + * Native switch - autofill::switches::kWalletServiceUseSandbox. + */ + public static final String USE_SANDBOX_WALLET_ENVIRONMENT = "wallet-service-use-sandbox"; + // Prevent instantiation. private ChromeSwitches() {} }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ApplicationInitialization.java b/chrome/android/java/src/org/chromium/chrome/browser/ApplicationInitialization.java new file mode 100644 index 0000000..4af293d --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/ApplicationInitialization.java
@@ -0,0 +1,54 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser; + +import android.content.Context; +import android.content.res.Resources; +import android.util.TypedValue; + +import org.chromium.base.CommandLine; +import org.chromium.chrome.ChromeSwitches; +import org.chromium.chrome.R; +import org.chromium.content.app.ContentApplication; +import org.chromium.content.common.ContentSwitches; + + +/** + * Utility class for application level initialization calls. + */ +public final class ApplicationInitialization { + // Prevent instantiation. + private ApplicationInitialization() { + } + + /** + * Enable fullscreen related startup flags. + * @param resources Resources to use while calculating initialization constants. + * @param resControlContainerHeight The resource id for the height of the top controls. + */ + public static void enableFullscreenFlags( + Resources resources, Context context, int resControlContainerHeight) { + ContentApplication.initCommandLine(context); + + CommandLine commandLine = CommandLine.getInstance(); + if (commandLine.hasSwitch(ChromeSwitches.DISABLE_FULLSCREEN)) return; + + commandLine.appendSwitch(ContentSwitches.ENABLE_TOP_CONTROLS_POSITION_CALCULATION); + + float controlsHeightDp = + resources.getDimensionPixelSize(resControlContainerHeight) + / resources.getDisplayMetrics().density; + commandLine.appendSwitchWithValue( + ContentSwitches.TOP_CONTROLS_HEIGHT, Float.toString(controlsHeightDp)); + + TypedValue threshold = new TypedValue(); + resources.getValue(R.floats.top_controls_show_threshold, threshold, true); + commandLine.appendSwitchWithValue( + ContentSwitches.TOP_CONTROLS_SHOW_THRESHOLD, threshold.coerceToString().toString()); + resources.getValue(R.floats.top_controls_hide_threshold, threshold, true); + commandLine.appendSwitchWithValue( + ContentSwitches.TOP_CONTROLS_HIDE_THRESHOLD, threshold.coerceToString().toString()); + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/EmptyTabObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/EmptyTabObserver.java index 47d404b3..9a5b09f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/EmptyTabObserver.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/EmptyTabObserver.java
@@ -77,6 +77,12 @@ public void onDidChangeThemeColor(int color) { } @Override + public void onDidAttachInterstitialPage(Tab tab) { } + + @Override + public void onDidDetachInterstitialPage(Tab tab) { } + + @Override public void webContentsCreated(Tab tab, long sourceWebContents, long openerRenderFrameId, String frameName, String targetUrl, long newWebContents) { } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/Tab.java b/chrome/android/java/src/org/chromium/chrome/browser/Tab.java index b4b54aa5..3b90f49 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/Tab.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/Tab.java
@@ -332,6 +332,20 @@ observer.onDidChangeThemeColor(color); } } + + @Override + public void didAttachInterstitialPage() { + for (TabObserver observer : mObservers) { + observer.onDidAttachInterstitialPage(Tab.this); + } + } + + @Override + public void didDetachInterstitialPage() { + for (TabObserver observer : mObservers) { + observer.onDidDetachInterstitialPage(Tab.this); + } + } } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/TabObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/TabObserver.java index 627a112..224b94a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/TabObserver.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/TabObserver.java
@@ -183,6 +183,18 @@ */ public void onDidChangeThemeColor(int color); + /** + * Called when an interstitial page gets attached to the tab content. + * @param tab The notifying {@link Tab}. + */ + public void onDidAttachInterstitialPage(Tab tab); + + /** + * Called when an interstitial page gets detached from the tab content. + * @param tab The notifying {@link Tab}. + */ + public void onDidDetachInterstitialPage(Tab tab); + public void webContentsCreated(Tab tab, long sourceWebContents, long openerRenderFrameId, String frameName, String targetUrl, long newWebContents); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/WebsiteSettingsPopup.java b/chrome/android/java/src/org/chromium/chrome/browser/WebsiteSettingsPopup.java index ac023d6..a8d6158 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/WebsiteSettingsPopup.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/WebsiteSettingsPopup.java
@@ -222,9 +222,13 @@ * * @param toolbarModelSecurityLevel A valid ToolbarModelSecurityLevel, which is the security * level of the page. + * @param isInternalPage Whether or not this page is an internal chrome page (e.g. the + * chrome://settings page). * @return The ID of the message to display in the connection message box. */ - private int getConnectionMessageId(int toolbarModelSecurityLevel) { + private int getConnectionMessageId(int toolbarModelSecurityLevel, boolean isInternalPage) { + if (isInternalPage) return R.string.page_info_connection_internal_page; + switch (toolbarModelSecurityLevel) { case ToolbarModelSecurityLevel.NONE: return R.string.page_info_connection_http; @@ -259,7 +263,7 @@ SpannableStringBuilder messageBuilder = new SpannableStringBuilder(); if (securityLevel != ToolbarModelSecurityLevel.SECURITY_ERROR) { messageBuilder.append(mContext.getResources().getString( - getConnectionMessageId(securityLevel))); + getConnectionMessageId(securityLevel, isInternalPage))); } else { String originToDisplay; try {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/DataReductionProxyInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/DataReductionProxyInfoBar.java index 10976ae..1758df3 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/DataReductionProxyInfoBar.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/DataReductionProxyInfoBar.java
@@ -11,8 +11,6 @@ * data reduction proxy settings menu. */ public class DataReductionProxyInfoBar extends ConfirmInfoBar { - private static String sSettingsClassName; - private static String sDataReductionProxySettingsClassName; private static String sTitle; private static String sLinkText; @@ -20,36 +18,29 @@ * Launch a data reduction proxy {@link InfoBar} with the specified title and link * text. Clicking the link will open the specified settings page. * @param webContents The {@link WebContents} in which to open the {@link InfoBar}. - * @param settingsClassName The settings class to open. - * @param drpSettingsClassName The {@link PreferenceActivity} fragment to show. * @param title The text to display in the {@link InfoBar}. * @param linkText The text to display in the link in the {@link InfoBar}. * @param linkUrl The URL to be loaded when the link text is clicked. */ public static void launch(WebContents webContents, - String settingsClassName, - String drpSettingsClassName, String title, String linkText, String linkUrl) { - sSettingsClassName = settingsClassName; - sDataReductionProxySettingsClassName = drpSettingsClassName; sTitle = title; sLinkText = linkText; DataReductionProxyInfoBarDelegate.launch(webContents, linkUrl); } /** - * Callers should now pass a linkUrl, which is loaded when the user clicks on linkText. See - * {@link #launch} above. See http://crbug.com/383988. + * Use the method above instead. TODO(newt): delete this once all callers are updated. */ - @Deprecated public static void launch(WebContents webContents, - String settingsClassName, - String drpSettingsClassName, + String unused1, + String unused2, String title, - String linkText) { - launch(webContents, settingsClassName, drpSettingsClassName, title, linkText, ""); + String linkText, + String linkUrl) { + launch(webContents, title, linkText, linkUrl); } DataReductionProxyInfoBar(long nativeInfoBar, int iconDrawableId) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateLanguagePanel.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateLanguagePanel.java index fb48247..77e8cb7 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateLanguagePanel.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateLanguagePanel.java
@@ -9,6 +9,7 @@ import android.text.SpannableString; import android.text.TextUtils; import android.text.style.ForegroundColorSpan; +import android.util.TypedValue; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -103,8 +104,9 @@ mTargetAdapter.measureWidthRequiredForView(); // Create the spinners. - mSourceSpinner = new Spinner(context); - mTargetSpinner = new Spinner(context); + LayoutInflater inflater = LayoutInflater.from(context); + mSourceSpinner = (Spinner) inflater.inflate(R.layout.spinner, null); + mTargetSpinner = (Spinner) inflater.inflate(R.layout.spinner, null); mSourceSpinner.setOnItemSelectedListener(this); mTargetSpinner.setOnItemSelectedListener(this); mSourceSpinner.setAdapter(mSourceAdapter); @@ -234,8 +236,9 @@ public View getView(int position, View convertView, ViewGroup parent) { TextView result; if (!(convertView instanceof TextView)) { - result = (TextView) LayoutInflater.from(getContext()).inflate( - R.layout.infobar_text, null); + result = new TextView(getContext()); + result.setTextSize(TypedValue.COMPLEX_UNIT_PX, + getContext().getResources().getDimension(R.dimen.infobar_text_size)); } else { result = (TextView) convertView; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationService.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationService.java index a9d07f7d..eac70b7 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationService.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationService.java
@@ -14,7 +14,6 @@ import org.chromium.base.ThreadUtils; import org.chromium.base.library_loader.LibraryLoader; import org.chromium.base.library_loader.ProcessInitException; -import org.chromium.chrome.browser.NotificationUIManager; import org.chromium.content.app.ContentApplication; import org.chromium.content.browser.BrowserStartupController;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/NotificationUIManager.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUIManager.java similarity index 84% rename from chrome/android/java/src/org/chromium/chrome/browser/NotificationUIManager.java rename to chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUIManager.java index d288142..4ecb6a4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/NotificationUIManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUIManager.java
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -package org.chromium.chrome.browser; +package org.chromium.chrome.browser.notifications; import android.app.Notification; import android.app.NotificationManager; @@ -15,8 +15,6 @@ import android.util.Log; import org.chromium.base.CalledByNative; -import org.chromium.chrome.browser.notifications.NotificationConstants; -import org.chromium.chrome.browser.notifications.NotificationService; import org.chromium.chrome.browser.widget.RoundedIconGenerator; /** @@ -31,7 +29,24 @@ private static final int NOTIFICATION_ICON_BG_COLOR = Color.rgb(150, 150, 150); private static final int NOTIFICATION_TEXT_SIZE_DP = 28; + /** + * The application has the ability to observe the UI manager by providing an Observer. + */ + public interface Observer { + /** + * Will be called right before a notification is being displayed. The implementation may + * modify the Notification's builder. + * + * @param notificationBuilder The NotificationBuilder which is about to be shown. + * @param origin The origin which is displaying the notification. + */ + void onBeforeDisplayNotification(Notification.Builder notificationBuilder, + String origin); + } + private static NotificationUIManager sInstance; + private static Observer sObserver; + private final long mNativeNotificationManager; private final Context mAppContext; @@ -57,6 +72,19 @@ return sInstance; } + /** + * Sets the optional observer to be used when displaying notifications. May be NULL. + * + * @param observer The observer to call when displaying notifications. + */ + public static void setObserver(Observer observer) { + if (sObserver != null && observer != null) { + throw new IllegalStateException("There must only be one active Observer at a time."); + } + + sObserver = observer; + } + private NotificationUIManager(long nativeNotificationManager, Context context) { mNativeNotificationManager = nativeNotificationManager; mAppContext = context.getApplicationContext(); @@ -133,7 +161,7 @@ icon = getIconGenerator().generateIconForUrl(origin); } - Notification notification = new Notification.Builder(mAppContext) + Notification.Builder notificationBuilder = new Notification.Builder(mAppContext) .setContentTitle(title) .setContentText(body) .setStyle(new Notification.BigTextStyle().bigText(body)) @@ -145,10 +173,13 @@ .setDeleteIntent(getPendingIntent( notificationId, mLastNotificationId, NotificationConstants.ACTION_CLOSE_NOTIFICATION)) - .setSubText(origin) - .build(); + .setSubText(origin); - mNotificationManager.notify(mLastNotificationId, notification); + if (sObserver != null) { + sObserver.onBeforeDisplayNotification(notificationBuilder, origin); + } + + mNotificationManager.notify(mLastNotificationId, notificationBuilder.build()); return mLastNotificationId++; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManager.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManager.java index fc78d9bd..58e13dd6 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninManager.java
@@ -482,6 +482,13 @@ } /** + * @return Whether there is a signed in account on the native side. + */ + public boolean isSignedInOnNative() { + return nativeIsSignedInOnNative(mNativeSigninManagerAndroid); + } + + /** * @return Experiment group for the android signin promo that the current user falls into. * -1 if the sigin promo experiment is disabled, otherwise an integer between 0 and 7. * TODO(guohui): instead of group names, it is better to use experiment params to control @@ -517,5 +524,6 @@ private native void nativeWipeProfileData(long nativeSigninManagerAndroid); private native void nativeClearLastSignedInUser(long nativeSigninManagerAndroid); private native void nativeLogInSignedInUser(long nativeSigninManagerAndroid); + private native boolean nativeIsSignedInOnNative(long nativeSigninManagerAndroid); private static native boolean nativeIsNewProfileManagementEnabled(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/ChromiumSyncAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/ChromiumSyncAdapter.java index ca96e36..d6bf354 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/sync/ChromiumSyncAdapter.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/ChromiumSyncAdapter.java
@@ -8,6 +8,7 @@ import android.app.Application; import android.content.AbstractThreadedSyncAdapter; import android.content.ContentProviderClient; +import android.content.ContentResolver; import android.content.Context; import android.content.SyncResult; import android.os.Bundle; @@ -23,8 +24,10 @@ import org.chromium.chrome.browser.profiles.Profile; import org.chromium.content.app.ContentApplication; import org.chromium.content.browser.BrowserStartupController; +import org.chromium.sync.signin.ChromeSigninController; import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; /** * A sync adapter for Chromium. @@ -57,6 +60,16 @@ @Override public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) { + if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE)) { + Account signedInAccount = ChromeSigninController.get(getContext()).getSignedInUser(); + if (account.equals(signedInAccount)) { + ContentResolver.setIsSyncable(account, authority, 1); + } else { + ContentResolver.setIsSyncable(account, authority, 0); + } + return; + } + if (!DelayedSyncController.getInstance().shouldPerformSync(getContext(), extras, account)) { return; } @@ -70,8 +83,12 @@ startBrowserProcess(callback, syncResult, semaphore); try { - // Wait for startup to complete. - semaphore.acquire(); + // This code is only synchronously calling a single native method + // to trigger and asynchronous sync cycle, so 5 minutes is generous. + if (!semaphore.tryAcquire(5, TimeUnit.MINUTES)) { + Log.w(TAG, "Sync request timed out!"); + syncResult.stats.numIoExceptions++; + } } catch (InterruptedException e) { Log.w(TAG, "Got InterruptedException when trying to request a sync.", e); // Using numIoExceptions so Android will treat this as a soft error.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorBase.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorBase.java index 2074778..47da506 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorBase.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorBase.java
@@ -58,6 +58,7 @@ for (TabModel model : models) { model.addObserver(tabModelObserver); } + notifyChanged(); } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorTabObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorTabObserver.java new file mode 100644 index 0000000..924edb5 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorTabObserver.java
@@ -0,0 +1,113 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.tabmodel; + +import org.chromium.chrome.browser.EmptyTabObserver; +import org.chromium.chrome.browser.Tab; +import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType; +import org.chromium.chrome.browser.tabmodel.TabModelSelector.ChangeListener; + +import java.util.List; + +/** + * Observer of tab changes for all tabs owned by a {@link TabModelSelector}. + */ +public class TabModelSelectorTabObserver extends EmptyTabObserver { + + private final TabModelSelector mTabModelSelector; + private final TabModelObserver mTabModelObserver; + + private ChangeListener mChangeListener; + private boolean mIsDestroyed; + + /** + * Constructs an observer that should be notified of tabs changes for all tabs owned + * by a specified {@link TabModelSelector}. Any Tabs created after this call will be + * observed as well, and Tabs removed will no longer have their information broadcast. + * + * <p> + * {@link #destroy()} must be called to unregister this observer. + * + * @param selector The selector that owns the Tabs that should notify this observer. + */ + public TabModelSelectorTabObserver(TabModelSelector selector) { + mTabModelSelector = selector; + + mTabModelObserver = new EmptyTabModelObserver() { + @Override + public void didAddTab(Tab tab, TabLaunchType type) { + tab.addObserver(TabModelSelectorTabObserver.this); + } + + @Override + public void didCloseTab(Tab tab) { + tab.removeObserver(TabModelSelectorTabObserver.this); + } + }; + + List<TabModel> tabModels = selector.getModels(); + if (tabModels.isEmpty()) { + mChangeListener = new ChangeListener() { + @Override + public void onNewTabCreated(Tab tab) { + assert false : "onChange should have happened and unregistered this listener."; + } + + @Override + public void onChange() { + mTabModelSelector.unregisterChangeListener(this); + mChangeListener = null; + registerModelObservers(); + } + }; + mTabModelSelector.registerChangeListener(mChangeListener); + } else { + registerModelObservers(); + } + } + + private void registerModelObservers() { + List<TabModel> tabModels = mTabModelSelector.getModels(); + for (int i = 0; i < tabModels.size(); i++) { + TabModel tabModel = tabModels.get(i); + tabModel.addObserver(mTabModelObserver); + + TabList comprehensiveTabList = tabModel.getComprehensiveModel(); + for (int j = 0; j < comprehensiveTabList.getCount(); j++) { + comprehensiveTabList.getTabAt(j).addObserver(this); + } + } + } + + /** + * Destroys the observer and removes itself as a listener for Tab updates. + */ + public void destroy() { + mIsDestroyed = true; + + if (mChangeListener != null) { + mTabModelSelector.unregisterChangeListener(mChangeListener); + mChangeListener = null; + } + + List<TabModel> tabModels = mTabModelSelector.getModels(); + for (int i = 0; i < tabModels.size(); i++) { + TabModel tabModel = tabModels.get(i); + tabModel.removeObserver(mTabModelObserver); + + TabList comprehensiveTabList = tabModel.getComprehensiveModel(); + for (int j = 0; j < comprehensiveTabList.getCount(); j++) { + comprehensiveTabList.getTabAt(j).removeObserver(this); + } + } + } + + @Override + protected void finalize() throws Throwable { + super.finalize(); + + assert mIsDestroyed; + } +}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ChromiumSyncAdapterTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ChromiumSyncAdapterTest.java index 8f7b707..fb84f98 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ChromiumSyncAdapterTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ChromiumSyncAdapterTest.java
@@ -6,6 +6,7 @@ import android.accounts.Account; import android.app.Application; +import android.content.ContentResolver; import android.content.Context; import android.content.SyncResult; import android.os.Bundle; @@ -19,6 +20,9 @@ import org.chromium.sync.notifier.SyncStatusHelper; import org.chromium.sync.signin.AccountManagerHelper; +/** + * Tests for ChromiumSyncAdapter. + */ public class ChromiumSyncAdapterTest extends ChromeShellTestBase { private static final Account TEST_ACCOUNT = @@ -66,19 +70,22 @@ getActivity().getApplication()); } + public void performSyncWithBundle(Bundle bundle) { + mSyncAdapter.onPerformSync(TEST_ACCOUNT, bundle, + SyncStatusHelper.get(getActivity()).getContractAuthority(), + null, new SyncResult()); + } + @MediumTest @Feature({"Sync"}) public void testRequestSyncNoInvalidationData() { - SyncResult syncResult = new SyncResult(); - mSyncAdapter.onPerformSync(TEST_ACCOUNT, new Bundle(), - SyncStatusHelper.get(getActivity()).getContractAuthority(), null, syncResult); + performSyncWithBundle(new Bundle()); assertTrue(mSyncAdapter.mSyncRequestedForAllTypes); assertFalse(mSyncAdapter.mSyncRequested); assertTrue(CommandLine.isInitialized()); } private void testRequestSyncSpecificDataType(boolean withObjectSource) { - SyncResult syncResult = new SyncResult(); Bundle extras = new Bundle(); if (withObjectSource) { extras.putInt(ChromiumSyncAdapter.INVALIDATION_OBJECT_SOURCE_KEY, 61); @@ -86,8 +93,9 @@ extras.putString(ChromiumSyncAdapter.INVALIDATION_OBJECT_ID_KEY, "objectid_value"); extras.putLong(ChromiumSyncAdapter.INVALIDATION_VERSION_KEY, 42); extras.putString(ChromiumSyncAdapter.INVALIDATION_PAYLOAD_KEY, "payload_value"); - mSyncAdapter.onPerformSync(TEST_ACCOUNT, extras, - SyncStatusHelper.get(getActivity()).getContractAuthority(), null, syncResult); + + performSyncWithBundle(extras); + assertFalse(mSyncAdapter.mSyncRequestedForAllTypes); assertTrue(mSyncAdapter.mSyncRequested); if (withObjectSource) { @@ -117,11 +125,19 @@ @Feature({"Sync"}) public void testRequestSyncWhenChromeInBackground() throws InterruptedException { DelayedSyncControllerTest.sendChromeToBackground(getActivity()); - SyncResult syncResult = new SyncResult(); - mSyncAdapter.onPerformSync(TEST_ACCOUNT, new Bundle(), - SyncStatusHelper.get(getActivity()).getContractAuthority(), null, syncResult); + performSyncWithBundle(new Bundle()); assertFalse(mSyncAdapter.mSyncRequestedForAllTypes); assertFalse(mSyncAdapter.mSyncRequested); assertTrue(CommandLine.isInitialized()); } + + @MediumTest + @Feature({"Sync"}) + public void testRequestInitializeSync() throws InterruptedException { + Bundle extras = new Bundle(); + extras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true); + performSyncWithBundle(extras); + assertFalse(mSyncAdapter.mSyncRequestedForAllTypes); + assertFalse(mSyncAdapter.mSyncRequested); + } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorTabObserverTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorTabObserverTest.java new file mode 100644 index 0000000..fb947a5 --- /dev/null +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorTabObserverTest.java
@@ -0,0 +1,246 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.tabmodel; + +import android.test.InstrumentationTestCase; +import android.test.MoreAsserts; +import android.test.UiThreadTest; +import android.test.suitebuilder.annotation.SmallTest; + +import org.chromium.base.CommandLine; +import org.chromium.base.ObserverList; +import org.chromium.base.ThreadUtils; +import org.chromium.base.library_loader.ProcessInitException; +import org.chromium.chrome.browser.Tab; +import org.chromium.chrome.browser.TabObserver; +import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType; +import org.chromium.chrome.browser.tabmodel.TabModel.TabSelectionType; +import org.chromium.content.browser.BrowserStartupController; +import org.chromium.content_public.browser.LoadUrlParams; +import org.chromium.ui.base.WindowAndroid; + +/** + * Tests for the TabModelSelectorTabObserver. + */ +public class TabModelSelectorTabObserverTest extends InstrumentationTestCase { + + private TabModelSelectorBase mSelector; + private TabModel mNormalTabModel; + private TabModel mIncognitoTabModel; + + private WindowAndroid mWindowAndroid; + + @Override + public void setUp() throws Exception { + super.setUp(); + + ThreadUtils.runOnUiThreadBlocking(new Runnable() { + @Override + public void run() { + initialize(); + } + }); + } + + private void initialize() { + CommandLine.init(null); + try { + BrowserStartupController.get(getInstrumentation().getTargetContext()) + .startBrowserProcessesSync(false); + } catch (ProcessInitException e) { + fail("Unable to load native library"); + } + + mWindowAndroid = new WindowAndroid( + getInstrumentation().getTargetContext().getApplicationContext()); + + mSelector = new TabModelSelectorBase() { + @Override + public Tab openNewTab(LoadUrlParams loadUrlParams, TabLaunchType type, Tab parent, + boolean incognito) { + return null; + } + }; + + TabModelOrderController orderController = new TabModelOrderController(mSelector); + TabModelDelegate delegate = new TabModelDelegate() { + @Override + public void selectModel(boolean incognito) { + mSelector.selectModel(incognito); + } + + @Override + public void requestToShowTab(Tab tab, TabSelectionType type) { + } + + @Override + public boolean isSessionRestoreInProgress() { + return false; + } + + @Override + public boolean isInOverviewMode() { + return false; + } + + @Override + public TabModel getModel(boolean incognito) { + return mSelector.getModel(incognito); + } + + @Override + public TabModel getCurrentModel() { + return mSelector.getCurrentModel(); + } + }; + mNormalTabModel = new TabModelBase(false, orderController, delegate) { + @Override + protected Tab createTabWithNativeContents(boolean incognito, long nativeWebContents, + int parentId) { + return null; + } + + @Override + protected Tab createNewTabForDevTools(String url) { + return null; + } + }; + + mIncognitoTabModel = new TabModelBase(true, orderController, delegate) { + @Override + protected Tab createTabWithNativeContents(boolean incognito, long nativeWebContents, + int parentId) { + return null; + } + + @Override + protected Tab createNewTabForDevTools(String url) { + return null; + } + }; + + mSelector.initialize(false, mNormalTabModel, mIncognitoTabModel); + } + + @UiThreadTest + @SmallTest + public void testAddingTab() { + TestTabModelSelectorTabObserver observer = new TestTabModelSelectorTabObserver(); + TestTab tab = new TestTab(false); + assertTabDoesNotHaveObserver(tab, observer); + mNormalTabModel.addTab(tab, 0, TabModel.TabLaunchType.FROM_LINK); + assertTabHasObserver(tab, observer); + } + + @UiThreadTest + @SmallTest + public void testRemovingTab() { + TestTabModelSelectorTabObserver observer = new TestTabModelSelectorTabObserver(); + TestTab tab = new TestTab(false); + mNormalTabModel.addTab(tab, 0, TabModel.TabLaunchType.FROM_LINK); + assertTabHasObserver(tab, observer); + mNormalTabModel.closeTab(tab); + assertTabDoesNotHaveObserver(tab, observer); + } + + @UiThreadTest + @SmallTest + public void testPreExistingTabs() { + TestTab normalTab1 = new TestTab(false); + mNormalTabModel.addTab(normalTab1, 0, TabModel.TabLaunchType.FROM_LINK); + TestTab normalTab2 = new TestTab(false); + mNormalTabModel.addTab(normalTab2, 1, TabModel.TabLaunchType.FROM_LINK); + + TestTab incognitoTab1 = new TestTab(true); + mIncognitoTabModel.addTab(incognitoTab1, 0, TabModel.TabLaunchType.FROM_LINK); + TestTab incognitoTab2 = new TestTab(true); + mIncognitoTabModel.addTab(incognitoTab2, 1, TabModel.TabLaunchType.FROM_LINK); + + TestTabModelSelectorTabObserver observer = new TestTabModelSelectorTabObserver(); + assertTabHasObserver(normalTab1, observer); + assertTabHasObserver(normalTab2, observer); + assertTabHasObserver(incognitoTab1, observer); + assertTabHasObserver(incognitoTab2, observer); + } + + @UiThreadTest + @SmallTest + public void testDestroyRemovesObserver() { + TestTab normalTab1 = new TestTab(false); + mNormalTabModel.addTab(normalTab1, 0, TabModel.TabLaunchType.FROM_LINK); + TestTab incognitoTab1 = new TestTab(true); + mIncognitoTabModel.addTab(incognitoTab1, 0, TabModel.TabLaunchType.FROM_LINK); + + TestTabModelSelectorTabObserver observer = new TestTabModelSelectorTabObserver(); + assertTabHasObserver(normalTab1, observer); + assertTabHasObserver(incognitoTab1, observer); + + observer.destroy(); + assertTabDoesNotHaveObserver(normalTab1, observer); + assertTabDoesNotHaveObserver(incognitoTab1, observer); + } + + @UiThreadTest + @SmallTest + public void testObserverAddedBeforeInitialize() { + mSelector = new TabModelSelectorBase() { + @Override + public Tab openNewTab(LoadUrlParams loadUrlParams, TabLaunchType type, Tab parent, + boolean incognito) { + return null; + } + }; + TestTabModelSelectorTabObserver observer = new TestTabModelSelectorTabObserver(); + mSelector.initialize(false, mNormalTabModel, mIncognitoTabModel); + + TestTab normalTab1 = new TestTab(false); + mNormalTabModel.addTab(normalTab1, 0, TabModel.TabLaunchType.FROM_LINK); + assertTabHasObserver(normalTab1, observer); + + TestTab incognitoTab1 = new TestTab(true); + mIncognitoTabModel.addTab(incognitoTab1, 0, TabModel.TabLaunchType.FROM_LINK); + assertTabHasObserver(incognitoTab1, observer); + } + + private class TestTab extends Tab { + public TestTab(boolean incognito) { + super(incognito, null, mWindowAndroid); + initializeNative(); + } + + // Exists to expose the method to the test. + @Override + protected ObserverList.RewindableIterator<TabObserver> getTabObservers() { + return super.getTabObservers(); + } + } + + private class TestTabModelSelectorTabObserver extends TabModelSelectorTabObserver { + public TestTabModelSelectorTabObserver() { + super(mSelector); + } + } + + private void assertTabHasObserver(TestTab tab, TabObserver observer) { + ObserverList.RewindableIterator<TabObserver> tabObservers = tab.getTabObservers(); + tabObservers.rewind(); + boolean containsObserver = false; + while (tabObservers.hasNext()) { + if (tabObservers.next().equals(observer)) { + containsObserver = true; + break; + } + } + assertTrue(containsObserver); + } + + private void assertTabDoesNotHaveObserver(TestTab tab, TabObserver observer) { + ObserverList.RewindableIterator<TabObserver> tabObservers = tab.getTabObservers(); + tabObservers.rewind(); + while (tabObservers.hasNext()) { + MoreAsserts.assertNotEqual(tabObservers.next(), observer); + } + } +}
diff --git a/chrome/android/shell/java/AndroidManifest.xml b/chrome/android/shell/java/AndroidManifest.xml index 00e2caff..9962ea4 100644 --- a/chrome/android/shell/java/AndroidManifest.xml +++ b/chrome/android/shell/java/AndroidManifest.xml
@@ -14,6 +14,7 @@ android:protectionLevel="signature" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> + <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.GET_ACCOUNTS"/> <uses-permission android:name="android.permission.INTERNET"/>
diff --git a/chrome/android/sync_shell/java/AndroidManifest.xml b/chrome/android/sync_shell/java/AndroidManifest.xml index 2b96208f..8523c1f 100644 --- a/chrome/android/sync_shell/java/AndroidManifest.xml +++ b/chrome/android/sync_shell/java/AndroidManifest.xml
@@ -14,6 +14,7 @@ android:protectionLevel="signature" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> + <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.GET_ACCOUNTS"/> <uses-permission android:name="android.permission.INTERNET"/>
diff --git a/chrome/app/OWNERS b/chrome/app/OWNERS index 81113aa..ee667fe 100644 --- a/chrome/app/OWNERS +++ b/chrome/app/OWNERS
@@ -1,4 +1,9 @@ +# For .grd and .grdp changes, TBR an OWNER below. If you are not +# a google employee then you also need to file a bug in which the +# proposed strings have been approved. + cpu@chromium.org +grt@chromium.org per-file address_input_strings*=estade@chromium.org per-file address_input_strings*=rouslan@chromium.org
diff --git a/chrome/app/chrome_command_ids.h b/chrome/app/chrome_command_ids.h index a011e62..b3ecb3bb 100644 --- a/chrome/app/chrome_command_ids.h +++ b/chrome/app/chrome_command_ids.h
@@ -212,6 +212,7 @@ #define IDC_HELP_MENU 40244 #define IDC_EXTENSIONS_OVERFLOW_MENU 40245 #define IDC_SHOW_SRT_BUBBLE 40246 +#define IDC_ELEVATED_RECOVERY_DIALOG 40247 // Spell-check // Insert any additional suggestions before _LAST; these have to be consecutive.
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp index 8db6e43..33e7c0d56 100644 --- a/chrome/app/chromeos_strings.grdp +++ b/chrome/app/chromeos_strings.grdp
@@ -442,6 +442,9 @@ <message name="IDS_FILE_BROWSER_SHARE_BUTTON_LABEL" desc="Menu item label, showing dialog to share the selected file."> Share </message> + <message name="IDS_FILE_BROWSER_CLOUD_IMPORT_BUTTON_LABEL" desc="Label for button that initiates media backup to the cloud."> + Import Photos & Videos to Google Drive + </message> <message name="IDS_FILE_BROWSER_COPY_FILE_NAME" desc="File Manager status message."> Copying <ph name="FILE_NAME">$1<ex>movie.avi</ex></ph>...
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd index 88717a2..9a97acc 100644 --- a/chrome/app/chromium_strings.grd +++ b/chrome/app/chromium_strings.grd
@@ -1286,6 +1286,20 @@ Chromium could not update itself to the latest version, so you are missing out on awesome new features and security fixes. You need to update Chromium. </message> + <!-- Upgrade recovery bubble --> + <message name="IDS_RUN_RECOVERY" desc="Text for the button the user clicks to recover chromium and its updater."> + Update Chromium + </message> + <message name="IDS_DECLINE_RECOVERY" desc="Text for the button the user clicks to decline recovery request."> + No, thanks + </message> + <message name="IDS_RECOVERY_BUBBLE_TITLE" desc="Text for the title of the chrome recovery bubble view."> + Chromium is out of date + </message> + <message name="IDS_RECOVERY_BUBBLE_TEXT" desc="Text for the chrome recovery bubble view full description."> + Chromium could not update to the latest version, so you are missing out on new features and security fixes. You need to update Chromium. + </message> + <!-- Dialog that asks whether user wants to participate in Safe Browsing Extended Reporting --> <message name="IDS_FEEDBACK_SERVICE_DIALOG_TITLE" desc="Title of the dialog asking whether the user wants to upload suspected malicious files for analysis"> Help make Chromium better
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index ff49fe6..cbb0447 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -4578,6 +4578,16 @@ <message name="IDS_EXTENSION_PROMPT_WARNING_EXPERIENCE_SAMPLING_PRIVATE" desc="Permission string for Experience Sampling Private API."> Monitor when you take actions in Chrome </message> + <if expr="is_macosx"> + <message name="IDS_EXTENSION_PROMPT_WARNING_INTERCEPT_ALL_KEYS" desc="Permission string for intercept all keyboard keys via packaged app extension APIs"> + Read and change anything you type including task switching keys like CMD+TAB + </message> + </if> + <if expr="not is_macosx"> + <message name="IDS_EXTENSION_PROMPT_WARNING_INTERCEPT_ALL_KEYS" desc="Permission string for intercept all keyboard keys via packaged app extension APIs"> + Read and change anything you type including task switching keys like ALT+TAB + </message> + </if> <!-- Extension/App error messages --> <message name="IDS_EXTENSION_CANT_GET_ABSOLUTE_PATH" desc="Warning displayed in pack dialog when the absolute path to the extension directory can not be found."> @@ -6088,6 +6098,12 @@ <message name="IDS_FLAGS_ENABLE_TOUCH_FEEDBACK_DESCRIPTION" desc="Description for the flag to enable additional visual feedback for touch."> Certain UI components will display visual feedback upon touch interactions. </message> + <message name="IDS_FLAGS_DISABLE_TOUCH_FEEDBACK_NAME" desc="Title for the flag that disables additional visual feedback for touch."> + Disable additional touch feedback on UI components. + </message> + <message name="IDS_FLAGS_DISABLE_TOUCH_FEEDBACK_DESCRIPTION" desc="Description for the flag that disables additional visual feedback for touch."> + Certain UI components will stop displaying visual feedback upon touch interactions. + </message> <message name="IDS_FLAGS_ASH_DISABLE_TEXT_FILTERING_IN_OVERVIEW_MODE_NAME" desc="Title for the flag to disable window filtering in overview mode by inputing text"> Disable text filtering in Overview Mode. </message> @@ -6863,9 +6879,16 @@ <message name="IDS_HOTWORD_SEARCH_PREF_CHKBOX" desc="A checkbox on the Settings page to allow audio capture devices to initiate searches."> Enable "Ok Google" to start a voice search </message> - <message name="IDS_HOTWORD_SEARCH_NO_DSP_DESCRIPTION" desc="Description of the hotword search preference for devices with no DSP."> - Say "Ok Google" in a new tab, google.com, and the App Launcher - </message> + <if expr="chromeos"> + <message name="IDS_HOTWORD_SEARCH_NO_DSP_DESCRIPTION" desc="Description of the hotword search preference for devices with no DSP."> + Say "Ok Google" in a new tab, google.com, and the App Launcher + </message> + </if> + <if expr="not chromeos"> + <message name="IDS_HOTWORD_SEARCH_NO_DSP_DESCRIPTION" desc="Description of the hotword search preference for devices with no DSP."> + Say "Ok Google" in a new tab and google.com + </message> + </if> <message name="IDS_HOTWORD_SEARCH_ALWAYS_ON_DESCRIPTION" desc="Description of the hotword-always-on search preference."> Say "Ok Google" when the screen is on and unlocked. </message> @@ -6876,13 +6899,13 @@ When you say "Ok Google," Chrome will search for what you say next. </message> <message name="IDS_HOTWORD_AUDIO_HISTORY_ENABLED" desc="Text to display when the user has audio history enabled."> - Audio History is enabled for <ph name="USER_EMAIL">$1<ex>joe@gmail.com</ex></ph>. + Voice & Audio Activity is enabled for <ph name="USER_EMAIL">$1<ex>joe@gmail.com</ex></ph>. </message> <message name="IDS_HOTWORD_ALWAYS_ON_AUDIO_HISTORY_DESCRIPTION" desc="Description for the audio history message when always-on is enabled."> - Audio History is required to use "Ok Google" + Voice & Audio Activity is required to use "Ok Google" </message> <message name="IDS_HOTWORD_AUDIO_HISTORY_MANAGE_LINK" desc="Text for link to manage audio history."> - Manage Audio History + Manage Voice & Audio Activity </message> <message name="IDS_HOTWORD_CONFIRM_BUBBLE_TITLE" desc="The title text for the bubble to enable the hotword voice search trigger."> Ok Google @@ -10187,10 +10210,10 @@ Ask where to save each file before downloading </message> <message name="IDS_OPTIONS_EASY_UNLOCK_SECTION_TITLE" desc="The title of the Easy Unlock section on the settings page."> - Smart Lock (Beta) + Smart Lock (beta) </message> <message name="IDS_OPTIONS_EASY_UNLOCK_SETUP_INTRO" desc="The text to show in Easy Unlock section to introduce the feature."> - Keep your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph> unlocked when your Android phone is unlocked and nearby – no need to type your password. Learn more + Keep your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph> unlocked when your Android phone is unlocked and nearby—no need to type your password. </message> <message name="IDS_OPTIONS_EASY_UNLOCK_SETUP_BUTTON" desc="The label of the button to set up Easy Unlock section on the settings page."> Set up Smart Lock @@ -10202,7 +10225,7 @@ Only unlock this <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph> when your phone is within arm’s reach. </message> <message name="IDS_OPTIONS_EASY_UNLOCK_TURN_OFF_BUTTON" desc="The label of the button to disable Easy unlock on the settings page and the turn off Easy unlock dialog."> - Turn off + Turn off Smart Lock </message> <message name="IDS_OPTIONS_EASY_UNLOCK_NOTIFICATION_OPTION_LABEL" desc="The label of the preference in the Smart Lock settings page to control whether notifications should be shown when unlocking the Chromebook."> Get notified on your phone every time Smart Lock unlocks your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>. @@ -10211,10 +10234,10 @@ Manage Bluetooth settings </message> <message name="IDS_OPTIONS_EASY_UNLOCK_TURN_OFF_TITLE" desc="The title of the Easy unlock turn off dialog."> - Turn off Chrome Smart Lock + Turn off Smart Lock? </message> <message name="IDS_OPTIONS_EASY_UNLOCK_TURN_OFF_DESCRIPTION" desc="The description text of the Easy unlock turn off dialog."> - If you turn off Chrome Smart Lock, you won’t be able to unlock your Chrome devices when your phone is with you. You will have to type in your password. + If you turn off Smart Lock for Chrome, you won’t be able to unlock your Chrome devices using your phone. You will have to type in your password. </message> <message name="IDS_OPTIONS_EASY_UNLOCK_TURN_OFF_OFFLINE_TITLE" desc="The title text on the Easy unlock turn off dialog when Easy unlock could not be turned off because the device is offline."> Please connect to a network @@ -14855,6 +14878,14 @@ <message name="IDS_FLAGS_ENABLE_APP_INSTALL_ALERTS_DESCRIPTION" desc="Description to allow app install alerts"> If enabled, websites will be parsed for app install alert meta tags. </message> + + <!-- Flag strings for seccomp-bpf sandbox flag. --> + <message name="IDS_FLAGS_ENABLE_SECCOMP_FILTER_SANDBOX_ANDROID_NAME" desc="Title for the flag to enable the seccomp-bpf sandbox on Android."> + Enable seccomp-bpf renderer sandbox + </message> + <message name="IDS_FLAGS_ENABLE_SECCOMP_FILTER_SANDBOX_ANDROID_DESCRIPTION" desc="Description for the flag to enable the seccomp-bpf sandbox on Android."> + If enabled, renderers will have a second-layer sandbox provided by seccomp-bpf. This requires kernel features only available on select Android versions. + </message> </if> <!-- Extension Content Verification --> @@ -14902,10 +14933,10 @@ <!-- Easy Unlock strings --> <!-- Strings for the Easy Unlock promo notification --> <message name="IDS_EASY_UNLOCK_SETUP_NOTIFICATION_TITLE" desc="Title for the notification inviting the user to use the Easy Unlock feature."> - Chrome Smart Lock + Smart Lock for Chrome </message> <message name="IDS_EASY_UNLOCK_SETUP_NOTIFICATION_MESSAGE" desc="The body text for the notification inviting the user to use the Easy Unlock feature."> - Use your Android phone to unlock this <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>. No need to type your password again. + Tired of typing passwords? Use your phone to unlock your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>—no password needed. </message> <message name="IDS_EASY_UNLOCK_SETUP_NOTIFICATION_BUTTON_TITLE" desc="The text to show on the button in the notification inviting the user to use the Easy Unlock feature."> 1-minute setup @@ -14915,10 +14946,10 @@ Smart Lock is almost ready </message> <message name="IDS_EASY_UNLOCK_CHROMEBOOK_ADDED_NOTIFICATION_MESSAGE" desc="Message for the notification shown when this Chromebook is added to Easy Unlock as an additional Easy Unlock device."> - It will be activated next time you unlock this <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>. With Smart Lock, your phone will unlock this device—without a password. Bluetooth will be turned on to enable Smart Lock. + It will be activated next time you unlock this <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>. With Smart Lock, your phone will unlock this device—without a password. Bluetooth will be turned on to enable Smart Lock. </message> <message name="IDS_EASY_UNLOCK_CHROMEBOOK_ADDED_NOTIFICATION_ABOUT_BUTTON" desc="Label of a button on the new chrome notification to bring user to smart lock settings."> - About Smart Lock + Learn more </message> <!-- Strings for the phone changed (aka old Chromebook setup) notification --> <message name="IDS_EASY_UNLOCK_PAIRING_CHANGED_NOTIFICATION_TITLE" desc="Title for notification shown when the paired phone is changed."> @@ -14944,7 +14975,7 @@ <!-- Strings for the Easy Unlock setup dialog --> <!-- Step 1: Intro --> <message name="IDS_EASY_UNLOCK_SETUP_INTRO_HEADER_TITLE" desc="The text to show as the header title of the Easy Unlock dialog during the first, introductory step."> - Let’s get started + Get started with Smart Lock </message> <message name="IDS_EASY_UNLOCK_SETUP_INTRO_HEADER_TEXT" desc="The text to show as the header body text of the Easy Unlock dialog during the first, introductory step. Note that the <a> element surrounds a link; these HTML elements should be preserved in the translation."> Keep your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph> unlocked when your phone is unlocked and nearby. @@ -14959,15 +14990,15 @@ <message name="IDS_EASY_UNLOCK_SETUP_INTRO_RETRY_FIND_PHONE_BUTTON_LABEL" desc="The text to show as a label for the button in Easy Unlock setup dialog when the setup app fails to find any phones to be used. Finding a phone is the first setup step. Clicking the button restarts the setup flow."> Retry </message> - <message name="IDS_EASY_UNLOCK_SETUP_INTRO_HOW_IS_THIS_SECURE_LINK_TEXT" desc="The text to show as the 'How is it secure?' link text in the Easy Unlock dialog. This link is visible during the first, introductory step."> - How is it secure? + <message name="IDS_EASY_UNLOCK_SETUP_INTRO_HOW_IS_THIS_SECURE_LINK_TEXT" desc="The displayed text for the link that explains how the Easy Unlock feature is secure. This link is visible during the first, introductory step of the Easy Unlock setup dialog."> + How this is secure </message> <!-- Step 1.5: "Secure this phone to continue" --> <message name="IDS_EASY_UNLOCK_SETUP_SECURE_PHONE_HEADER_TITLE" desc="The text to show as the header title of the Easy Unlock dialog after a phone has been found but is not secured by a lock screen."> Secure this phone to continue </message> <message name="IDS_EASY_UNLOCK_SETUP_SECURE_PHONE_HEADER_TEXT" desc="The text to show as the header body text of the Easy Unlock dialog after a suitable phone has been found but is not secured by a lock screen. Note that the <a> element surrounds a link; these HTML elements should be preserved in the translation."> - To keep your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph> safe, Chrome Smart Lock requires a screen lock on your phone. <a>Learn how to secure your phone</a> + To keep your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph> safe, Smart Lock for Chrome requires a screen lock on your phone. <a>Learn how to secure your phone</a> </message> <!-- Step 2: Phone Found --> <message name="IDS_EASY_UNLOCK_SETUP_FOUND_PHONE_HEADER_TITLE" desc="The text to show as the header title of the Easy Unlock dialog during the second step, after a suitable phone has been found."> @@ -14990,23 +15021,23 @@ </message> <!-- Step 2.5: "Recommended: Set up Android Smart Lock" --> <message name="IDS_EASY_UNLOCK_SETUP_ANDROID_SMART_LOCK_HEADER_TITLE" desc="The text to show as the header title of the Easy Unlock dialog to encourage the user to enable Android Smart Lock if it is not currently enabled."> - Recommended: Set up Android Smart Lock + Recommended: Set up Smart Lock for Android </message> - <message name="IDS_EASY_UNLOCK_SETUP_ANDROID_SMART_LOCK_HEADER_TEXT" desc="The text to show as the header body text of the Easy Unlock dialog to encourage the user to enable Android Smart Lock if it is not currently enabled. Note that the <a> element surrounds a link; these HTML elements should be preserved in the translation."> - Update your phone's screen lock so it turns off when you're nearby. You'll unlock the phone faster, and enjoy a better Chrome Smart Lock experience. <a>About Android Smart Lock</a> + <message name="IDS_EASY_UNLOCK_SETUP_ANDROID_SMART_LOCK_HEADER_TEXT" desc="The text to show as the header body text of the Easy Unlock dialog to encourage the user to enable Smart Lock for Android if it is not currently enabled. Note that the <a> element surrounds a link; these HTML elements should be preserved in the translation."> + Update your phone's screen lock so it turns off when you're nearby. You'll unlock the phone faster, and enjoy a better Smart Lock experience on your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>. </message> - <message name="IDS_EASY_UNLOCK_SETUP_ANDROID_SMART_LOCK_DONE_BUTTON_LABEL" desc="The text to show as the button label in the Easy Unlock dialog step for encouraging the user to enable Android Smart Lock. Clicking this button advances the dialog to step 3."> + <message name="IDS_EASY_UNLOCK_SETUP_ANDROID_SMART_LOCK_DONE_BUTTON_LABEL" desc="The text to show as the button label in the Easy Unlock dialog step for encouraging the user to enable Smart Lock for Android. Clicking this button advances the dialog to step 3."> Done </message> - <message name="IDS_EASY_UNLOCK_SETUP_ANDROID_SMART_LOCK_ABOUT_LINK_TEXT" desc="The text to show as the link text to access the Android Smart Lock help article."> - About Android Smart Lock + <message name="IDS_EASY_UNLOCK_SETUP_ANDROID_SMART_LOCK_ABOUT_LINK_TEXT" desc="The text to show as the link text to access the Smart Lock for Android help article."> + About Smart Lock for Android </message> <!-- Step 3: "You're all set" --> <message name="IDS_EASY_UNLOCK_SETUP_COMPLETE_HEADER_TITLE" desc="The text to show as the header title of the Easy Unlock dialog during the penultimate step, confirming success."> You’re all set! </message> <message name="IDS_EASY_UNLOCK_SETUP_COMPLETE_HEADER_TEXT" desc="The text to show as the header body text of the Easy Unlock dialog during the penultimate step, confirming success."> - If you have other Chrome devices, they’ll be synced automatically, so your Android phone can unlock them, too. + If you have other Chrome devices, they’ll be synced automatically, so your phone will unlock them too. </message> <message name="IDS_EASY_UNLOCK_SETUP_COMPLETE_TRY_IT_OUT_BUTTON_LABEL" desc="The text to show as the 'Try it out' button label in the Easy Unlock dialog. This button is visible during the penultimate step, once the Easy Unlock setup succeeds."> Try it out @@ -15045,16 +15076,16 @@ </message> <!-- Easy Unlock strings shown on the lock screen --> <message name="IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_NO_BLUETOOTH" desc="Tooltip for an icon on a user's lock screen pod shown by Easy Unlock when the Chromebook doesn't have Bluetooth enabled."> - Bluetooth is off on this <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>. Type in your password to enter, and turn on Bluetooth. + Bluetooth is off on this <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>. Type your password to enter, and turn on Bluetooth. </message> <message name="IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_NO_PHONE" desc="Tooltip for an icon on a user's lock screen pod shown by Easy Unlock when a phone eligible to unlock the Chromebook cannot be found."> - Can’t find your Android phone. Make sure it’s with you and Bluetooth is turned on. + Can’t find your phone. Make sure it’s nearby and Bluetooth is turned on. </message> <message name="IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_PHONE_NOT_AUTHENTICATED" desc="Tooltip for an icon on a user's lock screen pod shown by Easy Unlock when no phones eligible to unlock the Chromebook can be authenticated."> Unable to unlock. Enter your password. </message> <message name="IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_PHONE_LOCKED" desc="Tooltip for an icon on a user's lock screen pod shown by Easy Unlock when a phone eligible to unlock the Chromebook is detected, but it's locked and thus not allowed to unlock the Chromebook."> - Your Android phone is locked. Unlock it to enter. + Your phone is locked. Unlock it to enter. </message> <message name="IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_PHONE_UNLOCKABLE" desc="Tooltip for an icon on a user's lock screen pod shown by Easy Unlock when a phone eligible to unlock the Chromebook is detected, but it does not have lock screen enabled, in which case it is not allowed to unlock Chromebooks."> Your Android phone must have a lock screen enabled before it can unlock this <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>. Otherwise, you will need to type in your password. @@ -15066,28 +15097,28 @@ Your Android phone is too far away from your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>. Bring it closer to enter. </message> <message name="IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_INITIAL_AUTHENTICATED" desc="Tooltip text shown on lock screen when a phone eligible to unlock the Chromebook via Easy Unlock is detected and authenticated for the first time."> - When your phone is unlocked and nearby, you can just click to enter. Otherwise, you'll see a locked icon and need to type your password. + When your phone is unlocked and nearby, just click to enter. Otherwise, you'll see a locked icon and need to type your password. </message> <message name="IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_HARDLOCK_INSTRUCTIONS" desc="Tooltip for an icon on user's lock screen pod shown by Easy Unlock when a phone eligible to unlock the Chromebook is detected and authenticated. The tooltip shows instructions for hard-locking the Chromebook."> - If you click this icon, you can manually lock this <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>. Next time, you’ll need to enter your password to unlock it. + If you click this icon, you will manually lock this <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>. Next time, you’ll need to type your password to enter. </message> <message name="IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_UNSUPPORTED_ANDROID_VERSION" desc="Tooltip for the icon on user's lock screen pod shown by Easy Unlock when a phone set up to unlock the Chromebook is detected, but has an unsupported Android version. The user is asked to update the phone."> Please update your phone to a newer version of Android to unlock this <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>. </message> <message name="IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_HARDLOCK_USER" desc="Tooltip text shown on a user's lock screen pod when Easy Unlock feature is enabled for the user, but the user hard locked the device. Hard lock is done by clicking the Easy Unlock icon on the user's pod. When a device is hard locked by a user, the Easy Unlock cannot be used to unlock the device as that user. A password has to be entered to unlock the device."> - Your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph> has been manually locked. You'll need to enter your password to unlock it. + Your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph> has been manually locked. You'll need to type your password to enter. </message> <message name="IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_HARDLOCK_PAIRING_CHANGED" desc="Tooltip text shown on a user's lock screen pod when Easy Unlock feature is enabled for the user, but the pairing data is changed. A password has to be entered to unlock the device."> Your phone for Smart Lock changed. Type your password to update Smart Lock on this device. Next time, you can just click your picture to enter. </message> <message name="IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_HARDLOCK_PAIRING_ADDED" desc="Tooltip text shown on a user's lock screen pod when Easy Unlock pairing data is synced on a new Chromebook."> - One-time activation: Type your password to activate Smart Lock. With Smart Lock, your phone will unlock this Chromebook—without a password. To change or disable this feature, visit your Chromebook's settings. + One-time activation: Type your password to activate Smart Lock. With Smart Lock, your phone will unlock this <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>—without a password. To change or disable this feature, visit your <ph name="DEVICE_TYPE">$2<ex>Chromebook</ex></ph>'s settings. </message> <message name="IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_LOGIN_FAILURE" desc="Tooltip text shown on a user's lock screen when Smart Lock signin attempt fails."> Smart Lock couldn't verify your account. Type your password to enter. </message> <message name="IDS_SMART_LOCK_SCREENLOCK_TOOLTIP_HARDLOCK_REAUTH_USER" desc="Tooltip text shown on a user's lock screen pod to reauthenticate the user before setting up Smart Lock. A password has to be entered to unlock the device."> - To set up Chrome Smart Lock, Google needs to make sure it's you--type your password to get started. + To set up Smart Lock for Chrome, Google needs to make sure it's you—type your password to get started. </message> <message name="IDS_EASY_UNLOCK_SCREENLOCK_USER_POD_AUTH_VALUE" desc="Message on lock screen user pod shown in place of password field when Easy Unlock is enabled and a phone that can unlock the Chromebook is detected in proximity."> Click to enter @@ -15237,13 +15268,24 @@ <message name="IDS_HOTWORD_OPT_IN_FINISH" desc="Text on the finish button for the 'Ok Google' hotword opt-in dialog."> OK </message> - <message name="IDS_HOTWORD_OPT_IN_FINISHED_WAIT" desc="The text displayed when waiting for the voice model training to complete. "> + <message name="IDS_HOTWORD_OPT_IN_FINISHED_WAIT" desc="The text displayed when waiting for the voice model training to complete."> Processing ... </message> <message name="IDS_CAPTIVE_PORTAL_AUTHORIZATION_DIALOG_NAME" desc="Name of the modal Web dialog (displayed in the title) displaying captive portal login page on ChromeOS."> Captive Portal Authorization </message> + + <!-- Hotword Notification --> + <message name="IDS_HOTWORD_NOTIFICATION_TITLE" desc="The text displayed as the title for the hotword notification. "> + Voice search at any time + </message> + <message name="IDS_HOTWORD_NOTIFICATION_DESCRIPTION" desc="The text displayed as the description for the hotword notification. "> + Enable "Ok Google" to voice search when your screen is on and unlocked + </message> + <message name="IDS_HOTWORD_NOTIFICATION_BUTTON" desc="The text displayed on the button of the hotword notification. "> + Enable "Ok Google" + </message> </messages> </release> </grit>
diff --git a/chrome/app/google_chrome_strings.grd b/chrome/app/google_chrome_strings.grd index 9b9eb0f..a5fa4c38 100644 --- a/chrome/app/google_chrome_strings.grd +++ b/chrome/app/google_chrome_strings.grd
@@ -1211,6 +1211,20 @@ Chrome could not update itself to the latest version, so you are missing out on awesome new features and security fixes. You need to update Chrome. </message> + <!-- Upgrade recovery bubble --> + <message name="IDS_RUN_RECOVERY" desc="Text for the button the user clicks to recover Chrome and its updater."> + Update Chrome + </message> + <message name="IDS_DECLINE_RECOVERY" desc="Text for the button the user clicks to decline recovery request."> + No, thanks + </message> + <message name="IDS_RECOVERY_BUBBLE_TITLE" desc="Text for the title of the chrome recovery bubble view."> + Chrome is out of date + </message> + <message name="IDS_RECOVERY_BUBBLE_TEXT" desc="Text for the chrome recovery bubble view full description."> + Chrome could not update to the latest version, so you are missing out on new features and security fixes. You need to update Chrome. + </message> + <!-- Dialog that asks whether user wants to participate in Safe Browsing Extended Reporting --> <message name="IDS_FEEDBACK_SERVICE_DIALOG_TITLE" desc="Title of the dialog asking whether the user wants to upload suspected malicious files for analysis"> Help make Chrome better
diff --git a/chrome/app/theme/default_100_percent/common/notification_hotword_icon.png b/chrome/app/theme/default_100_percent/common/notification_hotword_icon.png new file mode 100644 index 0000000..95c161bc --- /dev/null +++ b/chrome/app/theme/default_100_percent/common/notification_hotword_icon.png Binary files differ
diff --git a/chrome/app/theme/default_100_percent/mac/avatar_button/sign_in_button_avatar.png b/chrome/app/theme/default_100_percent/mac/avatar_button/sign_in_button_avatar.png index 3dc773ce..8c265c8 100644 --- a/chrome/app/theme/default_100_percent/mac/avatar_button/sign_in_button_avatar.png +++ b/chrome/app/theme/default_100_percent/mac/avatar_button/sign_in_button_avatar.png Binary files differ
diff --git a/chrome/app/theme/default_100_percent/mac/avatar_button/sign_in_button_avatar_hover.png b/chrome/app/theme/default_100_percent/mac/avatar_button/sign_in_button_avatar_hover.png index 8dc3327..3bb45bf 100644 --- a/chrome/app/theme/default_100_percent/mac/avatar_button/sign_in_button_avatar_hover.png +++ b/chrome/app/theme/default_100_percent/mac/avatar_button/sign_in_button_avatar_hover.png Binary files differ
diff --git a/chrome/app/theme/default_100_percent/mac/avatar_button/sign_in_button_avatar_pressed.png b/chrome/app/theme/default_100_percent/mac/avatar_button/sign_in_button_avatar_pressed.png index 8dc3327..3bb45bf 100644 --- a/chrome/app/theme/default_100_percent/mac/avatar_button/sign_in_button_avatar_pressed.png +++ b/chrome/app/theme/default_100_percent/mac/avatar_button/sign_in_button_avatar_pressed.png Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/notification_hotword_icon.png b/chrome/app/theme/default_200_percent/common/notification_hotword_icon.png new file mode 100644 index 0000000..87aa19c --- /dev/null +++ b/chrome/app/theme/default_200_percent/common/notification_hotword_icon.png Binary files differ
diff --git a/chrome/app/theme/default_200_percent/mac/avatar_button/sign_in_button_avatar.png b/chrome/app/theme/default_200_percent/mac/avatar_button/sign_in_button_avatar.png index 72b99da..c235cc1 100644 --- a/chrome/app/theme/default_200_percent/mac/avatar_button/sign_in_button_avatar.png +++ b/chrome/app/theme/default_200_percent/mac/avatar_button/sign_in_button_avatar.png Binary files differ
diff --git a/chrome/app/theme/default_200_percent/mac/avatar_button/sign_in_button_avatar_hover.png b/chrome/app/theme/default_200_percent/mac/avatar_button/sign_in_button_avatar_hover.png index de5bc5d..ac1f2b1 100644 --- a/chrome/app/theme/default_200_percent/mac/avatar_button/sign_in_button_avatar_hover.png +++ b/chrome/app/theme/default_200_percent/mac/avatar_button/sign_in_button_avatar_hover.png Binary files differ
diff --git a/chrome/app/theme/default_200_percent/mac/avatar_button/sign_in_button_avatar_pressed.png b/chrome/app/theme/default_200_percent/mac/avatar_button/sign_in_button_avatar_pressed.png index 13b65d2..0f64459 100644 --- a/chrome/app/theme/default_200_percent/mac/avatar_button/sign_in_button_avatar_pressed.png +++ b/chrome/app/theme/default_200_percent/mac/avatar_button/sign_in_button_avatar_pressed.png Binary files differ
diff --git a/chrome/app/theme/theme_resources.grd b/chrome/app/theme/theme_resources.grd index b606025..812e50d6 100644 --- a/chrome/app/theme/theme_resources.grd +++ b/chrome/app/theme/theme_resources.grd
@@ -351,6 +351,7 @@ <structure type="chrome_scaled_image" name="IDR_HOME_H" file="common/browser_home_hover.png" /> <structure type="chrome_scaled_image" name="IDR_HOME_P" file="common/browser_home_pressed.png" /> </if> + <structure type="chrome_scaled_image" name="IDR_HOTWORD_NOTIFICATION_ICON" file="common/notification_hotword_icon.png" /> <if expr="not is_android and not is_ios"> <structure type="chrome_scaled_image" name="IDR_ICON_PROFILES_ADD_USER" file="common/icon_add_user.png" /> <structure type="chrome_scaled_image" name="IDR_ICON_PROFILES_BROWSE_GUEST" file="common/icon_browse_as_guest.png" /> @@ -1206,7 +1207,6 @@ <structure type="chrome_scaled_image" name="IDR_PEOPLE_SEARCH_ACTION_CHAT" file="common/chat.png" /> <structure type="chrome_scaled_image" name="IDR_PEOPLE_SEARCH_ACTION_CHAT_HOVER" file="common/chat_hover.png" /> <structure type="chrome_scaled_image" name="IDR_PEOPLE_SEARCH_ACTION_CHAT_PRESSED" file="common/chat_pressed.png" /> - </structures> </release> </grit>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index dafc5af..8ecfdef6 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -658,12 +658,12 @@ "//ui/app_list", ] } - if (enable_managed_users) { + if (enable_supervised_users) { sources += rebase_path( gypi_values.chrome_browser_supervised_user_sources, ".", "//chrome") } - if (enable_managed_users && enable_themes) { + if (enable_supervised_users && enable_themes) { sources += rebase_path( gypi_values.chrome_browser_supervised_user_and_themes_sources, ".", "//chrome")
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index cdc0ff2..d38a609 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -958,11 +958,11 @@ SINGLE_VALUE_TYPE(ash::switches::kAshEnableTouchViewTesting), }, { - "enable-touch-feedback", - IDS_FLAGS_ENABLE_TOUCH_FEEDBACK_NAME, - IDS_FLAGS_ENABLE_TOUCH_FEEDBACK_DESCRIPTION, + "disable-touch-feedback", + IDS_FLAGS_DISABLE_TOUCH_FEEDBACK_NAME, + IDS_FLAGS_DISABLE_TOUCH_FEEDBACK_DESCRIPTION, kOsCrOS, - SINGLE_VALUE_TYPE(switches::kEnableTouchFeedback), + SINGLE_VALUE_TYPE(switches::kDisableTouchFeedback), }, { "ash-disable-text-filtering-in-overview-mode", IDS_FLAGS_ASH_DISABLE_TEXT_FILTERING_IN_OVERVIEW_MODE_NAME, @@ -1525,7 +1525,7 @@ "enable-streamlined-hosted-apps", IDS_FLAGS_ENABLE_STREAMLINED_HOSTED_APPS_NAME, IDS_FLAGS_ENABLE_STREAMLINED_HOSTED_APPS_DESCRIPTION, - kOsWin | kOsCrOS | kOsLinux, + kOsWin | kOsCrOS | kOsLinux | kOsMac, SINGLE_VALUE_TYPE(switches::kEnableStreamlinedHostedApps) }, { @@ -2041,6 +2041,15 @@ SINGLE_VALUE_TYPE(chromeos::switches::kEnableCaptivePortalBypassProxy) }, #endif // defined(OS_CHROMEOS) +#if defined(OS_ANDROID) + { + "enable-seccomp-filter-sandbox", + IDS_FLAGS_ENABLE_SECCOMP_FILTER_SANDBOX_ANDROID_NAME, + IDS_FLAGS_ENABLE_SECCOMP_FILTER_SANDBOX_ANDROID_DESCRIPTION, + kOsAndroid, + SINGLE_VALUE_TYPE(switches::kEnableSeccompFilterSandbox) + }, +#endif // NOTE: Adding new command-line switches requires adding corresponding // entries to enum "LoginCustomFlags" in histograms.xml. See note in
diff --git a/chrome/browser/android/signin/signin_manager_android.cc b/chrome/browser/android/signin/signin_manager_android.cc index 2397f5f..d9e5042 100644 --- a/chrome/browser/android/signin/signin_manager_android.cc +++ b/chrome/browser/android/signin/signin_manager_android.cc
@@ -298,6 +298,10 @@ return SigninManagerFactory::GetForProfile(profile_)->IsSigninAllowed(); } +jboolean SigninManagerAndroid::IsSignedInOnNative(JNIEnv* env, jobject obj) { + return SigninManagerFactory::GetForProfile(profile_)->IsAuthenticated(); +} + void SigninManagerAndroid::OnSigninAllowedPrefChanged() { Java_SigninManager_onSigninAllowedByPolicyChanged( base::android::AttachCurrentThread(), java_signin_manager_.obj(),
diff --git a/chrome/browser/android/signin/signin_manager_android.h b/chrome/browser/android/signin/signin_manager_android.h index 6db3c22..ce4a95d 100644 --- a/chrome/browser/android/signin/signin_manager_android.h +++ b/chrome/browser/android/signin/signin_manager_android.h
@@ -64,6 +64,8 @@ jboolean IsSigninAllowedByPolicy(JNIEnv* env, jobject obj); + jboolean IsSignedInOnNative(JNIEnv* env, jobject obj); + private: virtual ~SigninManagerAndroid();
diff --git a/chrome/browser/app_icon_win.cc b/chrome/browser/app_icon_win.cc index e893b4e..dafde451 100644 --- a/chrome/browser/app_icon_win.cc +++ b/chrome/browser/app_icon_win.cc
@@ -33,6 +33,17 @@ MAKEINTRESOURCE(icon_id)); } +HICON GetSmallAppIcon() { + const int icon_id = GetAppIconResourceId(); + return static_cast<HICON>(LoadImage( + GetModuleHandle(chrome::kBrowserResourcesDll), + MAKEINTRESOURCE(icon_id), + IMAGE_ICON, + GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), + LR_DEFAULTCOLOR)); +} + scoped_ptr<SkBitmap> GetAppIconForSize(int size) { const int icon_id = GetAppIconResourceId(); return IconUtil::CreateSkBitmapFromIconResource(
diff --git a/chrome/browser/app_icon_win.h b/chrome/browser/app_icon_win.h index d15ac6c..7a29d1f3 100644 --- a/chrome/browser/app_icon_win.h +++ b/chrome/browser/app_icon_win.h
@@ -12,6 +12,7 @@ class SkBitmap; HICON GetAppIcon(); +HICON GetSmallAppIcon(); // Retrieve the application icon for the given size. Note that if you specify a // size other than what is contained in chrome.dll (16x16, 32x32, 48x48), this
diff --git a/chrome/browser/apps/app_browsertest.cc b/chrome/browser/apps/app_browsertest.cc index 9db785e..7d604b4 100644 --- a/chrome/browser/apps/app_browsertest.cc +++ b/chrome/browser/apps/app_browsertest.cc
@@ -20,6 +20,7 @@ #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/renderer_context_menu/render_view_context_menu.h" #include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/extensions/app_launch_params.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/webui/print_preview/print_preview_ui.h" @@ -42,9 +43,11 @@ #include "extensions/browser/notification_types.h" #include "extensions/browser/pref_names.h" #include "extensions/common/api/app_runtime.h" +#include "extensions/common/constants.h" #include "extensions/test/extension_test_message_listener.h" #include "extensions/test/result_catcher.h" #include "net/test/embedded_test_server/embedded_test_server.h" +#include "ui/base/window_open_disposition.h" #include "url/gurl.h" #if defined(OS_CHROMEOS) @@ -508,8 +511,8 @@ ASSERT_TRUE(extension); // Run the test - AppLaunchParams params( - browser()->profile(), extension, LAUNCH_CONTAINER_NONE, NEW_WINDOW); + AppLaunchParams params(browser()->profile(), extension, LAUNCH_CONTAINER_NONE, + NEW_WINDOW, extensions::SOURCE_UNTRACKED); params.command_line = *CommandLine::ForCurrentProcess(); params.current_directory = test_data_dir_; OpenApplication(params); @@ -838,8 +841,9 @@ content::WindowedNotificationObserver app_loaded_observer( content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME, content::NotificationService::AllSources()); - OpenApplication(AppLaunchParams( - browser()->profile(), extension, LAUNCH_CONTAINER_NONE, NEW_WINDOW)); + OpenApplication(AppLaunchParams(browser()->profile(), extension, + LAUNCH_CONTAINER_NONE, NEW_WINDOW, + extensions::SOURCE_UNTRACKED)); app_loaded_observer.Wait(); window = GetFirstAppWindow(); ASSERT_TRUE(window); @@ -983,8 +987,9 @@ ASSERT_TRUE(should_install.seen()); ExtensionTestMessageListener launched_listener("Launched", false); - OpenApplication(AppLaunchParams( - browser()->profile(), extension, LAUNCH_CONTAINER_NONE, NEW_WINDOW)); + OpenApplication(AppLaunchParams(browser()->profile(), extension, + LAUNCH_CONTAINER_NONE, NEW_WINDOW, + extensions::SOURCE_UNTRACKED)); ASSERT_TRUE(launched_listener.WaitUntilSatisfied()); } @@ -1006,8 +1011,9 @@ ASSERT_TRUE(extension); ExtensionTestMessageListener launched_listener("Launched", false); - OpenApplication(AppLaunchParams( - browser()->profile(), extension, LAUNCH_CONTAINER_NONE, NEW_WINDOW)); + OpenApplication(AppLaunchParams(browser()->profile(), extension, + LAUNCH_CONTAINER_NONE, NEW_WINDOW, + extensions::SOURCE_UNTRACKED)); ASSERT_TRUE(launched_listener.WaitUntilSatisfied()); ASSERT_FALSE(should_not_install.seen()); @@ -1043,8 +1049,9 @@ ASSERT_TRUE(should_install.seen()); ExtensionTestMessageListener launched_listener("Launched", false); - OpenApplication(AppLaunchParams( - browser()->profile(), extension, LAUNCH_CONTAINER_NONE, NEW_WINDOW)); + OpenApplication(AppLaunchParams(browser()->profile(), extension, + LAUNCH_CONTAINER_NONE, NEW_WINDOW, + extensions::SOURCE_UNTRACKED)); ASSERT_TRUE(launched_listener.WaitUntilSatisfied()); } @@ -1066,8 +1073,9 @@ { ExtensionTestMessageListener launched_listener("Launched", false); - OpenApplication(AppLaunchParams( - browser()->profile(), extension, LAUNCH_CONTAINER_NONE, NEW_WINDOW)); + OpenApplication(AppLaunchParams(browser()->profile(), extension, + LAUNCH_CONTAINER_NONE, NEW_WINDOW, + extensions::SOURCE_UNTRACKED)); ASSERT_TRUE(launched_listener.WaitUntilSatisfied()); } @@ -1217,8 +1225,9 @@ ASSERT_TRUE(registry != NULL); registry->AddObserver(this); - OpenApplication(AppLaunchParams( - incognito_profile, file_manager, 0, chrome::HOST_DESKTOP_TYPE_NATIVE)); + OpenApplication(AppLaunchParams(incognito_profile, file_manager, CURRENT_TAB, + chrome::HOST_DESKTOP_TYPE_NATIVE, + extensions::SOURCE_UNTRACKED)); while (!ContainsKey(opener_app_ids_, file_manager->id())) { content::RunAllPendingInMessageLoop();
diff --git a/chrome/browser/apps/app_browsertest_util.cc b/chrome/browser/apps/app_browsertest_util.cc index f8d804ea..169883f 100644 --- a/chrome/browser/apps/app_browsertest_util.cc +++ b/chrome/browser/apps/app_browsertest_util.cc
@@ -11,6 +11,7 @@ #include "chrome/browser/extensions/extension_function_test_utils.h" #include "chrome/browser/ui/apps/chrome_app_delegate.h" #include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/extensions/app_launch_params.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "content/public/browser/notification_service.h" #include "content/public/test/browser_test_utils.h" @@ -19,6 +20,7 @@ #include "extensions/browser/app_window/app_window_registry.h" #include "extensions/browser/app_window/native_app_window.h" #include "extensions/browser/process_manager.h" +#include "extensions/common/constants.h" #include "extensions/common/switches.h" #include "extensions/test/extension_test_message_listener.h" @@ -112,8 +114,9 @@ } void PlatformAppBrowserTest::LaunchPlatformApp(const Extension* extension) { - OpenApplication(AppLaunchParams( - browser()->profile(), extension, LAUNCH_CONTAINER_NONE, NEW_WINDOW)); + OpenApplication(AppLaunchParams(browser()->profile(), extension, + LAUNCH_CONTAINER_NONE, NEW_WINDOW, + extensions::SOURCE_UNTRACKED)); } WebContents* PlatformAppBrowserTest::GetFirstAppWindowWebContents() {
diff --git a/chrome/browser/apps/app_window_browsertest.cc b/chrome/browser/apps/app_window_browsertest.cc index 12bcbab..4674257e 100644 --- a/chrome/browser/apps/app_window_browsertest.cc +++ b/chrome/browser/apps/app_window_browsertest.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/apps/app_browsertest_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/extensions/app_launch_params.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "content/public/browser/notification_service.h" #include "content/public/test/test_utils.h" @@ -216,10 +217,9 @@ test_data_dir_.AppendASCII("platform_apps").AppendASCII("window_api")); EXPECT_TRUE(extension); - OpenApplication(AppLaunchParams(browser()->profile(), - extension, - extensions::LAUNCH_CONTAINER_NONE, - NEW_WINDOW)); + OpenApplication(AppLaunchParams(browser()->profile(), extension, + extensions::LAUNCH_CONTAINER_NONE, NEW_WINDOW, + extensions::SOURCE_UNTRACKED)); ExtensionTestMessageListener geometry_listener("ListenGeometryChange", true);
diff --git a/chrome/browser/apps/app_window_intercept_all_keys_uitest.cc b/chrome/browser/apps/app_window_intercept_all_keys_uitest.cc new file mode 100644 index 0000000..14c069b --- /dev/null +++ b/chrome/browser/apps/app_window_intercept_all_keys_uitest.cc
@@ -0,0 +1,364 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/callback.h" +#include "base/logging.h" +#include "base/macros.h" +#include "base/strings/stringprintf.h" +#include "chrome/browser/apps/app_browsertest_util.h" +#include "chrome/test/base/interactive_test_utils.h" +#include "extensions/browser/app_window/native_app_window.h" +#include "extensions/test/extension_test_message_listener.h" +#include "testing/gtest/include/gtest/gtest-spi.h" + +using extensions::NativeAppWindow; + +class AppWindowInterceptAllKeysTest + : public extensions::PlatformAppBrowserTest { + public: + // Send key to window but does not wait till the key is actually in the input + // queue (like ui_test_utils::SendKeyPressToWindowSync()) as key will not be + // sent to hook when keyboard is intercepted. + bool SimulateKeyPress(ui::KeyboardCode key, + bool control, + bool shift, + bool alt, + bool command) { + DVLOG(1) << "Sending: " << key << " control = " << control + << " shift = " << shift << " alt = " << alt + << " command = " << command; + if (!ui_controls::SendKeyPressNotifyWhenDone( + GetFirstAppWindow()->GetNativeWindow(), key, control, shift, alt, + command, null_callback_)) { + LOG(WARNING) << "Failed to send key to app"; + failure_message_ = "Failed to send key to app."; + return false; + } + + base::RunLoop().RunUntilIdle(); + return !testing::Test::HasFatalFailure(); + } + + bool SimulateKeyPress(ui::KeyboardCode key) { + return SimulateKeyPress(key, false, false, false, false); + } + + bool WaitForKeyEvent(ui::KeyboardCode code) { + std::string key_event = base::StringPrintf("KeyReceived: %d", code); + ExtensionTestMessageListener key_listener(key_event, false); + + if (!SimulateKeyPress(code)) { + failure_message_ = "Failed to send key to app"; + return false; + } + + key_listener.WaitUntilSatisfied(); + + DVLOG(1) << "Application ACK-ed keypress"; + return true; + } + + bool LoadApplication(const char* app_path) { + DVLOG(1) << "Launching app = " << app_path; + LoadAndLaunchPlatformApp(app_path, "Launched"); + + DVLOG(1) << "Validating that application is in focus"; + // We start by making sure the window is actually focused. + if (!ui_test_utils::ShowAndFocusNativeWindow( + GetFirstAppWindow()->GetNativeWindow())) { + failure_message_ = "App did not get focus."; + return false; + } + + DVLOG(1) << "Launched application"; + return true; + } + + void SendTaskSwitchKeys() { + // Send switch sequence (currently just for windows - will have to update as + // more platform support is added). + SimulateKeyPress(ui::VKEY_TAB, false, false, true, false); + } + + void ValidateCannotInterceptKeys(const char* app_path, + bool change_intercept, + bool enable_intercept) { + ExtensionTestMessageListener command_listener("readyForCommand", true); + ASSERT_TRUE(LoadApplication(app_path)) << failure_message_; + + const char* message = ""; + if (change_intercept) { + message = enable_intercept ? "enable" : "disable"; + } + ASSERT_TRUE(command_listener.WaitUntilSatisfied()); + command_listener.Reply(message); + command_listener.Reset(); + + ASSERT_TRUE(WaitForKeyEvent(ui::VKEY_Z)) << failure_message_; + + SendTaskSwitchKeys(); + + // Send key and check if it is received. + ASSERT_FALSE(SimulateKeyPress(ui::VKEY_Z)) << failure_message_; + } + + void ValidateInterceptKeys(bool disable_after_enabling) { + ExtensionTestMessageListener command_listener("readyForCommand", true); + ASSERT_TRUE(LoadApplication(app_with_permission_)) << failure_message_; + + // setInterceptAllKeys() is asynchronous so wait for response and receiving + // a key back. + ASSERT_TRUE(command_listener.WaitUntilSatisfied()); + command_listener.Reply("enable"); + command_listener.Reset(); + + ASSERT_TRUE(WaitForKeyEvent(ui::VKEY_Z)) << failure_message_; + + SendTaskSwitchKeys(); + + // Send key and check if it is received. + ASSERT_TRUE(SimulateKeyPress(ui::VKEY_Z)) << failure_message_; + + ASSERT_TRUE(WaitForKeyEvent(ui::VKEY_Z)) << failure_message_; + + if (disable_after_enabling) { + ASSERT_TRUE(command_listener.WaitUntilSatisfied()); + command_listener.Reply("disable"); + command_listener.Reset(); + ASSERT_TRUE(command_listener.WaitUntilSatisfied()); + } + } + + protected: + std::string failure_message_; + base::Callback<void(void)> null_callback_; + const char* app_with_permission_ = + "window_api_intercept_all_keys/has_permission"; + const char* app_without_permission_ = + "window_api_intercept_all_keys/no_permission"; +}; + +// Currently this is implemented only for Windows. +// Disabled test http://crbug.com/438209 +#if defined(OS_WIN) +#define MAYBE_GetKeysAfterSwitchSequence DISABLED_GetKeysAfterSwitchSequence +#else +#define MAYBE_GetKeysAfterSwitchSequence DISABLED_GetKeysAfterSwitchSequence +#endif + +// Tests a window continues to keep focus even after application switch key +// sequence is sent when setInterceptAllKeys() is enabled. +IN_PROC_BROWSER_TEST_F(AppWindowInterceptAllKeysTest, + MAYBE_GetKeysAfterSwitchSequence) { + ValidateInterceptKeys(false); +} + +// Test to make sure that keys not received after disable. +// Disabled test http://crbug.com/438209 +#if defined(OS_WIN) +#define MAYBE_NoKeysAfterDisableIsCalled DISABLED_NoKeysAfterDisableIsCalled +#else +#define MAYBE_NoKeysAfterDisableIsCalled DISABLED_NoKeysAfterDisableIsCalled +#endif + +IN_PROC_BROWSER_TEST_F(AppWindowInterceptAllKeysTest, + MAYBE_NoKeysAfterDisableIsCalled) { + ValidateInterceptKeys(true); + + ASSERT_TRUE(WaitForKeyEvent(ui::VKEY_Z)) << failure_message_; + + SendTaskSwitchKeys(); + + // Send key and check if it is received. + ASSERT_FALSE(SimulateKeyPress(ui::VKEY_Z)) << failure_message_; +} + +// Test that calling just disable has no effect in retaining keyboard intercept. +// Currently this is implemented only for Windows. +// Disabled test http://crbug.com/438209 +#if defined(OS_WIN) +#define MAYBE_NoopCallingDisableInterceptAllKeys \ + DISABLED_NoopCallingDisableInterceptAllKeys +#else +#define MAYBE_NoopCallingDisableInterceptAllKeys \ + DISABLED_NoopCallingDisableInterceptAllKeys +#endif + +IN_PROC_BROWSER_TEST_F(AppWindowInterceptAllKeysTest, + MAYBE_NoopCallingDisableInterceptAllKeys) { + ValidateCannotInterceptKeys(app_with_permission_, true, false); +} + +// Test no effect when called without permissions +// Currently this is implemented only for Windows. +#if defined(OS_WIN) +#define MAYBE_NoopCallingEnableWithoutPermission \ + NoopCallingEnableWithoutPermission +#else +#define MAYBE_NoopCallingEnableWithoutPermission \ + DISABLED_NoopCallingEnableWithoutPermission +#endif + +IN_PROC_BROWSER_TEST_F(AppWindowInterceptAllKeysTest, + MAYBE_NoopCallingEnableWithoutPermission) { + ValidateCannotInterceptKeys(app_without_permission_, true, true); +} + +// Test that intercept is disabled by default +#if defined(OS_WIN) +// Disabled test http://crbug.com/438209 +#define MAYBE_InterceptDisabledByDefault DISABLED_InterceptDisabledByDefault +#else +#define MAYBE_InterceptDisabledByDefault DISABLED_InterceptDisabledByDefault +#endif + +IN_PROC_BROWSER_TEST_F(AppWindowInterceptAllKeysTest, + MAYBE_InterceptDisabledByDefault) { + ValidateCannotInterceptKeys(app_with_permission_, false, false); +} + +// Tests that the application cannot be loaded in stable. +IN_PROC_BROWSER_TEST_F(AppWindowInterceptAllKeysTest, CannotLoadOtherThanDev) { + chrome::VersionInfo::Channel version_info[] = { + chrome::VersionInfo::CHANNEL_BETA, chrome::VersionInfo::CHANNEL_STABLE}; + for (unsigned int index = 0; index < arraysize(version_info); index++) { + extensions::ScopedCurrentChannel channel(version_info[index]); + const extensions::Extension* extension = nullptr; + EXPECT_NONFATAL_FAILURE( + extension = LoadExtension(test_data_dir_.AppendASCII("platform_apps") + .AppendASCII(app_with_permission_)), + ""); + + DVLOG(1) << "Finished loading extension"; + + ASSERT_TRUE(extension == nullptr) << "Application loaded in" + << version_info[index] + << " while permission does not exist"; + } +} + +// Inject different keyboard combos and make sure that the app get them all. +// Disabled test http://crbug.com/438209 +#if defined(OS_WIN) +#define MAYBE_ValidateKeyEvent DISABLED_ValidateKeyEvent +#else +#define MAYBE_ValidateKeyEvent DISABLED_ValidateKeyEvent +#endif + +namespace { +// Maximum lenght of the result array in KeyEventTestData structure. +const size_t kMaxResultLength = 10; + +// A structure holding test data of a keyboard event. +// Each keyboard event may generate multiple result strings representing +// the result of keydown, keypress, keyup and textInput events. +// For keydown, keypress and keyup events, the format of the result string is: +// <type> <keyCode> <charCode> <ctrlKey> <shiftKey> <altKey> <commandKey> +// where <type> may be 'D' (keydown), 'P' (keypress) or 'U' (keyup). +// <ctrlKey>, <shiftKey> <altKey> and <commandKey> are boolean value indicating +// the state of corresponding modifier key. +struct KeyEventTestData { + ui::KeyboardCode key; + bool control; + bool shift; + bool alt; + bool command; + + int result_length; + const char* const result[kMaxResultLength]; +}; +} // namespace + +IN_PROC_BROWSER_TEST_F(AppWindowInterceptAllKeysTest, MAYBE_ValidateKeyEvent) { + // Launch the app + ValidateInterceptKeys(false); + + static const KeyEventTestData kValidateKeyEvents[] = { + // a + {ui::VKEY_A, + false, + false, + false, + false, + 3, + {"D 65 0 false false false false", + "P 97 97 false false false false", + "U 65 0 false false false false"}}, + // shift+a + {ui::VKEY_A, + false, + true, + false, + false, + 5, + {"D 16 0 false true false false", + "D 65 0 false true false false", + "P 65 65 false true false false", + "U 65 0 false true false false", + "U 16 0 false true false false"}}, + // ctrl+f which has accelerator binding should also result in all keys + // being + // sent. + {ui::VKEY_F, + true, + false, + false, + false, + 5, + {"D 17 0 true false false false", + "D 70 0 true false false false", + "P 6 6 true false false false", + "U 70 0 true false false false", + "U 17 0 true false false false"}}, + // ctrl+z + {ui::VKEY_Z, + true, + false, + false, + false, + 5, + {"D 17 0 true false false false", + "D 90 0 true false false false", + "P 26 26 true false false false", + "U 90 0 true false false false", + "U 17 0 true false false false"}}, + // alt+f + {ui::VKEY_F, + false, + false, + true, + false, + 4, + {"D 18 0 false false true false", + "D 70 0 false false true false", + "U 70 0 false false true false", + "U 18 0 false false true false"}}, + // make sure both left and right shift makes it across + {ui::VKEY_RSHIFT, + false, + false, + false, + false, + 2, + {"D 16 0 false true false false", "U 16 0 false true false false"}}, + }; + + DVLOG(1) << "Starting keyboard input test"; + + for (unsigned int index = 0; index < arraysize(kValidateKeyEvents); index++) { + // create all the event listeners needed + const KeyEventTestData* current_event = &kValidateKeyEvents[index]; + scoped_ptr<ExtensionTestMessageListener> listeners[kMaxResultLength]; + for (int i = 0; i < current_event->result_length; i++) { + listeners[i].reset( + new ExtensionTestMessageListener(current_event->result[i], false)); + } + ASSERT_TRUE(SimulateKeyPress(current_event->key, current_event->control, + current_event->shift, current_event->alt, + current_event->command)); + for (int i = 0; i < current_event->result_length; i++) { + EXPECT_TRUE(listeners[i]->WaitUntilSatisfied()); + } + } +}
diff --git a/chrome/browser/apps/ephemeral_app_launcher.cc b/chrome/browser/apps/ephemeral_app_launcher.cc index a1f516b..643f633 100644 --- a/chrome/browser/apps/ephemeral_app_launcher.cc +++ b/chrome/browser/apps/ephemeral_app_launcher.cc
@@ -11,6 +11,7 @@ #include "chrome/browser/extensions/extension_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser_navigator.h" +#include "chrome/browser/ui/extensions/app_launch_params.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/browser/ui/extensions/extension_enable_flow.h" #include "chrome/browser/ui/native_window_tracker.h" @@ -22,6 +23,7 @@ #include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_system.h" #include "extensions/browser/management_policy.h" +#include "extensions/common/constants.h" #include "extensions/common/permissions/permissions_data.h" using content::WebContents; @@ -279,7 +281,8 @@ ExtensionRegistry::Get(profile()) ->GetExtensionById(extension->id(), ExtensionRegistry::ENABLED)); - AppLaunchParams params(profile(), extension, NEW_FOREGROUND_TAB); + AppLaunchParams params(profile(), extension, NEW_FOREGROUND_TAB, + extensions::SOURCE_EPHEMERAL_APP); params.desktop_type = chrome::GetHostDesktopTypeForNativeWindow(parent_window_); OpenApplication(params);
diff --git a/chrome/browser/apps/web_view_browsertest.cc b/chrome/browser/apps/web_view_browsertest.cc index a859a6c..d3a2f7e 100644 --- a/chrome/browser/apps/web_view_browsertest.cc +++ b/chrome/browser/apps/web_view_browsertest.cc
@@ -27,10 +27,15 @@ #include "content/public/test/browser_test_utils.h" #include "content/public/test/fake_speech_recognition_manager.h" #include "content/public/test/test_renderer_host.h" +#include "extensions/browser/api/declarative/rules_registry.h" +#include "extensions/browser/api/declarative/rules_registry_service.h" +#include "extensions/browser/api/declarative/test_rules_registry.h" +#include "extensions/browser/api/declarative_webrequest/webrequest_constants.h" #include "extensions/browser/app_window/native_app_window.h" #include "extensions/browser/guest_view/guest_view_manager.h" #include "extensions/browser/guest_view/guest_view_manager_factory.h" #include "extensions/browser/guest_view/test_guest_view_manager.h" +#include "extensions/browser/guest_view/web_view/web_view_guest.h" #include "extensions/common/extension.h" #include "extensions/common/extensions_client.h" #include "extensions/test/extension_test_message_listener.h" @@ -119,6 +124,34 @@ DISALLOW_COPY_AND_ASSIGN(WebContentsHiddenObserver); }; +class EmbedderWebContentsObserver : public content::WebContentsObserver { + public: + EmbedderWebContentsObserver(content:: WebContents* web_contents) + : WebContentsObserver(web_contents), + terminated_(false) { + } + + // WebContentsObserver. + void RenderProcessGone(base::TerminationStatus status) override { + terminated_ = true; + if (message_loop_runner_.get()) + message_loop_runner_->Quit(); + } + + void WaitForEmbedderRenderProcessTerminate() { + if (terminated_) + return; + message_loop_runner_ = new content::MessageLoopRunner; + message_loop_runner_->Run(); + } + + private: + bool terminated_; + scoped_refptr<content::MessageLoopRunner> message_loop_runner_; + + DISALLOW_COPY_AND_ASSIGN(EmbedderWebContentsObserver); +}; + void ExecuteScriptWaitForTitle(content::WebContents* web_contents, const char* script, const char* title) { @@ -2295,6 +2328,81 @@ TestHelper("testLoadDataAPI", "web_view/shim", NEEDS_TEST_SERVER); } +// This test verify that the set of rules registries of a webview will be +// removed from RulesRegistryService after the webview is gone. +// http://crbug.com/438327 +IN_PROC_BROWSER_TEST_F( + WebViewTest, + DISABLED_Shim_TestRulesRegistryIDAreRemovedAfterWebViewIsGone) { + LoadAppWithGuest("web_view/rules_registry"); + + content::WebContents* embedder_web_contents = GetEmbedderWebContents(); + ASSERT_TRUE(embedder_web_contents); + scoped_ptr<EmbedderWebContentsObserver> observer( + new EmbedderWebContentsObserver(embedder_web_contents)); + + content::WebContents* guest_web_contents = GetGuestWebContents(); + ASSERT_TRUE(guest_web_contents); + extensions::WebViewGuest* guest = + extensions::WebViewGuest::FromWebContents(guest_web_contents); + ASSERT_TRUE(guest); + + // Register rule for the guest. + Profile* profile = browser()->profile(); + int rules_registry_id = + extensions::WebViewGuest::GetOrGenerateRulesRegistryID( + guest->owner_render_process_id(), + guest->view_instance_id(), + profile); + + extensions::RulesRegistryService* registry_service = + extensions::RulesRegistryService::Get(profile); + extensions::TestRulesRegistry* rules_registry = + new extensions::TestRulesRegistry( + content::BrowserThread::UI, "ui", rules_registry_id); + registry_service->RegisterRulesRegistry(make_scoped_refptr(rules_registry)); + + EXPECT_TRUE(registry_service->GetRulesRegistry( + rules_registry_id, "ui").get()); + + // Kill the embedder's render process, so the webview will go as well. + content::RenderProcessHost* host = + embedder_web_contents->GetRenderProcessHost(); + base::KillProcess(host->GetHandle(), 0, false); + observer->WaitForEmbedderRenderProcessTerminate(); + + EXPECT_FALSE(registry_service->GetRulesRegistry( + rules_registry_id, "ui").get()); +} + +IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_WebViewWebRequestRegistryHasNoCache) { + LoadAppWithGuest("web_view/rules_registry"); + + content::WebContents* guest_web_contents = GetGuestWebContents(); + ASSERT_TRUE(guest_web_contents); + extensions::WebViewGuest* guest = + extensions::WebViewGuest::FromWebContents(guest_web_contents); + ASSERT_TRUE(guest); + + Profile* profile = browser()->profile(); + extensions::RulesRegistryService* registry_service = + extensions::RulesRegistryService::Get(profile); + int rules_registry_id = + extensions::WebViewGuest::GetOrGenerateRulesRegistryID( + guest->owner_render_process_id(), + guest->view_instance_id(), + profile); + + // Get an existing registered rule for the guest. + extensions::RulesRegistry* registry = + registry_service->GetRulesRegistry( + rules_registry_id, + extensions::declarative_webrequest_constants::kOnRequest).get(); + + EXPECT_TRUE(registry); + EXPECT_FALSE(registry->rules_cache_delegate_for_testing()); +} + // <webview> screenshot capture fails with ubercomp. // See http://crbug.com/327035. IN_PROC_BROWSER_TEST_F(WebViewCaptureTest,
diff --git a/chrome/browser/autofill/autofill_browsertest.cc b/chrome/browser/autofill/autofill_browsertest.cc index eb385e97..1eb2d13b 100644 --- a/chrome/browser/autofill/autofill_browsertest.cc +++ b/chrome/browser/autofill/autofill_browsertest.cc
@@ -26,6 +26,7 @@ #include "chrome/test/base/test_switches.h" #include "chrome/test/base/ui_test_utils.h" #include "components/autofill/content/browser/content_autofill_driver.h" +#include "components/autofill/content/browser/content_autofill_driver_factory.h" #include "components/autofill/core/browser/autofill_profile.h" #include "components/autofill/core/browser/autofill_test_utils.h" #include "components/autofill/core/browser/credit_card.h" @@ -123,8 +124,10 @@ // Make sure to close any showing popups prior to tearing down the UI. content::WebContents* web_contents = browser()->tab_strip_model()->GetActiveWebContents(); - AutofillManager* autofill_manager = ContentAutofillDriver::FromWebContents( - web_contents)->autofill_manager(); + AutofillManager* autofill_manager = + ContentAutofillDriverFactory::FromWebContents(web_contents) + ->DriverForFrame(web_contents->GetMainFrame()) + ->autofill_manager(); autofill_manager->client()->HideAutofillPopup(); }
diff --git a/chrome/browser/autofill/autofill_interactive_uitest.cc b/chrome/browser/autofill/autofill_interactive_uitest.cc index c871a26..379b449 100644 --- a/chrome/browser/autofill/autofill_interactive_uitest.cc +++ b/chrome/browser/autofill/autofill_interactive_uitest.cc
@@ -30,6 +30,7 @@ #include "chrome/test/base/test_switches.h" #include "chrome/test/base/ui_test_utils.h" #include "components/autofill/content/browser/content_autofill_driver.h" +#include "components/autofill/content/browser/content_autofill_driver_factory.h" #include "components/autofill/core/browser/autofill_manager.h" #include "components/autofill/core/browser/autofill_manager_test_delegate.h" #include "components/autofill/core/browser/autofill_profile.h" @@ -210,7 +211,8 @@ // Inject the test delegate into the AutofillManager. content::WebContents* web_contents = GetWebContents(); ContentAutofillDriver* autofill_driver = - ContentAutofillDriver::FromWebContents(web_contents); + ContentAutofillDriverFactory::FromWebContents(web_contents) + ->DriverForFrame(web_contents->GetMainFrame()); AutofillManager* autofill_manager = autofill_driver->autofill_manager(); autofill_manager->SetTestDelegate(&test_delegate_); @@ -225,8 +227,10 @@ void TearDownOnMainThread() override { // Make sure to close any showing popups prior to tearing down the UI. content::WebContents* web_contents = GetWebContents(); - AutofillManager* autofill_manager = ContentAutofillDriver::FromWebContents( - web_contents)->autofill_manager(); + AutofillManager* autofill_manager = + ContentAutofillDriverFactory::FromWebContents(web_contents) + ->DriverForFrame(web_contents->GetMainFrame()) + ->autofill_manager(); autofill_manager->client()->HideAutofillPopup(); }
diff --git a/chrome/browser/autofill/content_autofill_driver_browsertest.cc b/chrome/browser/autofill/content_autofill_driver_browsertest.cc index 1b15094..312a10fe 100644 --- a/chrome/browser/autofill/content_autofill_driver_browsertest.cc +++ b/chrome/browser/autofill/content_autofill_driver_browsertest.cc
@@ -11,6 +11,7 @@ #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/testing_pref_service_syncable.h" #include "components/autofill/content/browser/content_autofill_driver.h" +#include "components/autofill/content/browser/content_autofill_driver_factory.h" #include "components/autofill/core/browser/autofill_manager.h" #include "components/autofill/core/browser/test_autofill_client.h" #include "content/public/browser/navigation_controller.h" @@ -58,10 +59,10 @@ // instance. class TestContentAutofillDriver : public ContentAutofillDriver { public: - TestContentAutofillDriver(content::WebContents* web_contents, + TestContentAutofillDriver(content::RenderFrameHost* rfh, AutofillClient* client) : ContentAutofillDriver( - web_contents, + rfh, client, g_browser_process->GetApplicationLocale(), AutofillManager::ENABLE_AUTOFILL_DOWNLOAD_MANAGER) {} @@ -86,14 +87,12 @@ Observe(web_contents); AutofillManager::RegisterProfilePrefs(autofill_client_.GetPrefRegistry()); - autofill_driver_.reset( - new TestContentAutofillDriver(web_contents, &autofill_client_)); - } - - // Normally the WebContents will automatically delete the driver, but here - // the driver is owned by this test, so we have to manually destroy. - virtual void WebContentsDestroyed() override { - autofill_driver_.reset(); + web_contents->RemoveUserData( + ContentAutofillDriverFactory:: + kContentAutofillDriverFactoryWebContentsUserDataKey); + ContentAutofillDriverFactory::CreateForWebContentsAndDelegate( + web_contents, &autofill_client_, "en-US", + AutofillManager::DISABLE_AUTOFILL_DOWNLOAD_MANAGER); } virtual void WasHidden() override { @@ -114,7 +113,6 @@ base::Closure nav_entry_committed_callback_; testing::NiceMock<MockAutofillClient> autofill_client_; - scoped_ptr<TestContentAutofillDriver> autofill_driver_; }; IN_PROC_BROWSER_TEST_F(ContentAutofillDriverBrowserTest,
diff --git a/chrome/browser/autofill/form_structure_browsertest.cc b/chrome/browser/autofill/form_structure_browsertest.cc index df8a9c3..ea53d05c 100644 --- a/chrome/browser/autofill/form_structure_browsertest.cc +++ b/chrome/browser/autofill/form_structure_browsertest.cc
@@ -14,6 +14,7 @@ #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" #include "components/autofill/content/browser/content_autofill_driver.h" +#include "components/autofill/content/browser/content_autofill_driver_factory.h" #include "components/autofill/core/browser/autofill_manager.h" #include "components/autofill/core/browser/data_driven_test.h" #include "components/autofill/core/browser/form_structure.h" @@ -71,9 +72,11 @@ ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), HTMLToDataURI(input))); + content::WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); ContentAutofillDriver* autofill_driver = - ContentAutofillDriver::FromWebContents( - browser()->tab_strip_model()->GetActiveWebContents()); + ContentAutofillDriverFactory::FromWebContents(web_contents) + ->DriverForFrame(web_contents->GetMainFrame()); ASSERT_NE(static_cast<ContentAutofillDriver*>(NULL), autofill_driver); AutofillManager* autofill_manager = autofill_driver->autofill_manager(); ASSERT_NE(static_cast<AutofillManager*>(NULL), autofill_manager);
diff --git a/chrome/browser/background/background_mode_manager.cc b/chrome/browser/background/background_mode_manager.cc index a6bb71b..b95f598 100644 --- a/chrome/browser/background/background_mode_manager.cc +++ b/chrome/browser/background/background_mode_manager.cc
@@ -32,6 +32,7 @@ #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/chrome_pages.h" +#include "chrome/browser/ui/extensions/app_launch_params.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/browser/ui/host_desktop.h" #include "chrome/browser/ui/user_manager.h" @@ -44,6 +45,7 @@ #include "content/public/browser/notification_service.h" #include "content/public/browser/user_metrics.h" #include "extensions/browser/extension_system.h" +#include "extensions/common/constants.h" #include "extensions/common/extension.h" #include "extensions/common/manifest_handlers/options_page_info.h" #include "extensions/common/permissions/permission_set.h" @@ -318,7 +320,8 @@ void BackgroundModeManager::LaunchBackgroundApplication( Profile* profile, const Extension* extension) { - OpenApplication(AppLaunchParams(profile, extension, NEW_FOREGROUND_TAB)); + OpenApplication(AppLaunchParams(profile, extension, NEW_FOREGROUND_TAB, + extensions::SOURCE_BACKGROUND)); } bool BackgroundModeManager::IsBackgroundModeActive() {
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc index 150d9d0..34ddec2 100644 --- a/chrome/browser/browser_process_impl.cc +++ b/chrome/browser/browser_process_impl.cc
@@ -102,9 +102,7 @@ #include "chrome/browser/chrome_browser_main_mac.h" #endif -#if defined(OS_ANDROID) -#include "components/gcm_driver/gcm_driver_android.h" -#else +#if !defined(OS_ANDROID) #include "chrome/browser/chrome_device_client.h" #include "chrome/browser/services/gcm/gcm_desktop_utils.h" #include "components/gcm_driver/gcm_client_factory.h" @@ -1128,7 +1126,11 @@ DCHECK(!gcm_driver_); #if defined(OS_ANDROID) - gcm_driver_.reset(new gcm::GCMDriverAndroid); + // Android's GCMDriver currently makes the assumption that it's a singleton. + // Until this gets fixed, instantiating multiple Java GCMDrivers will throw + // an exception, but because they're only initialized on demand these crashes + // would be very difficult to triage. See http://crbug.com/437827. + NOTREACHED(); #else base::FilePath store_path; CHECK(PathService::Get(chrome::DIR_GLOBAL_GCM_STORE, &store_path));
diff --git a/chrome/browser/chromeos/DEPS b/chrome/browser/chromeos/DEPS index 2e6fcd6..f90c11d 100644 --- a/chrome/browser/chromeos/DEPS +++ b/chrome/browser/chromeos/DEPS
@@ -8,6 +8,7 @@ "+device/bluetooth", "+media/audio/sounds", # For system sounds "+media/base/media_switches.h", # For media command line switches. + "+ui/ozone/public", # Other libraries. "+third_party/libjingle",
diff --git a/chrome/browser/chromeos/app_mode/startup_app_launcher.cc b/chrome/browser/chromeos/app_mode/startup_app_launcher.cc index 6a2451e..4bdd7dd6c 100644 --- a/chrome/browser/chromeos/app_mode/startup_app_launcher.cc +++ b/chrome/browser/chromeos/app_mode/startup_app_launcher.cc
@@ -22,6 +22,7 @@ #include "chrome/browser/lifetime/application_lifetime.h" #include "chrome/browser/signin/profile_oauth2_token_service_factory.h" #include "chrome/browser/signin/signin_manager_factory.h" +#include "chrome/browser/ui/extensions/app_launch_params.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_switches.h" @@ -33,6 +34,7 @@ #include "content/public/browser/browser_thread.h" #include "content/public/browser/notification_service.h" #include "extensions/browser/extension_system.h" +#include "extensions/common/constants.h" #include "extensions/common/extension.h" #include "extensions/common/manifest_handlers/kiosk_mode_info.h" #include "extensions/common/manifest_handlers/offline_enabled_info.h" @@ -331,7 +333,7 @@ // Always open the app in a window. OpenApplication(AppLaunchParams(profile_, extension, extensions::LAUNCH_CONTAINER_WINDOW, - NEW_WINDOW)); + NEW_WINDOW, extensions::SOURCE_KIOSK)); InitAppSession(profile_, app_id_); user_manager::UserManager::Get()->SessionStarted();
diff --git a/chrome/browser/chromeos/attestation/OWNERS b/chrome/browser/chromeos/attestation/OWNERS index 8f05b0f8..d7df737 100644 --- a/chrome/browser/chromeos/attestation/OWNERS +++ b/chrome/browser/chromeos/attestation/OWNERS
@@ -1,4 +1,3 @@ dkrahn@chromium.org mnissler@chromium.org -pastarmovj@chromium.org bartfab@chromium.org
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc index 448c8c8d..58ae1d8 100644 --- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc +++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -753,8 +753,6 @@ SystemKeyEventListener::Shutdown(); #endif - CrasAudioHandler::Shutdown(); - // Detach D-Bus clients before DBusThreadManager is shut down. power_button_observer_.reset(); idle_action_warning_observer_.reset(); @@ -804,6 +802,9 @@ // Stops all in-flight OAuth2 token fetchers before the IO thread stops. DeviceOAuth2TokenServiceFactory::Shutdown(); + // Shutdown after PostMainMessageLoopRun() which should destroy all observers. + CrasAudioHandler::Shutdown(); + // Called after // ChromeBrowserMainPartsLinux::PostMainMessageLoopRun() to be // executed after execution of chrome::CloseAsh(), because some
diff --git a/chrome/browser/chromeos/dbus/org.chromium.LibCrosService.conf b/chrome/browser/chromeos/dbus/org.chromium.LibCrosService.conf deleted file mode 100644 index 7a0d0c0b..0000000 --- a/chrome/browser/chromeos/dbus/org.chromium.LibCrosService.conf +++ /dev/null
@@ -1,36 +0,0 @@ -<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" - "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> -<!-- - Copyright (c) 2011 The Chromium Authors. All rights reserved. - Use of this source code is governed by a BSD-style license that can be - found in the LICENSE file. - - This file will be installed at /etc/dbus-1/system.d on Chromium OS. ---> -<busconfig> - <policy user="chronos"> - <allow own="org.chromium.LibCrosService"/> - <allow receive_sender="org.chromium.LibCrosService"/> - <allow send_destination="org.chromium.LibCrosService"/> - </policy> - - <!-- bluez makes agent method calls to Chromium. --> - <policy user="bluetooth"> - <allow send_destination="org.chromium.LibCrosService"/> - </policy> - - <!-- tlsdate needs to query proxy config. --> - <policy user="tlsdate"> - <allow send_destination="org.chromium.LibCrosService"/> - </policy> - - <!-- powerd needs to change display power states. --> - <policy user="power"> - <allow send_destination="org.chromium.LibCrosService"/> - </policy> - - <!-- update_engine uses this service to resolve the proxy config. --> - <policy user="root"> - <allow send_destination="org.chromium.LibCrosService"/> - </policy> -</busconfig>
diff --git a/chrome/browser/chromeos/extensions/file_manager/device_event_router.cc b/chrome/browser/chromeos/extensions/file_manager/device_event_router.cc index b6252e3..47faf53 100644 --- a/chrome/browser/chromeos/extensions/file_manager/device_event_router.cc +++ b/chrome/browser/chromeos/extensions/file_manager/device_event_router.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "base/bind.h" +#include "base/metrics/histogram_macros.h" #include "base/thread_task_runner_handle.h" #include "chrome/browser/chromeos/extensions/file_manager/device_event_router.h" #include "chrome/browser/chromeos/file_manager/volume_manager.h" @@ -80,6 +81,13 @@ const std::string& device_path = disk.system_path_prefix(); if (!disk.mount_path().empty() && GetDeviceState(device_path) != DEVICE_HARD_UNPLUGGED_AND_REPORTED) { + // TODO(hirono): Remove the temporary UMA. crbug.com/433734 + if (!last_suspend_done_.is_null()) { + UMA_HISTOGRAM_MEDIUM_TIMES( + "FileBrowser.HardUnpluggedAroundSuspend.TimeSinceResume", + base::Time::Now() - last_suspend_done_); + } + last_hard_unplugged_ = base::Time::Now(); OnDeviceEvent(file_manager_private::DEVICE_EVENT_TYPE_HARD_UNPLUGGED, device_path); SetDeviceState(device_path, DEVICE_HARD_UNPLUGGED_AND_REPORTED); @@ -124,11 +132,18 @@ void DeviceEventRouter::SuspendImminent() { DCHECK(thread_checker_.CalledOnValidThread()); + // TODO(hirono): Remove the temporary UMA. crbug.com/433734 + if (!last_hard_unplugged_.is_null()) { + UMA_HISTOGRAM_MEDIUM_TIMES( + "FileBrowser.HardUnpluggedAroundSuspend.TimeUntilSuspend", + base::Time::Now() - last_hard_unplugged_); + } is_resuming_ = true; } void DeviceEventRouter::SuspendDone(const base::TimeDelta& sleep_duration) { DCHECK(thread_checker_.CalledOnValidThread()); + last_suspend_done_ = base::Time::Now(); base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, base::Bind(&DeviceEventRouter::SuspendDoneDelayed,
diff --git a/chrome/browser/chromeos/extensions/file_manager/device_event_router.h b/chrome/browser/chromeos/extensions/file_manager/device_event_router.h index a43ced26..c9b0591f 100644 --- a/chrome/browser/chromeos/extensions/file_manager/device_event_router.h +++ b/chrome/browser/chromeos/extensions/file_manager/device_event_router.h
@@ -98,6 +98,11 @@ // Thread checker. base::ThreadChecker thread_checker_; + // Last event time for UMA. + // TODO(hirono): Remove the temporarily UMA. crbug.com/433734 + base::Time last_hard_unplugged_; + base::Time last_suspend_done_; + // Note: This should remain the last member so it'll be destroyed and // invalidate the weak pointers before any other members are destroyed. base::WeakPtrFactory<DeviceEventRouter> weak_factory_;
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc index fb2a5e9..e27599c 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
@@ -248,6 +248,8 @@ IDS_FILE_BROWSER_REMOVE_FOLDER_SHORTCUT_BUTTON_LABEL); SET_STRING("SHARE_BUTTON_LABEL", IDS_FILE_BROWSER_SHARE_BUTTON_LABEL); + SET_STRING("CLOUD_IMPORT_BUTTON_LABEL", + IDS_FILE_BROWSER_CLOUD_IMPORT_BUTTON_LABEL); SET_STRING("OPEN_WITH_BUTTON_LABEL", IDS_FILE_BROWSER_OPEN_WITH_BUTTON_LABEL);
diff --git a/chrome/browser/chromeos/extensions/virtual_keyboard_browsertest.cc b/chrome/browser/chromeos/extensions/virtual_keyboard_browsertest.cc index 408e705..da1a481 100644 --- a/chrome/browser/chromeos/extensions/virtual_keyboard_browsertest.cc +++ b/chrome/browser/chromeos/extensions/virtual_keyboard_browsertest.cc
@@ -65,7 +65,7 @@ ui_test_utils::NavigateToURL(browser(), GURL(config.url_)); content::WebContents* web_contents = browser()->tab_strip_model()->GetActiveWebContents(); - content::WaitForLoadStop(web_contents); + EXPECT_TRUE(content::WaitForLoadStop(web_contents)); ASSERT_TRUE(web_contents); // Inject testing scripts. @@ -103,8 +103,8 @@ if (url == view->GetSiteInstance()->GetSiteURL()) { content::WebContents* wc = content::WebContents::FromRenderViewHost(view); - // Waits for Polymer to load. - content::WaitForLoadStop(wc); + // Waits for virtual keyboard to load. + EXPECT_TRUE(content::WaitForLoadStop(wc)); return view; } } @@ -122,13 +122,6 @@ utf8_content_.append(";\n"); } -// crbug.com/367817. Either this feature or just the test are depending -// on the presense of Object.observe which is presently disabled by default. -IN_PROC_BROWSER_TEST_F(VirtualKeyboardBrowserTest, DISABLED_AttributesTest) { - RunTest(base::FilePath(FILE_PATH_LITERAL("attributes_test.js")), - VirtualKeyboardBrowserTestConfig()); -} - IN_PROC_BROWSER_TEST_F(VirtualKeyboardBrowserTest, TypingTest) { RunTest(base::FilePath(FILE_PATH_LITERAL("typing_test.js")), VirtualKeyboardBrowserTestConfig()); @@ -144,31 +137,12 @@ VirtualKeyboardBrowserTestConfig()); } -// crbug.com/387372. This test started failing at Blink r176582. -IN_PROC_BROWSER_TEST_F(VirtualKeyboardBrowserTest, DISABLED_ControlKeysTest) { - RunTest(base::FilePath(FILE_PATH_LITERAL("control_keys_test.js")), - VirtualKeyboardBrowserTestConfig()); -} - IN_PROC_BROWSER_TEST_F(VirtualKeyboardBrowserTest, HideKeyboardKeyTest) { RunTest(base::FilePath(FILE_PATH_LITERAL("hide_keyboard_key_test.js")), VirtualKeyboardBrowserTestConfig()); } -// http://crbug.com/396326 -IN_PROC_BROWSER_TEST_F(VirtualKeyboardBrowserTest, - DISABLED_KeysetTransitionTest) { - RunTest(base::FilePath(FILE_PATH_LITERAL("keyset_transition_test.js")), - VirtualKeyboardBrowserTestConfig()); -} - -// Fails when enabling Object.observe. See http://crbug.com/370004 -#if defined(OS_CHROMEOS) -#define MAYBE_IsKeyboardLoaded DISABLED_IsKeyboardLoaded -#else -#define MAYBE_IsKeyboardLoaded IsKeyboardLoaded -#endif -IN_PROC_BROWSER_TEST_F(VirtualKeyboardBrowserTest, MAYBE_IsKeyboardLoaded) { +IN_PROC_BROWSER_TEST_F(VirtualKeyboardBrowserTest, IsKeyboardLoaded) { content::RenderViewHost* keyboard_rvh = GetKeyboardRenderViewHost(kExtensionId); ASSERT_TRUE(keyboard_rvh); @@ -182,7 +156,7 @@ ASSERT_TRUE(loaded); } -IN_PROC_BROWSER_TEST_F(VirtualKeyboardBrowserTest, DISABLED_EndToEndTest) { +IN_PROC_BROWSER_TEST_F(VirtualKeyboardBrowserTest, EndToEndTest) { // Get the virtual keyboard's render view host. content::RenderViewHost* keyboard_rvh = GetKeyboardRenderViewHost(kExtensionId);
diff --git a/chrome/browser/chromeos/extensions/wallpaper_manager_util.cc b/chrome/browser/chromeos/extensions/wallpaper_manager_util.cc index da40b7a01..46ed021 100644 --- a/chrome/browser/chromeos/extensions/wallpaper_manager_util.cc +++ b/chrome/browser/chromeos/extensions/wallpaper_manager_util.cc
@@ -8,9 +8,11 @@ #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_manager.h" +#include "chrome/browser/ui/extensions/app_launch_params.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/common/extensions/extension_constants.h" #include "extensions/browser/extension_system.h" +#include "extensions/common/constants.h" #include "extensions/common/extension.h" #include "ui/base/window_open_disposition.h" @@ -30,9 +32,9 @@ if (!extension) return; - OpenApplication(AppLaunchParams(profile, extension, - extensions::LAUNCH_CONTAINER_WINDOW, - NEW_WINDOW)); + OpenApplication( + AppLaunchParams(profile, extension, extensions::LAUNCH_CONTAINER_WINDOW, + NEW_WINDOW, extensions::SOURCE_CHROME_INTERNAL)); } } // namespace wallpaper_manager_util
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc index 32a4b0f7..e8efbfe 100644 --- a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc +++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
@@ -826,14 +826,6 @@ TestParameter(NOT_IN_GUEST_MODE, "fileDisplayDrive"), TestParameter(NOT_IN_GUEST_MODE, "fileDisplayMtp"))); -// http://crbug.com/327719 -WRAPPED_INSTANTIATE_TEST_CASE_P( - DISABLED_OpenZipFiles, - FileManagerBrowserTest, - ::testing::Values(TestParameter(IN_GUEST_MODE, "zipOpenDownloads"), - TestParameter(NOT_IN_GUEST_MODE, "zipOpenDownloads"), - TestParameter(NOT_IN_GUEST_MODE, "zipOpenDrive"))); - // Slow tests are disabled on debug build. http://crbug.com/327719 // Fails on official build. http://crbug.com/429294 #if !defined(NDEBUG) || defined(OFFICIAL_BUILD)
diff --git a/chrome/browser/chromeos/first_run/first_run.cc b/chrome/browser/chromeos/first_run/first_run.cc index b9c7947..b4af283 100644 --- a/chrome/browser/chromeos/first_run/first_run.cc +++ b/chrome/browser/chromeos/first_run/first_run.cc
@@ -11,6 +11,7 @@ #include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/profiles/profile_manager.h" +#include "chrome/browser/ui/extensions/app_launch_params.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/extensions/extension_constants.h" @@ -40,8 +41,9 @@ if (!extension) return; - OpenApplication(AppLaunchParams( - profile, extension, extensions::LAUNCH_CONTAINER_WINDOW, NEW_WINDOW)); + OpenApplication( + AppLaunchParams(profile, extension, extensions::LAUNCH_CONTAINER_WINDOW, + NEW_WINDOW, extensions::SOURCE_CHROME_INTERNAL)); profile->GetPrefs()->SetBoolean(prefs::kFirstRunTutorialShown, true); }
diff --git a/chrome/browser/chromeos/geolocation/simple_geolocation_unittest.cc b/chrome/browser/chromeos/geolocation/simple_geolocation_unittest.cc index 01b4900..019ccdb 100644 --- a/chrome/browser/chromeos/geolocation/simple_geolocation_unittest.cc +++ b/chrome/browser/chromeos/geolocation/simple_geolocation_unittest.cc
@@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "chrome/browser/chromeos/geolocation/simple_geolocation_provider.h" -#include "content/public/test/test_browser_thread_bundle.h" #include "net/http/http_response_headers.h" #include "net/http/http_status_code.h" #include "net/url_request/test_url_fetcher_factory.h" @@ -161,7 +161,7 @@ class SimpleGeolocationTest : public testing::Test { private: - content::TestBrowserThreadBundle thread_bundle_; + base::MessageLoop message_loop_; }; TEST_F(SimpleGeolocationTest, ResponseOK) {
diff --git a/chrome/browser/chromeos/login/chrome_restart_request.cc b/chrome/browser/chromeos/login/chrome_restart_request.cc index 28fea37..262febf8 100644 --- a/chrome/browser/chromeos/login/chrome_restart_request.cc +++ b/chrome/browser/chromeos/login/chrome_restart_request.cc
@@ -114,6 +114,7 @@ ::switches::kEnableOneCopy, ::switches::kEnablePinch, ::switches::kEnablePluginPlaceholderShadowDom, + ::switches::kEnableSlimmingPaint, ::switches::kEnableTouchDragDrop, ::switches::kEnableTouchEditing, ::switches::kEnableViewport,
diff --git a/chrome/browser/chromeos/login/demo_mode/demo_app_launcher.cc b/chrome/browser/chromeos/login/demo_mode/demo_app_launcher.cc index 466638fe..6be11b89 100644 --- a/chrome/browser/chromeos/login/demo_mode/demo_app_launcher.cc +++ b/chrome/browser/chromeos/login/demo_mode/demo_app_launcher.cc
@@ -14,6 +14,7 @@ #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/lifetime/application_lifetime.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/extensions/app_launch_params.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/extensions/extension_constants.h" @@ -22,6 +23,7 @@ #include "chromeos/network/network_state_handler.h" #include "components/user_manager/user_manager.h" #include "extensions/browser/extension_system.h" +#include "extensions/common/constants.h" #include "extensions/common/extension.h" #include "ui/base/window_open_disposition.h" @@ -92,8 +94,9 @@ false, chromeos::network_handler::ErrorCallback()); - OpenApplication(AppLaunchParams( - profile, extension, extensions::LAUNCH_CONTAINER_WINDOW, NEW_WINDOW)); + OpenApplication( + AppLaunchParams(profile, extension, extensions::LAUNCH_CONTAINER_WINDOW, + NEW_WINDOW, extensions::SOURCE_CHROME_INTERNAL)); InitAppSession(profile, extension_id); user_manager::UserManager::Get()->SessionStarted();
diff --git a/chrome/browser/chromeos/login/enrollment/OWNERS b/chrome/browser/chromeos/login/enrollment/OWNERS index 14584b93..0e4d8603 100644 --- a/chrome/browser/chromeos/login/enrollment/OWNERS +++ b/chrome/browser/chromeos/login/enrollment/OWNERS
@@ -1,2 +1 @@ mnissler@chromium.org -joaodasilva@chromium.org
diff --git a/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.cc b/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.cc index a0f5ef25..98810a8 100644 --- a/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.cc +++ b/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.cc
@@ -18,6 +18,20 @@ namespace chromeos { +namespace { + +NetworkPortalDetector::CaptivePortalStatus GetCaptivePortalStatus() { + const NetworkState* default_network = + NetworkHandler::Get()->network_state_handler()->DefaultNetwork(); + return default_network + ? NetworkPortalDetector::Get() + ->GetCaptivePortalState(default_network->guid()) + .status + : NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_UNKNOWN; +} + +} // namespace + // static AutoEnrollmentCheckScreen* AutoEnrollmentCheckScreen::Get( ScreenManager* manager) { @@ -45,60 +59,60 @@ actor_->SetDelegate(NULL); } -void AutoEnrollmentCheckScreen::Start() { - if (!IsStartNeeded()) - return; - - // Make sure the auto-enrollment client is running. - auto_enrollment_controller_->Start(); - - auto_enrollment_progress_subscription_ = - auto_enrollment_controller_->RegisterProgressCallback( - base::Bind( - &AutoEnrollmentCheckScreen::OnAutoEnrollmentCheckProgressed, - base::Unretained(this))); - auto_enrollment_state_ = auto_enrollment_controller_->state(); - - // NB: AddAndFireObserver below call back into OnPortalDetectionCompleted. - // This guarantees that the UI gets synced to current state. - NetworkPortalDetector* portal_detector = NetworkPortalDetector::Get(); - portal_detector->StartDetectionIfIdle(); - portal_detector->AddAndFireObserver(this); -} - void AutoEnrollmentCheckScreen::ClearState() { + auto_enrollment_progress_subscription_.reset(); + NetworkPortalDetector::Get()->RemoveObserver(this); + auto_enrollment_state_ = policy::AUTO_ENROLLMENT_STATE_IDLE; captive_portal_status_ = NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_UNKNOWN; } -bool AutoEnrollmentCheckScreen::IsStartNeeded() { - // Check that forced reenrollment is wanted and if the check is needed or we - // already know the outcome. - if (AutoEnrollmentController::GetMode() != - AutoEnrollmentController::MODE_FORCED_RE_ENROLLMENT || - IsCompleted()) { - SignalCompletion(); - return false; - } - return true; -} - void AutoEnrollmentCheckScreen::PrepareToShow() { } void AutoEnrollmentCheckScreen::Show() { - if (IsStartNeeded()) { - Start(); - // It's possible that Start() has already made a decision and called - // SignalCompletion(). In this case we shouldn't call Show(), becase screen - // will be switched to the next one soon. - if (IsCompleted()) - return; - if (actor_) - actor_->Show(); - histogram_helper_->OnScreenShow(); + // If the decision got made already, don't show the screen at all. + if (AutoEnrollmentController::GetMode() != + AutoEnrollmentController::MODE_FORCED_RE_ENROLLMENT || + IsCompleted()) { + SignalCompletion(); + return; } + + // Start from a clean slate. + ClearState(); + + // Bring up the screen. It's important to do this before updating the UI, + // because the latter may switch to the error screen, which needs to stay on + // top. + actor_->Show(); + histogram_helper_->OnScreenShow(); + + // Set up state change observers. + auto_enrollment_progress_subscription_ = + auto_enrollment_controller_->RegisterProgressCallback( + base::Bind( + &AutoEnrollmentCheckScreen::OnAutoEnrollmentCheckProgressed, + base::Unretained(this))); + NetworkPortalDetector* portal_detector = NetworkPortalDetector::Get(); + portal_detector->AddObserver(this); + + // Perform an initial UI update. + NetworkPortalDetector::CaptivePortalStatus new_captive_portal_status = + GetCaptivePortalStatus(); + policy::AutoEnrollmentState new_auto_enrollment_state = + auto_enrollment_controller_->state(); + + if (!UpdateCaptivePortalStatus(new_captive_portal_status)) + UpdateAutoEnrollmentState(new_auto_enrollment_state); + + captive_portal_status_ = new_captive_portal_status; + auto_enrollment_state_ = new_auto_enrollment_state; + + // Make sure gears are in motion in the background. + auto_enrollment_controller_->Start(); + portal_detector->StartDetectionIfIdle(); } void AutoEnrollmentCheckScreen::Hide() { @@ -108,10 +122,6 @@ return WizardController::kAutoEnrollmentCheckScreenName; } -void AutoEnrollmentCheckScreen::OnExit() { - Finish(BaseScreenDelegate::ENTERPRISE_AUTO_ENROLLMENT_CHECK_COMPLETED); -} - void AutoEnrollmentCheckScreen::OnActorDestroyed( AutoEnrollmentCheckScreenActor* actor) { if (actor_ == actor) @@ -120,19 +130,27 @@ void AutoEnrollmentCheckScreen::OnPortalDetectionCompleted( const NetworkState* /* network */, - const NetworkPortalDetector::CaptivePortalState& state) { - UpdateState(state.status, auto_enrollment_state_); + const NetworkPortalDetector::CaptivePortalState& /* state */) { + UpdateState(); } void AutoEnrollmentCheckScreen::OnAutoEnrollmentCheckProgressed( policy::AutoEnrollmentState state) { - UpdateState(captive_portal_status_, state); + if (IsCompleted()) { + SignalCompletion(); + return; + } + + UpdateState(); } -void AutoEnrollmentCheckScreen::UpdateState( - NetworkPortalDetector::CaptivePortalStatus new_captive_portal_status, - policy::AutoEnrollmentState new_auto_enrollment_state) { - // Configure the error screen to show the approriate error message. +void AutoEnrollmentCheckScreen::UpdateState() { + NetworkPortalDetector::CaptivePortalStatus new_captive_portal_status = + GetCaptivePortalStatus(); + policy::AutoEnrollmentState new_auto_enrollment_state = + auto_enrollment_controller_->state(); + + // Configure the error screen to show the appropriate error message. if (!UpdateCaptivePortalStatus(new_captive_portal_status)) UpdateAutoEnrollmentState(new_auto_enrollment_state); @@ -151,12 +169,6 @@ captive_portal_status_ = new_captive_portal_status; auto_enrollment_state_ = new_auto_enrollment_state; - DCHECK_NE(auto_enrollment_state_, policy::AUTO_ENROLLMENT_STATE_IDLE); - if (IsCompleted()) { - SignalCompletion(); - return; - } - // Retry if applicable. This is last so eventual callbacks find consistent // state. if (retry) @@ -239,7 +251,7 @@ } bool AutoEnrollmentCheckScreen::IsCompleted() const { - switch (auto_enrollment_state_) { + switch (auto_enrollment_controller_->state()) { case policy::AUTO_ENROLLMENT_STATE_IDLE: case policy::AUTO_ENROLLMENT_STATE_PENDING: case policy::AUTO_ENROLLMENT_STATE_CONNECTION_ERROR:
diff --git a/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.h b/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.h index d4ad79d7..cbe6eaa 100644 --- a/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.h +++ b/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.h
@@ -36,10 +36,6 @@ static AutoEnrollmentCheckScreen* Get(ScreenManager* manager); - // Hands over OOBE control to this AutoEnrollmentCheckStep. It'll return the - // flow back to the caller via the |base_screen_delegate_|'s OnExit function. - void Start(); - // Clears the cached state causing the forced enrollment check to be retried. void ClearState(); @@ -55,7 +51,6 @@ virtual std::string GetName() const override; // AutoEnrollmentCheckScreenActor::Delegate implementation: - virtual void OnExit() override; virtual void OnActorDestroyed(AutoEnrollmentCheckScreenActor* actor) override; // NetworkPortalDetector::Observer implementation: @@ -68,9 +63,7 @@ void OnAutoEnrollmentCheckProgressed(policy::AutoEnrollmentState state); // Handles a state update, updating the UI and saving the state. - void UpdateState( - NetworkPortalDetector::CaptivePortalStatus new_captive_portal_status, - policy::AutoEnrollmentState new_auto_enrollment_state); + void UpdateState(); // Configures the UI to reflect |new_captive_portal_status|. Returns true if // and only if a UI change has been made. @@ -93,10 +86,6 @@ // Returns whether enrollment check was completed and decision was made. bool IsCompleted() const; - // Checks if the enrollment status check is needed. It can be disabled either - // by command line flags, build configuration or might have finished already. - bool IsStartNeeded(); - AutoEnrollmentCheckScreenActor* actor_; AutoEnrollmentController* auto_enrollment_controller_;
diff --git a/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen_actor.h b/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen_actor.h index 22fe3ea..1079ad3 100644 --- a/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen_actor.h +++ b/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen_actor.h
@@ -16,9 +16,6 @@ public: virtual ~Delegate() {} - // Called when screen is exited. - virtual void OnExit() = 0; - // This method is called, when actor is being destroyed. Note, if Delegate // is destroyed earlier then it has to call SetDelegate(NULL). virtual void OnActorDestroyed(AutoEnrollmentCheckScreenActor* actor) = 0;
diff --git a/chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.cc b/chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.cc index 28ac13e..27720d8 100644 --- a/chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.cc +++ b/chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.cc
@@ -161,6 +161,8 @@ void AutoEnrollmentController::Retry() { if (client_) client_->Retry(); + else + Start(); } scoped_ptr<AutoEnrollmentController::ProgressCallbackList::Subscription>
diff --git a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc index 08d10ec..a5a636f4 100644 --- a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc +++ b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
@@ -212,6 +212,14 @@ MOCK_METHOD0(Show, void()); MOCK_METHOD0(Hide, void()); + void RealShow() { + T::Show(); + } + + void RealHide() { + T::Hide(); + } + private: scoped_ptr<H> actor_; }; @@ -799,12 +807,9 @@ EXPECT_CALL(*mock_auto_enrollment_check_screen_, Show()).Times(1); OnExit(*mock_update_screen_, BaseScreenDelegate::UPDATE_INSTALLED); - AutoEnrollmentCheckScreen* screen = - AutoEnrollmentCheckScreen::Get(WizardController::default_controller()); - EXPECT_EQ(screen, - WizardController::default_controller()->current_screen()); + CheckCurrentScreen(WizardController::kAutoEnrollmentCheckScreenName); EXPECT_CALL(*mock_auto_enrollment_check_screen_, Hide()).Times(1); - screen->Start(); + mock_auto_enrollment_check_screen_->RealShow(); // Wait for auto-enrollment controller to encounter the connection error. WaitForAutoEnrollmentState(policy::AUTO_ENROLLMENT_STATE_CONNECTION_ERROR); @@ -863,11 +868,8 @@ EXPECT_CALL(*mock_auto_enrollment_check_screen_, Show()).Times(1); OnExit(*mock_update_screen_, BaseScreenDelegate::UPDATE_INSTALLED); - AutoEnrollmentCheckScreen* screen = - AutoEnrollmentCheckScreen::Get(WizardController::default_controller()); - EXPECT_EQ(screen, - WizardController::default_controller()->current_screen()); - screen->Start(); + CheckCurrentScreen(WizardController::kAutoEnrollmentCheckScreenName); + mock_auto_enrollment_check_screen_->RealShow(); EXPECT_EQ(policy::AUTO_ENROLLMENT_STATE_NO_ENROLLMENT, LoginDisplayHostImpl::default_host() ->GetAutoEnrollmentController() @@ -895,12 +897,9 @@ EXPECT_CALL(*mock_auto_enrollment_check_screen_, Show()).Times(1); OnExit(*mock_update_screen_, BaseScreenDelegate::UPDATE_INSTALLED); - AutoEnrollmentCheckScreen* screen = - AutoEnrollmentCheckScreen::Get(WizardController::default_controller()); - EXPECT_EQ(screen, - WizardController::default_controller()->current_screen()); + CheckCurrentScreen(WizardController::kAutoEnrollmentCheckScreenName); EXPECT_CALL(*mock_auto_enrollment_check_screen_, Hide()).Times(1); - screen->Start(); + mock_auto_enrollment_check_screen_->RealShow(); // Wait for auto-enrollment controller to encounter the connection error. WaitForAutoEnrollmentState(policy::AUTO_ENROLLMENT_STATE_CONNECTION_ERROR);
diff --git a/chrome/browser/chromeos/memory/oom_priority_manager.cc b/chrome/browser/chromeos/memory/oom_priority_manager.cc index 823207f9..d1926800 100644 --- a/chrome/browser/chromeos/memory/oom_priority_manager.cc +++ b/chrome/browser/chromeos/memory/oom_priority_manager.cc
@@ -171,7 +171,7 @@ } OomPriorityManager::OomPriorityManager() - : focused_tab_pid_(0), + : focused_tab_process_info_(std::make_pair(0, 0)), low_memory_observer_(new LowMemoryObserver), discard_count_(0), recent_tab_discard_(false) { @@ -218,14 +218,14 @@ std::vector<base::string16> OomPriorityManager::GetTabTitles() { TabStatsList stats = GetTabStatsOnUIThread(); - base::AutoLock pid_to_oom_score_autolock(pid_to_oom_score_lock_); + base::AutoLock oom_score_autolock(oom_score_lock_); std::vector<base::string16> titles; titles.reserve(stats.size()); TabStatsList::iterator it = stats.begin(); for ( ; it != stats.end(); ++it) { base::string16 str; str.reserve(4096); - int score = pid_to_oom_score_[it->renderer_handle]; + int score = oom_score_map_[it->child_process_host_id]; str += base::IntToString16(score); str += base::ASCIIToUTF16(" - "); str += it->title; @@ -456,10 +456,12 @@ void OomPriorityManager::AdjustFocusedTabScoreOnFileThread() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - base::AutoLock pid_to_oom_score_autolock(pid_to_oom_score_lock_); + base::AutoLock oom_score_autolock(oom_score_lock_); + base::ProcessHandle pid = focused_tab_process_info_.second; content::ZygoteHost::GetInstance()->AdjustRendererOOMScore( - focused_tab_pid_, chrome::kLowestRendererOomScore); - pid_to_oom_score_[focused_tab_pid_] = chrome::kLowestRendererOomScore; + pid, chrome::kLowestRendererOomScore); + oom_score_map_[focused_tab_process_info_.first] = + chrome::kLowestRendererOomScore; } void OomPriorityManager::OnFocusTabScoreAdjustmentTimeout() { @@ -472,35 +474,30 @@ void OomPriorityManager::Observe(int type, const content::NotificationSource& source, const content::NotificationDetails& details) { - base::ProcessHandle handle = 0; - base::AutoLock pid_to_oom_score_autolock(pid_to_oom_score_lock_); + base::AutoLock oom_score_autolock(oom_score_lock_); switch (type) { - case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: { - handle = - content::Details<content::RenderProcessHost::RendererClosedDetails>( - details)->handle; - pid_to_oom_score_.erase(handle); - break; - } + case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: { - handle = content::Source<content::RenderProcessHost>(source)-> - GetHandle(); - pid_to_oom_score_.erase(handle); + content::RenderProcessHost* host = + content::Source<content::RenderProcessHost>(source).ptr(); + oom_score_map_.erase(host->GetID()); break; } case content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED: { bool visible = *content::Details<bool>(details).ptr(); if (visible) { - focused_tab_pid_ = + content::RenderProcessHost* render_host = content::Source<content::RenderWidgetHost>(source).ptr()-> - GetProcess()->GetHandle(); + GetProcess(); + focused_tab_process_info_ = std::make_pair(render_host->GetID(), + render_host->GetHandle()); // If the currently focused tab already has a lower score, do not // set it. This can happen in case the newly focused tab is script // connected to the previous tab. ProcessScoreMap::iterator it; - it = pid_to_oom_score_.find(focused_tab_pid_); - if (it == pid_to_oom_score_.end() + it = oom_score_map_.find(focused_tab_process_info_.first); + if (it == oom_score_map_.end() || it->second != chrome::kLowestRendererOomScore) { // By starting a timer we guarantee that the tab is focused for // certain amount of time. Secondly, it also does not add overhead @@ -581,6 +578,7 @@ stats.is_discarded = model->IsTabDiscarded(i); stats.last_active = contents->GetLastActiveTime(); stats.renderer_handle = contents->GetRenderProcessHost()->GetHandle(); + stats.child_process_host_id = contents->GetRenderProcessHost()->GetID(); stats.title = contents->GetTitle(); stats.tab_contents_id = IdFromWebContents(contents); stats_list.push_back(stats); @@ -596,9 +594,10 @@ } // static -std::vector<base::ProcessHandle> OomPriorityManager::GetProcessHandles( +std::vector<OomPriorityManager::ProcessInfo> + OomPriorityManager::GetChildProcessInfos( const TabStatsList& stats_list) { - std::vector<base::ProcessHandle> process_handles; + std::vector<ProcessInfo> process_infos; std::set<base::ProcessHandle> already_seen; for (TabStatsList::const_iterator iterator = stats_list.begin(); iterator != stats_list.end(); ++iterator) { @@ -613,21 +612,21 @@ continue; } - process_handles.push_back(iterator->renderer_handle); + process_infos.push_back(std::make_pair( + iterator->child_process_host_id, iterator->renderer_handle)); } - return process_handles; + return process_infos; } void OomPriorityManager::AdjustOomPrioritiesOnFileThread( TabStatsList stats_list) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - base::AutoLock pid_to_oom_score_autolock(pid_to_oom_score_lock_); + base::AutoLock oom_score_autolock(oom_score_lock_); // Remove any duplicate PIDs. Order of the list is maintained, so each // renderer process will take on the oom_score_adj of the most important // (least likely to be killed) tab. - std::vector<base::ProcessHandle> process_handles = - GetProcessHandles(stats_list); + std::vector<ProcessInfo> process_infos = GetChildProcessInfos(stats_list); // Now we assign priorities based on the sorted list. We're // assigning priorities in the range of kLowestRendererOomScore to @@ -643,18 +642,17 @@ const int kPriorityRange = chrome::kHighestRendererOomScore - chrome::kLowestRendererOomScore; float priority_increment = - static_cast<float>(kPriorityRange) / process_handles.size(); - for (std::vector<base::ProcessHandle>::iterator iterator = - process_handles.begin(); - iterator != process_handles.end(); ++iterator) { + static_cast<float>(kPriorityRange) / process_infos.size(); + for (const auto& process_info : process_infos) { int score = static_cast<int>(priority + 0.5f); - ProcessScoreMap::iterator it = pid_to_oom_score_.find(*iterator); + ProcessScoreMap::iterator it = + oom_score_map_.find(process_info.first); // If a process has the same score as the newly calculated value, // do not set it. - if (it == pid_to_oom_score_.end() || it->second != score) { - content::ZygoteHost::GetInstance()->AdjustRendererOOMScore(*iterator, - score); - pid_to_oom_score_[*iterator] = score; + if (it == oom_score_map_.end() || it->second != score) { + content::ZygoteHost::GetInstance()->AdjustRendererOOMScore( + process_info.second, score); + oom_score_map_[process_info.first] = score; } priority += priority_increment; }
diff --git a/chrome/browser/chromeos/memory/oom_priority_manager.h b/chrome/browser/chromeos/memory/oom_priority_manager.h index fcf4d92..92ef696 100644 --- a/chrome/browser/chromeos/memory/oom_priority_manager.h +++ b/chrome/browser/chromeos/memory/oom_priority_manager.h
@@ -5,6 +5,7 @@ #ifndef CHROME_BROWSER_CHROMEOS_MEMORY_OOM_PRIORITY_MANAGER_H_ #define CHROME_BROWSER_CHROMEOS_MEMORY_OOM_PRIORITY_MANAGER_H_ +#include <utility> #include <vector> #include "base/compiler_specific.h" @@ -79,6 +80,7 @@ bool is_discarded; base::TimeTicks last_active; base::ProcessHandle renderer_handle; + int child_process_host_id; base::string16 title; int64 tab_contents_id; // unique ID per WebContents }; @@ -111,10 +113,14 @@ // Called when the timer fires, sets oom_adjust_score for all renderers. void AdjustOomPriorities(); - // Returns a list of unique process handles from |stats_list|. If multiple - // tabs use the same process, returns the first process handle. This implies + // Pair to hold child process host id and ProcessHandle + typedef std::pair<int, base::ProcessHandle> ProcessInfo; + + // Returns a list of child process host ids and ProcessHandles from + // |stats_list| with unique pids. If multiple tabs use the same process, + // returns the first child process host id and corresponding pid. This implies // that the processes are selected based on their "most important" tab. - static std::vector<base::ProcessHandle> GetProcessHandles( + static std::vector<ProcessInfo> GetChildProcessInfos( const TabStatsList& stats_list); // Called by AdjustOomPriorities. @@ -137,12 +143,13 @@ base::RepeatingTimer<OomPriorityManager> recent_tab_discard_timer_; content::NotificationRegistrar registrar_; - // This lock is for pid_to_oom_score_ and focus_tab_pid_. - base::Lock pid_to_oom_score_lock_; - // map maintaining the process - oom_score mapping. - typedef base::hash_map<base::ProcessHandle, int> ProcessScoreMap; - ProcessScoreMap pid_to_oom_score_; - base::ProcessHandle focused_tab_pid_; + // This lock is for |oom_score_map_| and |focused_tab_process_info_|. + base::Lock oom_score_lock_; + // Map maintaining the child process host id - oom_score mapping. + typedef base::hash_map<int, int> ProcessScoreMap; + ProcessScoreMap oom_score_map_; + // Holds the focused tab's child process host id. + ProcessInfo focused_tab_process_info_; // Observer for the kernel low memory signal. NULL if tab discarding is // disabled.
diff --git a/chrome/browser/chromeos/memory/oom_priority_manager_unittest.cc b/chrome/browser/chromeos/memory/oom_priority_manager_unittest.cc index 212e7e78..9280b9f 100644 --- a/chrome/browser/chromeos/memory/oom_priority_manager_unittest.cc +++ b/chrome/browser/chromeos/memory/oom_priority_manager_unittest.cc
@@ -43,6 +43,7 @@ OomPriorityManager::TabStats stats; stats.is_pinned = true; stats.renderer_handle = kPinned; + stats.child_process_host_id = kPinned; test_list.push_back(stats); } @@ -50,6 +51,7 @@ OomPriorityManager::TabStats stats; stats.is_app = true; stats.renderer_handle = kApp; + stats.child_process_host_id = kApp; test_list.push_back(stats); } @@ -57,6 +59,7 @@ OomPriorityManager::TabStats stats; stats.is_playing_audio = true; stats.renderer_handle = kPlayingAudio; + stats.child_process_host_id = kPlayingAudio; test_list.push_back(stats); } @@ -64,6 +67,7 @@ OomPriorityManager::TabStats stats; stats.last_active = now - base::TimeDelta::FromSeconds(10); stats.renderer_handle = kRecent; + stats.child_process_host_id = kRecent; test_list.push_back(stats); } @@ -71,6 +75,7 @@ OomPriorityManager::TabStats stats; stats.last_active = now - base::TimeDelta::FromMinutes(15); stats.renderer_handle = kOld; + stats.child_process_host_id = kOld; test_list.push_back(stats); } @@ -78,6 +83,7 @@ OomPriorityManager::TabStats stats; stats.last_active = now - base::TimeDelta::FromDays(365); stats.renderer_handle = kReallyOld; + stats.child_process_host_id = kReallyOld; test_list.push_back(stats); } @@ -86,6 +92,7 @@ stats.is_pinned = true; stats.last_active = now - base::TimeDelta::FromDays(365); stats.renderer_handle = kOldButPinned; + stats.child_process_host_id = kOldButPinned; test_list.push_back(stats); } @@ -93,6 +100,7 @@ OomPriorityManager::TabStats stats; stats.is_reloadable_ui = true; stats.renderer_handle = kReloadableUI; + stats.child_process_host_id = kReloadableUI; test_list.push_back(stats); } @@ -102,6 +110,7 @@ OomPriorityManager::TabStats stats; stats.is_selected = true; stats.renderer_handle = kSelected; + stats.child_process_host_id = kSelected; test_list.push_back(stats); } @@ -119,6 +128,17 @@ EXPECT_EQ(kOld, test_list[index++].renderer_handle); EXPECT_EQ(kReallyOld, test_list[index++].renderer_handle); EXPECT_EQ(kReloadableUI, test_list[index++].renderer_handle); + + index = 0; + EXPECT_EQ(kSelected, test_list[index++].child_process_host_id); + EXPECT_EQ(kPinned, test_list[index++].child_process_host_id); + EXPECT_EQ(kOldButPinned, test_list[index++].child_process_host_id); + EXPECT_EQ(kApp, test_list[index++].child_process_host_id); + EXPECT_EQ(kPlayingAudio, test_list[index++].child_process_host_id); + EXPECT_EQ(kRecent, test_list[index++].child_process_host_id); + EXPECT_EQ(kOld, test_list[index++].child_process_host_id); + EXPECT_EQ(kReallyOld, test_list[index++].child_process_host_id); + EXPECT_EQ(kReloadableUI, test_list[index++].child_process_host_id); } TEST_F(OomPriorityManagerTest, IsReloadableUI) { @@ -144,44 +164,58 @@ TEST_F(OomPriorityManagerTest, GetProcessHandles) { OomPriorityManager::TabStats stats; - std::vector<base::ProcessHandle> handles; + std::vector<OomPriorityManager::ProcessInfo> process_id_pairs; - // Empty stats list gives empty handles list. + // Empty stats list gives empty |process_id_pairs| list. OomPriorityManager::TabStatsList empty_list; - handles = OomPriorityManager::GetProcessHandles(empty_list); - EXPECT_EQ(0u, handles.size()); + process_id_pairs = + OomPriorityManager::GetChildProcessInfos(empty_list); + EXPECT_EQ(0u, process_id_pairs.size()); - // Two tabs in two different processes generates two handles out. + // Two tabs in two different processes generates two + // |child_process_host_id| out. OomPriorityManager::TabStatsList two_list; - stats.renderer_handle = 100; - two_list.push_back(stats); + stats.child_process_host_id = 100; stats.renderer_handle = 101; two_list.push_back(stats); - handles = OomPriorityManager::GetProcessHandles(two_list); - EXPECT_EQ(2u, handles.size()); - EXPECT_EQ(100, handles[0]); - EXPECT_EQ(101, handles[1]); + stats.child_process_host_id = 200; + stats.renderer_handle = 201; + two_list.push_back(stats); + process_id_pairs = OomPriorityManager::GetChildProcessInfos(two_list); + EXPECT_EQ(2u, process_id_pairs.size()); + EXPECT_EQ(100, process_id_pairs[0].first); + EXPECT_EQ(101, process_id_pairs[0].second); + EXPECT_EQ(200, process_id_pairs[1].first); + EXPECT_EQ(201, process_id_pairs[1].second); // Zero handles are removed. OomPriorityManager::TabStatsList zero_handle_list; + stats.child_process_host_id = 100; stats.renderer_handle = 0; zero_handle_list.push_back(stats); - handles = OomPriorityManager::GetProcessHandles(zero_handle_list); - EXPECT_EQ(0u, handles.size()); + process_id_pairs = + OomPriorityManager::GetChildProcessInfos(zero_handle_list); + EXPECT_EQ(0u, process_id_pairs.size()); // Two tabs in the same process generates one handle out. When a duplicate // occurs the later instance is dropped. OomPriorityManager::TabStatsList same_process_list; - stats.renderer_handle = 100; - same_process_list.push_back(stats); + stats.child_process_host_id = 100; stats.renderer_handle = 101; same_process_list.push_back(stats); - stats.renderer_handle = 100; // Duplicate. + stats.child_process_host_id = 200; + stats.renderer_handle = 201; same_process_list.push_back(stats); - handles = OomPriorityManager::GetProcessHandles(same_process_list); - EXPECT_EQ(2u, handles.size()); - EXPECT_EQ(100, handles[0]); - EXPECT_EQ(101, handles[1]); + stats.child_process_host_id = 300; + stats.renderer_handle = 101; // Duplicate. + same_process_list.push_back(stats); + process_id_pairs = + OomPriorityManager::GetChildProcessInfos(same_process_list); + EXPECT_EQ(2u, process_id_pairs.size()); + EXPECT_EQ(100, process_id_pairs[0].first); + EXPECT_EQ(101, process_id_pairs[0].second); + EXPECT_EQ(200, process_id_pairs[1].first); + EXPECT_EQ(201, process_id_pairs[1].second); } } // namespace chromeos
diff --git a/chrome/browser/chromeos/policy/OWNERS b/chrome/browser/chromeos/policy/OWNERS index 32e8aae..78c3a59 100644 --- a/chrome/browser/chromeos/policy/OWNERS +++ b/chrome/browser/chromeos/policy/OWNERS
@@ -1,6 +1,4 @@ mnissler@chromium.org -pastarmovj@chromium.org -joaodasilva@chromium.org bartfab@chromium.org atwilson@chromium.org pneubeck@chromium.org
diff --git a/chrome/browser/chromeos/policy/cloud_external_data_manager_base_unittest.cc b/chrome/browser/chromeos/policy/cloud_external_data_manager_base_unittest.cc index fe9d3f9..8ba07da 100644 --- a/chrome/browser/chromeos/policy/cloud_external_data_manager_base_unittest.cc +++ b/chrome/browser/chromeos/policy/cloud_external_data_manager_base_unittest.cc
@@ -138,6 +138,7 @@ std::map<int, std::string*> callback_data_; PolicyDetailsMap policy_details_; + private: DISALLOW_COPY_AND_ASSIGN(CloudExternalDataManagerBaseTest); };
diff --git a/chrome/browser/chromeos/policy/cloud_external_data_store_unittest.cc b/chrome/browser/chromeos/policy/cloud_external_data_store_unittest.cc index 4ac05cd1..ca2341af 100644 --- a/chrome/browser/chromeos/policy/cloud_external_data_store_unittest.cc +++ b/chrome/browser/chromeos/policy/cloud_external_data_store_unittest.cc
@@ -41,6 +41,7 @@ base::ScopedTempDir temp_dir_; scoped_ptr<ResourceCache> resource_cache_; + private: DISALLOW_COPY_AND_ASSIGN(CouldExternalDataStoreTest); };
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_invalidator_unittest.cc b/chrome/browser/chromeos/policy/device_cloud_policy_invalidator_unittest.cc index dd2b3f6..87ea8be 100644 --- a/chrome/browser/chromeos/policy/device_cloud_policy_invalidator_unittest.cc +++ b/chrome/browser/chromeos/policy/device_cloud_policy_invalidator_unittest.cc
@@ -80,7 +80,7 @@ virtual void TearDown() override; // Ownership is not passed. The Profile is owned by the global ProfileManager. - Profile *LogInAndReturnProfile(const std::string& user_id); + Profile* LogInAndReturnProfile(const std::string& user_id); invalidation::TiclInvalidationService* GetDeviceInvalidationService(); bool HasDeviceInvalidationServiceObserver() const; @@ -180,7 +180,7 @@ chromeos::SystemSaltGetter::Shutdown(); } -Profile *DeviceCloudPolicyInvalidatorTest::LogInAndReturnProfile( +Profile* DeviceCloudPolicyInvalidatorTest::LogInAndReturnProfile( const std::string& user_id) { fake_user_manager_->AddUser(user_id); Profile* profile = profile_manager_.CreateTestingProfile(user_id); @@ -196,8 +196,8 @@ return invalidator_->device_invalidation_service_.get(); } -bool DeviceCloudPolicyInvalidatorTest::HasDeviceInvalidationServiceObserver( - ) const { +bool DeviceCloudPolicyInvalidatorTest::HasDeviceInvalidationServiceObserver() + const { return invalidator_->device_invalidation_service_observer_.get(); }
diff --git a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc index 125e03b..b10af17 100644 --- a/chrome/browser/chromeos/policy/device_local_account_browsertest.cc +++ b/chrome/browser/chromeos/policy/device_local_account_browsertest.cc
@@ -74,6 +74,7 @@ #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/browser_list_observer.h" #include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/extensions/app_launch_params.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/browser/ui/host_desktop.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" @@ -116,6 +117,7 @@ #include "extensions/browser/extension_system.h" #include "extensions/browser/management_policy.h" #include "extensions/browser/notification_types.h" +#include "extensions/common/constants.h" #include "extensions/common/extension.h" #include "net/base/url_util.h" #include "net/http/http_status_code.h" @@ -176,6 +178,9 @@ const char kGoodExtensionCRXPath[] = "extensions/good.crx"; const char kGoodExtensionVersion[] = "1.0"; const char kPackagedAppCRXPath[] = "extensions/platform_apps/app_window_2.crx"; +const char kShowManagedStorageID[] = "ongnjlefhnoajpbodoldndkbkdgfomlp"; +const char kShowManagedStorageCRXPath[] = "extensions/show_managed_storage.crx"; +const char kShowManagedStorageVersion[] = "1.0"; const char kExternalData[] = "External data"; const char kExternalDataURL[] = "http://localhost/external_data"; @@ -382,6 +387,12 @@ return user_manager::UserManager::Get()->IsSessionStarted(); } +void PolicyChangedCallback(const base::Closure& callback, + const base::Value* old_value, + const base::Value* new_value) { + callback.Run(); +} + } // namespace class DeviceLocalAccountTest : public DevicePolicyCrosBrowserTest, @@ -1325,8 +1336,9 @@ // Start the platform app, causing it to open a window. run_loop_.reset(new base::RunLoop); - OpenApplication(AppLaunchParams( - profile, app, extensions::LAUNCH_CONTAINER_NONE, NEW_WINDOW)); + OpenApplication(AppLaunchParams(profile, app, + extensions::LAUNCH_CONTAINER_NONE, NEW_WINDOW, + extensions::SOURCE_UNTRACKED)); run_loop_->Run(); EXPECT_EQ(1U, app_window_registry->app_windows().size()); @@ -1960,6 +1972,105 @@ .id()); } +// Test is disabled because it is flaky. crbug.com/438239 +IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, DISABLED_PolicyForExtensions) { + // Set up a test update server for the Show Managed Storage app. + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); + TestingUpdateManifestProvider testing_update_manifest_provider( + kRelativeUpdateURL); + testing_update_manifest_provider.AddUpdate( + kShowManagedStorageID, + kShowManagedStorageVersion, + embedded_test_server()->GetURL(std::string("/") + + kShowManagedStorageCRXPath)); + embedded_test_server()->RegisterRequestHandler( + base::Bind(&TestingUpdateManifestProvider::HandleRequest, + base::Unretained(&testing_update_manifest_provider))); + + // Force-install the Show Managed Storage app. This app can be installed in + // public sessions because it's whitelisted for testing purposes. + em::StringList* forcelist = device_local_account_policy_.payload() + .mutable_extensioninstallforcelist()->mutable_value(); + forcelist->add_entries(base::StringPrintf( + "%s;%s", + kShowManagedStorageID, + embedded_test_server()->GetURL(kRelativeUpdateURL).spec().c_str())); + + UploadAndInstallDeviceLocalAccountPolicy(); + AddPublicSessionToDevicePolicy(kAccountId1); + WaitForPolicy(); + + // Set a policy for the app at the policy testserver. + test_server_.UpdatePolicyData(dm_protocol::kChromeExtensionPolicyType, + kShowManagedStorageID, + "{" + " \"string\": {" + " \"Value\": \"policy test value one\"" + " }" + "}"); + + // Observe the app installation after login. + content::WindowedNotificationObserver extension_observer( + extensions::NOTIFICATION_EXTENSION_WILL_BE_INSTALLED_DEPRECATED, + base::Bind(DoesInstallSuccessReferToId, kShowManagedStorageID)); + ASSERT_NO_FATAL_FAILURE(StartLogin(std::string(), std::string())); + WaitForSessionStart(); + extension_observer.Wait(); + + // Verify that the app was installed. + Profile* profile = GetProfileForTest(); + ASSERT_TRUE(profile); + ExtensionService* extension_service = + extensions::ExtensionSystem::Get(profile)->extension_service(); + EXPECT_TRUE(extension_service->GetExtensionById(kShowManagedStorageID, true)); + + // Wait for the app policy if it hasn't been fetched yet. + ProfilePolicyConnector* connector = + ProfilePolicyConnectorFactory::GetForProfile(profile); + ASSERT_TRUE(connector); + PolicyService* policy_service = connector->policy_service(); + ASSERT_TRUE(policy_service); + const PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, kShowManagedStorageID); + if (policy_service->GetPolicies(ns).empty()) { + PolicyChangeRegistrar policy_registrar(policy_service, ns); + base::RunLoop run_loop; + policy_registrar.Observe( + "string", base::Bind(&PolicyChangedCallback, run_loop.QuitClosure())); + run_loop.Run(); + } + + // Verify that the app policy was set. + base::StringValue expected_value("policy test value one"); + EXPECT_TRUE(base::Value::Equals( + &expected_value, + policy_service->GetPolicies(ns).GetValue("string"))); + + // Now update the policy at the server. + test_server_.UpdatePolicyData(dm_protocol::kChromeExtensionPolicyType, + kShowManagedStorageID, + "{" + " \"string\": {" + " \"Value\": \"policy test value two\"" + " }" + "}"); + + // And issue a policy refresh. + { + PolicyChangeRegistrar policy_registrar(policy_service, ns); + base::RunLoop run_loop; + policy_registrar.Observe( + "string", base::Bind(&PolicyChangedCallback, run_loop.QuitClosure())); + policy_service->RefreshPolicies(base::Closure()); + run_loop.Run(); + } + + // Verify that the app policy was updated. + base::StringValue expected_new_value("policy test value two"); + EXPECT_TRUE(base::Value::Equals( + &expected_new_value, + policy_service->GetPolicies(ns).GetValue("string"))); +} + class TermsOfServiceDownloadTest : public DeviceLocalAccountTest, public testing::WithParamInterface<bool> { };
diff --git a/chrome/browser/chromeos/policy/device_local_account_extension_tracker.cc b/chrome/browser/chromeos/policy/device_local_account_extension_tracker.cc index 9b86e9b..546c5bd 100644 --- a/chrome/browser/chromeos/policy/device_local_account_extension_tracker.cc +++ b/chrome/browser/chromeos/policy/device_local_account_extension_tracker.cc
@@ -12,6 +12,7 @@ #include "components/policy/core/common/policy_map.h" #include "components/policy/core/common/policy_namespace.h" #include "components/policy/core/common/schema.h" +#include "components/policy/core/common/schema_map.h" #include "components/policy/core/common/schema_registry.h" #include "extensions/browser/pref_names.h" @@ -74,6 +75,17 @@ for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) { PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, it.key()); + if (schema_registry_->schema_map()->GetSchema(ns)) { + // Important detail: Don't register the component again if it already + // has a schema! If the session already started for this public session + // then the real Schema for the extension has already been set by the + // ManagedValueStoreCache::ExtensionTracker. Do not override that schema + // with an invalid one now, or the policy for the extension will be + // dropped. + // However, if the forcelist is updated then we need to register the new + // component ID so that its remote policy data can be fetched. + continue; + } schema_registry_->RegisterComponent(ns, Schema()); }
diff --git a/chrome/browser/chromeos/policy/device_local_account_extension_tracker.h b/chrome/browser/chromeos/policy/device_local_account_extension_tracker.h index a357986e..2b24d0ae 100644 --- a/chrome/browser/chromeos/policy/device_local_account_extension_tracker.h +++ b/chrome/browser/chromeos/policy/device_local_account_extension_tracker.h
@@ -16,6 +16,11 @@ // Helper class that keeps all the extensions that a device-local account uses // registered in a SchemaRegistry. +// This makes it possible to precache the policy for extensions for public +// sessions before the session is started (e.g. during enrollment). +// Otherwise, the ComponentCloudPolicyService would ignore the +// PolicyFetchResponses from the DMServer because the SchemaRegistry for this +// account doesn't have this extension "installed". class DeviceLocalAccountExtensionTracker : public CloudPolicyStore::Observer { public: DeviceLocalAccountExtensionTracker(
diff --git a/chrome/browser/chromeos/policy/device_local_account_policy_service.cc b/chrome/browser/chromeos/policy/device_local_account_policy_service.cc index e11a02f..19a8f3b 100644 --- a/chrome/browser/chromeos/policy/device_local_account_policy_service.cc +++ b/chrome/browser/chromeos/policy/device_local_account_policy_service.cc
@@ -173,11 +173,11 @@ if (!client) return; + CreateComponentCloudPolicyService(request_context, client.get()); core_.Connect(client.Pass()); external_data_manager_->Connect(request_context); core_.StartRefreshScheduler(); UpdateRefreshDelay(); - CreateComponentCloudPolicyService(request_context); } void DeviceLocalAccountPolicyBroker::UpdateRefreshDelay() { @@ -213,7 +213,8 @@ } void DeviceLocalAccountPolicyBroker::CreateComponentCloudPolicyService( - const scoped_refptr<net::URLRequestContextGetter>& request_context) { + const scoped_refptr<net::URLRequestContextGetter>& request_context, + CloudPolicyClient* client) { if (CommandLine::ForCurrentProcess()->HasSwitch( switches::kDisableComponentCloudPolicy)) { // Disabled via the command line. @@ -229,6 +230,7 @@ this, &schema_registry_, core(), + client, resource_cache.Pass(), request_context, content::BrowserThread::GetMessageLoopProxyForThread(
diff --git a/chrome/browser/chromeos/policy/device_local_account_policy_service.h b/chrome/browser/chromeos/policy/device_local_account_policy_service.h index 814437e..b391a5c 100644 --- a/chrome/browser/chromeos/policy/device_local_account_policy_service.h +++ b/chrome/browser/chromeos/policy/device_local_account_policy_service.h
@@ -112,7 +112,8 @@ private: void CreateComponentCloudPolicyService( - const scoped_refptr<net::URLRequestContextGetter>& request_context); + const scoped_refptr<net::URLRequestContextGetter>& request_context, + CloudPolicyClient* client); const std::string account_id_; const std::string user_id_;
diff --git a/chrome/browser/chromeos/policy/device_status_collector_browsertest.cc b/chrome/browser/chromeos/policy/device_status_collector_browsertest.cc index d2c5696..68d7072 100644 --- a/chrome/browser/chromeos/policy/device_status_collector_browsertest.cc +++ b/chrome/browser/chromeos/policy/device_status_collector_browsertest.cc
@@ -308,7 +308,7 @@ GetStatus(); EXPECT_EQ(1, status_.active_period_size()); EXPECT_EQ(1 * ActivePeriodMilliseconds(), GetActiveMilliseconds(status_)); - status_.clear_active_period(); // Clear the result protobuf. + status_.clear_active_period(); // Clear the result protobuf. // Test multiple consecutive active samples. status_collector_->Simulate(test_states, @@ -659,7 +659,7 @@ const char* mac_address; const char* meid; const char* imei; - int expected_type; // proto enum type value, -1 for not present. + int expected_type; // proto enum type value, -1 for not present. }; static const FakeDeviceData kFakeDevices[] = { @@ -727,7 +727,7 @@ TEST_F(DeviceStatusCollectorNetworkInterfacesTest, NetworkInterfaces) { // Interfaces should be reported by default. GetStatus(); - EXPECT_TRUE(status_.network_interface_size() > 0); + EXPECT_LT(0, status_.network_interface_size()); // No interfaces should be reported if the policy is off. cros_settings_->SetBoolean(chromeos::kReportDeviceNetworkInterfaces, false);
diff --git a/chrome/browser/chromeos/policy/login_screen_default_policy_browsertest.cc b/chrome/browser/chromeos/policy/login_screen_default_policy_browsertest.cc index 0114da8..c93f0f4 100644 --- a/chrome/browser/chromeos/policy/login_screen_default_policy_browsertest.cc +++ b/chrome/browser/chromeos/policy/login_screen_default_policy_browsertest.cc
@@ -463,4 +463,4 @@ EXPECT_TRUE(accessibility_manager->IsVirtualKeyboardEnabled()); } -} // namespace policy +} // namespace policy
diff --git a/chrome/browser/chromeos/policy/network_configuration_updater_unittest.cc b/chrome/browser/chromeos/policy/network_configuration_updater_unittest.cc index 0d508ed..18650cd2 100644 --- a/chrome/browser/chromeos/policy/network_configuration_updater_unittest.cc +++ b/chrome/browser/chromeos/policy/network_configuration_updater_unittest.cc
@@ -84,14 +84,14 @@ }; class FakeNetworkDeviceHandler : public chromeos::FakeNetworkDeviceHandler { - public: - FakeNetworkDeviceHandler() : allow_roaming_(false) {} + public: + FakeNetworkDeviceHandler() : allow_roaming_(false) {} - virtual void SetCellularAllowRoaming(bool allow_roaming) override { - allow_roaming_ = allow_roaming; - } + virtual void SetCellularAllowRoaming(bool allow_roaming) override { + allow_roaming_ = allow_roaming; + } - bool allow_roaming_; + bool allow_roaming_; private: DISALLOW_COPY_AND_ASSIGN(FakeNetworkDeviceHandler);
diff --git a/chrome/browser/chromeos/policy/power_policy_browsertest.cc b/chrome/browser/chromeos/policy/power_policy_browsertest.cc index 022cd3d..28a8e95 100644 --- a/chrome/browser/chromeos/policy/power_policy_browsertest.cc +++ b/chrome/browser/chromeos/policy/power_policy_browsertest.cc
@@ -159,6 +159,7 @@ virtual void SetUpOnMainThread() override; virtual void TearDownOnMainThread() override; + private: DISALLOW_COPY_AND_ASSIGN(PowerPolicyLoginScreenBrowserTest); }; @@ -169,6 +170,7 @@ // PowerPolicyBrowserTestBase: virtual void SetUpOnMainThread() override; + private: DISALLOW_COPY_AND_ASSIGN(PowerPolicyInSessionBrowserTest); };
diff --git a/chrome/browser/chromeos/policy/recommendation_restorer_factory.h b/chrome/browser/chromeos/policy/recommendation_restorer_factory.h index e137d0d9..c8275c4 100644 --- a/chrome/browser/chromeos/policy/recommendation_restorer_factory.h +++ b/chrome/browser/chromeos/policy/recommendation_restorer_factory.h
@@ -37,6 +37,6 @@ DISALLOW_COPY_AND_ASSIGN(RecommendationRestorerFactory); }; -} // namespace policy +} // namespace policy #endif // CHROME_BROWSER_CHROMEOS_POLICY_RECOMMENDATION_RESTORER_FACTORY_H_
diff --git a/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.cc b/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.cc index 7e93376..f1ce0c5b 100644 --- a/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.cc +++ b/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.cc
@@ -126,14 +126,13 @@ new CloudPolicyClient(std::string(), std::string(), kPolicyVerificationKeyHash, user_affiliation, device_management_service, request_context)); + CreateComponentCloudPolicyService(component_policy_cache_path_, + request_context, cloud_policy_client.get()); core()->Connect(cloud_policy_client.Pass()); client()->AddObserver(this); external_data_manager_->Connect(request_context); - CreateComponentCloudPolicyService(component_policy_cache_path_, - request_context); - // Determine the next step after the CloudPolicyService initializes. if (service()->IsInitializationComplete()) { OnInitializationCompleted(service());
diff --git a/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos.h b/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos.h index 07805d94..642a2b37 100644 --- a/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos.h +++ b/chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos.h
@@ -68,7 +68,7 @@ void OnPolicyToStoreValidated(UserCloudPolicyValidator* validator); // Called back from SessionManagerClient for policy store operations. - void OnPolicyStored(bool); + void OnPolicyStored(bool success); // Called back from SessionManagerClient for policy load operations. void OnPolicyRetrieved(const std::string& policy_blob);
diff --git a/chrome/browser/chromeos/policy/user_network_configuration_updater_factory.h b/chrome/browser/chromeos/policy/user_network_configuration_updater_factory.h index ab1c2fe1..99530b4 100644 --- a/chrome/browser/chromeos/policy/user_network_configuration_updater_factory.h +++ b/chrome/browser/chromeos/policy/user_network_configuration_updater_factory.h
@@ -18,7 +18,7 @@ class UserNetworkConfigurationUpdater; - // Factory to create UserNetworkConfigurationUpdater. +// Factory to create UserNetworkConfigurationUpdater. class UserNetworkConfigurationUpdaterFactory : public BrowserContextKeyedServiceFactory { public:
diff --git a/chrome/browser/chromeos/policy/variations_service_policy_browsertest.cc b/chrome/browser/chromeos/policy/variations_service_policy_browsertest.cc index c8eba3d..ad1cac9 100644 --- a/chrome/browser/chromeos/policy/variations_service_policy_browsertest.cc +++ b/chrome/browser/chromeos/policy/variations_service_policy_browsertest.cc
@@ -51,4 +51,4 @@ EXPECT_EQ("restricted", value); } -} // namespace policy +} // namespace policy
diff --git a/chrome/browser/chromeos/power/freezer_cgroup_process_manager.cc b/chrome/browser/chromeos/power/freezer_cgroup_process_manager.cc index 7c77836..59f14d2 100644 --- a/chrome/browser/chromeos/power/freezer_cgroup_process_manager.cc +++ b/chrome/browser/chromeos/power/freezer_cgroup_process_manager.cc
@@ -8,32 +8,20 @@ #include "base/files/file_util.h" #include "base/logging.h" -#include "base/strings/stringprintf.h" namespace chromeos { namespace { -const char kFreezerPath[] = "/sys/fs/cgroup/freezer/chrome_renderers"; -const char kToBeFrozen[] = "to_be_frozen"; -const char kFreezerState[] = "freezer.state"; -const char kCgroupProcs[] = "cgroup.procs"; - +const char kFreezerStatePath[] = + "/sys/fs/cgroup/freezer/chrome_renderers/freezer.state"; const char kFreezeCommand[] = "FROZEN"; const char kThawCommand[] = "THAWED"; } // namespace FreezerCgroupProcessManager::FreezerCgroupProcessManager() - : default_control_path_(base::FilePath(kFreezerPath).Append(kCgroupProcs)), - to_be_frozen_control_path_(base::FilePath(kFreezerPath) - .AppendASCII(kToBeFrozen) - .AppendASCII(kCgroupProcs)), - to_be_frozen_state_path_(base::FilePath(kFreezerPath) - .AppendASCII(kToBeFrozen) - .AppendASCII(kFreezerState)), - enabled_(base::PathIsWritable(default_control_path_) && - base::PathIsWritable(to_be_frozen_control_path_) && - base::PathIsWritable(to_be_frozen_state_path_)) { + : state_path_(base::FilePath(kFreezerStatePath)), + enabled_(base::PathIsWritable(state_path_)) { if (!enabled_) { LOG(WARNING) << "Cgroup freezer does not exist or is not writable. " << "Unable to freeze renderer processes."; @@ -43,15 +31,6 @@ FreezerCgroupProcessManager::~FreezerCgroupProcessManager() { } -void FreezerCgroupProcessManager::SetShouldFreezeRenderer( - base::ProcessHandle handle, - bool frozen) { - std::string pid = base::StringPrintf("%d", handle); - - WriteCommandToFile( - pid, frozen ? to_be_frozen_control_path_ : default_control_path_); -} - bool FreezerCgroupProcessManager::FreezeRenderers() { if (!enabled_) { LOG(ERROR) << "Attempting to freeze renderers when the freezer cgroup is " @@ -59,7 +38,7 @@ return false; } - return WriteCommandToFile(kFreezeCommand, to_be_frozen_state_path_); + return WriteCommandToStateFile(kFreezeCommand); } bool FreezerCgroupProcessManager::ThawRenderers() { @@ -69,23 +48,23 @@ return false; } - return WriteCommandToFile(kThawCommand, to_be_frozen_state_path_); + return WriteCommandToStateFile(kThawCommand); } bool FreezerCgroupProcessManager::CanFreezeRenderers() { return enabled_; } -bool FreezerCgroupProcessManager::WriteCommandToFile( - const std::string& command, - const base::FilePath& file) { - int bytes = base::WriteFile(file, command.c_str(), command.size()); +bool FreezerCgroupProcessManager::WriteCommandToStateFile( + const std::string& command) { + int bytes = base::WriteFile(state_path_, command.c_str(), command.size()); if (bytes == -1) { - PLOG(ERROR) << "Writing " << command << " to " << file.value() << " failed"; + PLOG(ERROR) << "Writing " << command << " to " << state_path_.value() + << " failed"; return false; } else if (bytes != static_cast<int>(command.size())) { - LOG(ERROR) << "Only wrote " << bytes << " byte(s) when writing " << command - << " to " << file.value(); + LOG(ERROR) << "Only wrote " << bytes << " byte(s) when writing " + << command << " to " << state_path_.value(); return false; } return true;
diff --git a/chrome/browser/chromeos/power/freezer_cgroup_process_manager.h b/chrome/browser/chromeos/power/freezer_cgroup_process_manager.h index 3a0b9ae..2cf095c8 100644 --- a/chrome/browser/chromeos/power/freezer_cgroup_process_manager.h +++ b/chrome/browser/chromeos/power/freezer_cgroup_process_manager.h
@@ -5,11 +5,8 @@ #ifndef CHROME_BROWSER_CHROMEOS_POWER_FREEZER_CGROUP_PROCESS_MANAGER_H_ #define CHROME_BROWSER_CHROMEOS_POWER_FREEZER_CGROUP_PROCESS_MANAGER_H_ -#include <string> - #include "base/files/file_path.h" #include "base/macros.h" -#include "base/process/process_handle.h" #include "chrome/browser/chromeos/power/renderer_freezer.h" namespace chromeos { @@ -18,26 +15,17 @@ class FreezerCgroupProcessManager : public RendererFreezer::Delegate { public: FreezerCgroupProcessManager(); - ~FreezerCgroupProcessManager() override; + virtual ~FreezerCgroupProcessManager(); // RendererFreezer::Delegate overrides. - void SetShouldFreezeRenderer(base::ProcessHandle handle, - bool frozen) override; - bool FreezeRenderers() override; - bool ThawRenderers() override; - bool CanFreezeRenderers() override; + virtual bool FreezeRenderers() override; + virtual bool ThawRenderers() override; + virtual bool CanFreezeRenderers() override; private: - bool WriteCommandToFile(const std::string& command, - const base::FilePath& file); + bool WriteCommandToStateFile(const std::string& command); - // Control path for the cgroup that is not frozen. - base::FilePath default_control_path_; - - // Control and state paths for the cgroup whose processes will be frozen. - base::FilePath to_be_frozen_control_path_; - base::FilePath to_be_frozen_state_path_; - + base::FilePath state_path_; bool enabled_; DISALLOW_COPY_AND_ASSIGN(FreezerCgroupProcessManager);
diff --git a/chrome/browser/chromeos/power/renderer_freezer.cc b/chrome/browser/chromeos/power/renderer_freezer.cc index 6548c9d5..1aaa79a7 100644 --- a/chrome/browser/chromeos/power/renderer_freezer.cc +++ b/chrome/browser/chromeos/power/renderer_freezer.cc
@@ -4,24 +4,10 @@ #include "chrome/browser/chromeos/power/renderer_freezer.h" -#include <string> - #include "base/bind.h" #include "base/logging.h" #include "base/message_loop/message_loop.h" -#include "base/process/process_handle.h" #include "chromeos/dbus/dbus_thread_manager.h" -#include "content/public/browser/notification_details.h" -#include "content/public/browser/notification_service.h" -#include "content/public/browser/notification_source.h" -#include "content/public/browser/notification_types.h" -#include "content/public/browser/render_process_host.h" -#include "extensions/browser/extension_registry.h" -#include "extensions/browser/notification_types.h" -#include "extensions/browser/process_map.h" -#include "extensions/common/extension.h" -#include "extensions/common/permissions/api_permission.h" -#include "extensions/common/permissions/permissions_data.h" namespace chromeos { @@ -29,33 +15,36 @@ : frozen_(false), delegate_(delegate.Pass()), weak_factory_(this) { - if (delegate_->CanFreezeRenderers()) { - DBusThreadManager::Get() - ->GetPowerManagerClient() - ->SetRenderProcessManagerDelegate(weak_factory_.GetWeakPtr()); - - registrar_.Add( - this, - content::NOTIFICATION_RENDERER_PROCESS_CREATED, - content::NotificationService::AllBrowserContextsAndSources()); - } + if (delegate_->CanFreezeRenderers()) + DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(this); } RendererFreezer::~RendererFreezer() { - for (int rph_id : gcm_extension_processes_) { - content::RenderProcessHost* host = - content::RenderProcessHost::FromID(rph_id); - if (host) - host->RemoveObserver(this); - } + if (delegate_->CanFreezeRenderers()) + DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(this); } void RendererFreezer::SuspendImminent() { - if (delegate_->FreezeRenderers()) - frozen_ = true; + // If there was already a callback pending, this will cancel it and create a + // new one. + suspend_readiness_callback_.Reset( + base::Bind(&RendererFreezer::OnReadyToSuspend, + weak_factory_.GetWeakPtr(), + DBusThreadManager::Get() + ->GetPowerManagerClient() + ->GetSuspendReadinessCallback())); + + base::MessageLoop::current()->PostTask( + FROM_HERE, suspend_readiness_callback_.callback()); } -void RendererFreezer::SuspendDone() { +void RendererFreezer::SuspendDone(const base::TimeDelta& sleep_duration) { + // If we get a SuspendDone before we've had a chance to run OnReadyForSuspend, + // we should cancel it because we no longer want to freeze the renderers. If + // we've already run it then cancelling the callback shouldn't really make a + // difference. + suspend_readiness_callback_.Cancel(); + if (!frozen_) return; @@ -69,98 +58,13 @@ frozen_ = false; } -void RendererFreezer::Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) { - switch (type) { - case content::NOTIFICATION_RENDERER_PROCESS_CREATED: { - content::RenderProcessHost* process = - content::Source<content::RenderProcessHost>(source).ptr(); - OnRenderProcessCreated(process); - break; - } - default: { - NOTREACHED(); - break; - } - } -} +void RendererFreezer::OnReadyToSuspend( + const base::Closure& power_manager_callback) { + if (delegate_->FreezeRenderers()) + frozen_ = true; -void RendererFreezer::RenderProcessExited(content::RenderProcessHost* host, - base::TerminationStatus status, - int exit_code) { - auto it = gcm_extension_processes_.find(host->GetID()); - if (it == gcm_extension_processes_.end()) { - LOG(ERROR) << "Received unrequested RenderProcessExited message"; - return; - } - gcm_extension_processes_.erase(it); - - // When this function is called, the renderer process has died but the - // RenderProcessHost will not be destroyed. If a new renderer process is - // created for this RPH, registering as an observer again will trigger a - // warning about duplicate observers. To prevent this we just stop observing - // this RPH until another renderer process is created for it. - host->RemoveObserver(this); -} - -void RendererFreezer::RenderProcessHostDestroyed( - content::RenderProcessHost* host) { - auto it = gcm_extension_processes_.find(host->GetID()); - if (it == gcm_extension_processes_.end()) { - LOG(ERROR) << "Received unrequested RenderProcessHostDestroyed message"; - return; - } - - gcm_extension_processes_.erase(it); -} - -void RendererFreezer::OnRenderProcessCreated(content::RenderProcessHost* rph) { - const int rph_id = rph->GetID(); - - if (gcm_extension_processes_.find(rph_id) != gcm_extension_processes_.end()) { - LOG(ERROR) << "Received duplicate notifications about the creation of a " - << "RenderProcessHost with id " << rph_id; - return; - } - - // According to extensions::ProcessMap, extensions and renderers have a - // many-to-many relationship. Specifically, a hosted app can appear in many - // renderers while any other kind of extension can be running in "split mode" - // if there is an incognito window open and so could appear in two renderers. - // - // We don't care about hosted apps because they cannot use GCM so we only need - // to worry about extensions in "split mode". Luckily for us this function is - // called any time a new renderer process is created so we don't really need - // to care whether we are currently in an incognito context. We just need to - // iterate over all the extensions in the newly created process and take the - // appropriate action based on whether we find an extension using GCM. - content::BrowserContext* context = rph->GetBrowserContext(); - extensions::ExtensionRegistry* registry = - extensions::ExtensionRegistry::Get(context); - for (const std::string& extension_id : - extensions::ProcessMap::Get(context)->GetExtensionsInProcess(rph_id)) { - if (!registry->GetExtensionById(extension_id, - extensions::ExtensionRegistry::ENABLED) - ->permissions_data() - ->HasAPIPermission(extensions::APIPermission::kGcm)) { - continue; - } - - // This renderer has an extension that is using GCM. Make sure it is not - // frozen during suspend. - delegate_->SetShouldFreezeRenderer(rph->GetHandle(), false); - gcm_extension_processes_.insert(rph_id); - - // Watch to see if the renderer process or the RenderProcessHost is - // destroyed. - rph->AddObserver(this); - return; - } - - // We didn't find an extension in this RenderProcessHost that is using GCM so - // we can go ahead and freeze it on suspend. - delegate_->SetShouldFreezeRenderer(rph->GetHandle(), true); + DCHECK(!power_manager_callback.is_null()); + power_manager_callback.Run(); } } // namespace chromeos
diff --git a/chrome/browser/chromeos/power/renderer_freezer.h b/chrome/browser/chromeos/power/renderer_freezer.h index 78ce9d6..d5ac6f9 100644 --- a/chrome/browser/chromeos/power/renderer_freezer.h +++ b/chrome/browser/chromeos/power/renderer_freezer.h
@@ -5,24 +5,14 @@ #ifndef CHROME_BROWSER_CHROMEOS_POWER_RENDERER_FREEZER_H_ #define CHROME_BROWSER_CHROMEOS_POWER_RENDERER_FREEZER_H_ -#include <set> - #include "base/callback.h" #include "base/cancelable_callback.h" #include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" -#include "base/process/kill.h" #include "base/time/time.h" #include "chromeos/chromeos_export.h" #include "chromeos/dbus/power_manager_client.h" -#include "content/public/browser/notification_observer.h" -#include "content/public/browser/notification_registrar.h" -#include "content/public/browser/render_process_host_observer.h" - -namespace content { -class RenderProcessHost; -} namespace chromeos { @@ -30,26 +20,18 @@ // them after the system fully resumes. This class registers itself as a // PowerManagerClient::Observer on creation and unregisters itself on // destruction. -class CHROMEOS_EXPORT RendererFreezer - : public PowerManagerClient::RenderProcessManagerDelegate, - public content::NotificationObserver, - public content::RenderProcessHostObserver { +class CHROMEOS_EXPORT RendererFreezer : public PowerManagerClient::Observer { public: class Delegate { public: virtual ~Delegate() {} - // If |frozen| is true, marks the renderer process |handle| to be frozen - // when FreezeRenderers() is called; otherwise marks it to remain unfrozen. - virtual void SetShouldFreezeRenderer(base::ProcessHandle handle, - bool frozen) = 0; - - // Freezes the renderers marked for freezing by SetShouldFreezeRenderer(). - // Returns true if the operation was successful. + // Freezes the chrome renderers. Returns true if the operation was + // successful. virtual bool FreezeRenderers() = 0; - // Thaws the chrome renderers that were frozen by the call to - // FreezeRenderers(). Returns true if the operation was successful. + // Thaws the chrome renderers. Returns true if the operation was + // successful. virtual bool ThawRenderers() = 0; // Returns true iff the delegate is capable of freezing renderers. @@ -57,40 +39,23 @@ }; explicit RendererFreezer(scoped_ptr<Delegate> delegate); - ~RendererFreezer() override; + virtual ~RendererFreezer(); - // PowerManagerClient::RenderProcessManagerDelegate implementation. - void SuspendImminent() override; - void SuspendDone() override; - - // content::NotificationObserver implementation. - void Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) override; - - // content::RenderProcessHostObserver overrides. - void RenderProcessExited(content::RenderProcessHost* host, - base::TerminationStatus status, - int exit_code) override; - void RenderProcessHostDestroyed(content::RenderProcessHost* host) override; + // PowerManagerClient::Observer implementation + virtual void SuspendImminent() override; + virtual void SuspendDone(const base::TimeDelta& sleep_duration) override; private: - // Called whenever a new renderer process is created. - void OnRenderProcessCreated(content::RenderProcessHost* rph); + // Called when all asynchronous work is complete and renderers can be frozen. + void OnReadyToSuspend(const base::Closure& power_manager_callback); - // Tracks if the renderers are currently frozen. + // Used to ensure that renderers do not get frozen if the suspend is canceled. + base::CancelableClosure suspend_readiness_callback_; + bool frozen_; - // Delegate that takes care of actually freezing and thawing renderers for us. scoped_ptr<Delegate> delegate_; - // Set that keeps track of the RenderProcessHosts for processes that are - // hosting GCM extensions. - std::set<int> gcm_extension_processes_; - - // Manages notification registrations. - content::NotificationRegistrar registrar_; - base::WeakPtrFactory<RendererFreezer> weak_factory_; DISALLOW_COPY_AND_ASSIGN(RendererFreezer);
diff --git a/chrome/browser/chromeos/power/renderer_freezer_unittest.cc b/chrome/browser/chromeos/power/renderer_freezer_unittest.cc index 557768b6..ec809ca 100644 --- a/chrome/browser/chromeos/power/renderer_freezer_unittest.cc +++ b/chrome/browser/chromeos/power/renderer_freezer_unittest.cc
@@ -6,33 +6,10 @@ #include <string> -#include "base/command_line.h" -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" -#include "chrome/browser/chromeos/login/users/scoped_test_user_manager.h" -#include "chrome/browser/chromeos/settings/cros_settings.h" -#include "chrome/browser/chromeos/settings/device_settings_service.h" -#include "chrome/browser/extensions/extension_service.h" -#include "chrome/browser/extensions/test_extension_system.h" -#include "chrome/test/base/testing_browser_process.h" -#include "chrome/test/base/testing_profile.h" -#include "chrome/test/base/testing_profile_manager.h" #include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/fake_power_manager_client.h" -#include "content/public/browser/notification_service.h" -#include "content/public/browser/notification_source.h" -#include "content/public/browser/notification_types.h" -#include "content/public/browser/site_instance.h" -#include "content/public/test/mock_render_process_host.h" -#include "content/public/test/test_browser_thread_bundle.h" -#include "extensions/browser/notification_types.h" -#include "extensions/browser/process_manager.h" -#include "extensions/browser/process_map.h" -#include "extensions/common/extension_builder.h" -#include "extensions/common/manifest_handlers/background_info.h" -#include "extensions/common/value_builder.h" #include "testing/gtest/include/gtest/gtest-death-test.h" #include "testing/gtest/include/gtest/gtest.h" @@ -72,8 +49,6 @@ }; // Actions that can be returned by TestDelegate::GetActions(). -const char kSetShouldFreezeRenderer[] = "set_should_freeze_renderer"; -const char kSetShouldNotFreezeRenderer[] = "set_should_not_freeze_renderer"; const char kFreezeRenderers[] = "freeze_renderers"; const char kThawRenderers[] = "thaw_renderers"; const char kNoActions[] = ""; @@ -87,25 +62,20 @@ freeze_renderers_result_(true), thaw_renderers_result_(true) {} - ~TestDelegate() override {} + virtual ~TestDelegate() {} // RendererFreezer::Delegate overrides. - void SetShouldFreezeRenderer(base::ProcessHandle handle, - bool frozen) override { - AppendAction(frozen ? kSetShouldFreezeRenderer - : kSetShouldNotFreezeRenderer); - } - bool FreezeRenderers() override { + virtual bool FreezeRenderers() override { AppendAction(kFreezeRenderers); return freeze_renderers_result_; } - bool ThawRenderers() override { + virtual bool ThawRenderers() override { AppendAction(kThawRenderers); return thaw_renderers_result_; } - bool CanFreezeRenderers() override { return can_freeze_renderers_; } + virtual bool CanFreezeRenderers() override { return can_freeze_renderers_; } void set_freeze_renderers_result(bool result) { freeze_renderers_result_ = result; @@ -145,28 +115,25 @@ scoped_ptr<PowerManagerClient>(power_manager_client_)); } - ~RendererFreezerTest() override { + virtual ~RendererFreezerTest() { renderer_freezer_.reset(); DBusThreadManager::Shutdown(); } - protected: void Init() { renderer_freezer_.reset(new RendererFreezer( scoped_ptr<RendererFreezer::Delegate>(test_delegate_))); } - // Owned by DBusThreadManager. + protected: FakePowerManagerClient* power_manager_client_; - - // Owned by |renderer_freezer_|. TestDelegate* test_delegate_; + scoped_ptr<RendererFreezer> renderer_freezer_; private: - content::TestBrowserThreadBundle browser_thread_bundle_; - + base::MessageLoop message_loop_; DISALLOW_COPY_AND_ASSIGN(RendererFreezerTest); }; @@ -176,6 +143,16 @@ Init(); power_manager_client_->SendSuspendImminent(); + + // The RendererFreezer should have grabbed an asynchronous callback and done + // nothing else. + EXPECT_EQ(1, power_manager_client_->GetNumPendingSuspendReadinessCallbacks()); + EXPECT_EQ(kNoActions, test_delegate_->GetActions()); + + // The RendererFreezer should eventually freeze the renderers and run the + // callback. + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(0, power_manager_client_->GetNumPendingSuspendReadinessCallbacks()); EXPECT_EQ(kFreezeRenderers, test_delegate_->GetActions()); // The renderers should be thawed when we resume. @@ -183,14 +160,38 @@ EXPECT_EQ(kThawRenderers, test_delegate_->GetActions()); } +// Tests that the RendereFreezer doesn't freeze renderers if the suspend attempt +// was canceled before it had a chance to complete. +TEST_F(RendererFreezerTest, SuspendCanceled) { + Init(); + + // We shouldn't do anything yet. + power_manager_client_->SendSuspendImminent(); + EXPECT_EQ(kNoActions, test_delegate_->GetActions()); + + // If a suspend gets canceled for any reason, we should see a SuspendDone(). + power_manager_client_->SendSuspendDone(); + + // We shouldn't try to freeze the renderers now. + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(kNoActions, test_delegate_->GetActions()); +} + // Tests that the renderer freezer does nothing if the delegate cannot freeze // renderers. TEST_F(RendererFreezerTest, DelegateCannotFreezeRenderers) { test_delegate_->set_can_freeze_renderers(false); Init(); - // Nothing happens on suspend. power_manager_client_->SendSuspendImminent(); + + // The RendererFreezer should not have grabbed a callback or done anything + // else. + EXPECT_EQ(0, power_manager_client_->GetNumPendingSuspendReadinessCallbacks()); + EXPECT_EQ(kNoActions, test_delegate_->GetActions()); + + // There should be nothing in the message loop. + base::RunLoop().RunUntilIdle(); EXPECT_EQ(kNoActions, test_delegate_->GetActions()); // Nothing happens on resume. @@ -204,9 +205,13 @@ Init(); test_delegate_->set_freeze_renderers_result(false); - // The freezing operation will fail. power_manager_client_->SendSuspendImminent(); + EXPECT_EQ(1, power_manager_client_->GetNumPendingSuspendReadinessCallbacks()); + + // The freezing operation should fail, but we should still report readiness. + base::RunLoop().RunUntilIdle(); EXPECT_EQ(kFreezeRenderers, test_delegate_->GetActions()); + EXPECT_EQ(0, power_manager_client_->GetNumPendingSuspendReadinessCallbacks()); // Since the delegate reported that the freezing was unsuccessful, don't do // anything on resume. @@ -218,176 +223,15 @@ // Tests that the RendererFreezer crashes the browser if the freezing operation // was successful but the thawing operation failed. TEST_F(RendererFreezerTest, ErrorThawingRenderers) { - // The "threadsafe" style of death test re-executes the unit test binary, - // which in turn re-initializes some global state leading to failed CHECKs. - // Instead, we use the "fast" style here to prevent re-initialization. - ::testing::FLAGS_gtest_death_test_style = "fast"; Init(); test_delegate_->set_thaw_renderers_result(false); power_manager_client_->SendSuspendImminent(); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(kFreezeRenderers, test_delegate_->GetActions()); EXPECT_DEATH(power_manager_client_->SendSuspendDone(), "Unable to thaw"); } #endif // GTEST_HAS_DEATH_TEST -class RendererFreezerTestWithExtensions : public RendererFreezerTest { - public: - RendererFreezerTestWithExtensions() {} - ~RendererFreezerTestWithExtensions() override {} - - // testing::Test overrides. - void SetUp() override { - RendererFreezerTest::SetUp(); - - profile_manager_.reset( - new TestingProfileManager(TestingBrowserProcess::GetGlobal())); - - // Must be called from testing::Test::SetUp. - EXPECT_TRUE(profile_manager_->SetUp()); - - profile_ = profile_manager_->CreateTestingProfile("RendererFreezerTest"); - - extensions::TestExtensionSystem* extension_system = - static_cast<extensions::TestExtensionSystem*>( - extensions::ExtensionSystem::Get(profile_)); - extension_system->CreateExtensionService( - base::CommandLine::ForCurrentProcess(), - base::FilePath() /* install_directory */, - false /* autoupdate_enabled*/); - } - void TearDown() override { - extensions::ExtensionSystem::Get(profile_)->Shutdown(); - - profile_ = NULL; - - profile_manager_->DeleteAllTestingProfiles(); - - base::RunLoop().RunUntilIdle(); - - profile_manager_.reset(); - - RendererFreezerTest::TearDown(); - } - - protected: - void CreateRenderProcessForExtension(extensions::Extension* extension) { - scoped_ptr<content::MockRenderProcessHostFactory> rph_factory( - new content::MockRenderProcessHostFactory()); - scoped_refptr<content::SiteInstance> site_instance( - extensions::ProcessManager::Get(profile_)->GetSiteInstanceForURL( - extensions::BackgroundInfo::GetBackgroundURL(extension))); - scoped_ptr<content::RenderProcessHost> rph( - rph_factory->CreateRenderProcessHost(profile_, site_instance.get())); - - // Fake that the RenderProcessHost is hosting the gcm app. - extensions::ProcessMap::Get(profile_) - ->Insert(extension->id(), rph->GetID(), site_instance->GetId()); - - // Send the notification that the RenderProcessHost has been created. - content::NotificationService::current()->Notify( - content::NOTIFICATION_RENDERER_PROCESS_CREATED, - content::Source<content::RenderProcessHost>(rph.get()), - content::NotificationService::NoDetails()); - } - - // Owned by |profile_manager_|. - TestingProfile* profile_; - scoped_ptr<TestingProfileManager> profile_manager_; - - private: - // Chrome OS needs extra services to run in the following order. - chromeos::ScopedTestDeviceSettingsService test_device_settings_service_; - chromeos::ScopedTestCrosSettings test_cros_settings_; - chromeos::ScopedTestUserManager test_user_manager_; - - DISALLOW_COPY_AND_ASSIGN(RendererFreezerTestWithExtensions); -}; - -// Tests that the RendererFreezer freezes renderers that are not hosting -// GCM extensions. -TEST_F(RendererFreezerTestWithExtensions, FreezesNonExtensionRenderers) { - Init(); - - // Create the mock RenderProcessHost. - scoped_ptr<content::MockRenderProcessHostFactory> rph_factory( - new content::MockRenderProcessHostFactory()); - scoped_refptr<content::SiteInstance> site_instance( - content::SiteInstance::Create(profile_)); - scoped_ptr<content::RenderProcessHost> rph( - rph_factory->CreateRenderProcessHost(profile_, site_instance.get())); - - // Send the notification that the RenderProcessHost has been created. - content::NotificationService::current()->Notify( - content::NOTIFICATION_RENDERER_PROCESS_CREATED, - content::Source<content::RenderProcessHost>(rph.get()), - content::NotificationService::NoDetails()); - - EXPECT_EQ(kSetShouldFreezeRenderer, test_delegate_->GetActions()); -} - -// Tests that the RendererFreezer does not freeze renderers that are hosting -// extensions that use GCM. -TEST_F(RendererFreezerTestWithExtensions, DoesNotFreezeGcmExtensionRenderers) { - Init(); - - // First build the GCM extension. - scoped_refptr<extensions::Extension> gcm_app = - extensions::ExtensionBuilder() - .SetManifest(extensions::DictionaryBuilder() - .Set("name", "GCM App") - .Set("version", "1.0.0") - .Set("manifest_version", 2) - .Set("app", - extensions::DictionaryBuilder() - .Set("background", - extensions::DictionaryBuilder() - .Set("scripts", - extensions::ListBuilder() - .Append("background.js")))) - .Set("permissions", - extensions::ListBuilder() - .Append("gcm"))) - .Build(); - - // Now install it and give it a renderer. - extensions::ExtensionSystem::Get(profile_) - ->extension_service() - ->AddExtension(gcm_app.get()); - CreateRenderProcessForExtension(gcm_app.get()); - - EXPECT_EQ(kSetShouldNotFreezeRenderer, test_delegate_->GetActions()); -} - -// Tests that the RendererFreezer freezes renderers that are hosting extensions -// that do not use GCM. -TEST_F(RendererFreezerTestWithExtensions, FreezesNonGcmExtensionRenderers) { - Init(); - - // First build the extension. - scoped_refptr<extensions::Extension> background_app = - extensions::ExtensionBuilder() - .SetManifest(extensions::DictionaryBuilder() - .Set("name", "Background App") - .Set("version", "1.0.0") - .Set("manifest_version", 2) - .Set("app", - extensions::DictionaryBuilder() - .Set("background", - extensions::DictionaryBuilder() - .Set("scripts", - extensions::ListBuilder() - .Append("background.js"))))) - .Build(); - - // Now install it and give it a renderer. - extensions::ExtensionSystem::Get(profile_) - ->extension_service() - ->AddExtension(background_app.get()); - CreateRenderProcessForExtension(background_app.get()); - - EXPECT_EQ(kSetShouldFreezeRenderer, test_delegate_->GetActions()); -} - } // namespace chromeos
diff --git a/chrome/browser/chromeos/profiles/avatar_menu_chromeos.cc b/chrome/browser/chromeos/profiles/avatar_menu_chromeos.cc new file mode 100644 index 0000000..c7149332 --- /dev/null +++ b/chrome/browser/chromeos/profiles/avatar_menu_chromeos.cc
@@ -0,0 +1,26 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/profiles/avatar_menu.h" + +#include <string> + +#include "ash/frame/frame_util.h" + +#include "chrome/browser/browser_process.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/profiles/profile_manager.h" + +#include "ui/gfx/image/image.h" + +// static +void AvatarMenu::GetImageForMenuButton(const base::FilePath& profile_path, + gfx::Image* image, + bool* is_rectangle) { + // ChromeOS avatar icon is circular. + *is_rectangle = false; + Profile* profile = + g_browser_process->profile_manager()->GetProfileByPath(profile_path); + *image = ash::GetAvatarImageForContext(profile); +}
diff --git a/chrome/browser/chromeos/settings/OWNERS b/chrome/browser/chromeos/settings/OWNERS index cd1c574..3b9684d 100644 --- a/chrome/browser/chromeos/settings/OWNERS +++ b/chrome/browser/chromeos/settings/OWNERS
@@ -1,2 +1,2 @@ mnissler@chromium.org -pastarmovj@chromium.org +ygorshenin@chromium.org
diff --git a/chrome/browser/chromeos/system/input_device_settings_impl_ozone.cc b/chrome/browser/chromeos/system/input_device_settings_impl_ozone.cc index 534435c6..60791f94 100644 --- a/chrome/browser/chromeos/system/input_device_settings_impl_ozone.cc +++ b/chrome/browser/chromeos/system/input_device_settings_impl_ozone.cc
@@ -4,6 +4,10 @@ #include "chrome/browser/chromeos/system/input_device_settings.h" +#include "content/public/browser/browser_thread.h" +#include "ui/ozone/public/input_controller.h" +#include "ui/ozone/public/ozone_platform.h" + namespace chromeos { namespace system { @@ -36,6 +40,10 @@ void ReapplyTouchpadSettings() override; void ReapplyMouseSettings() override; + // Cached InputController pointer. It should be fixed throughout the browser + // session. + ui::InputController* input_controller_; + // Respective device setting objects. TouchpadSettings current_touchpad_settings_; MouseSettings current_mouse_settings_; @@ -43,12 +51,17 @@ DISALLOW_COPY_AND_ASSIGN(InputDeviceSettingsImplOzone); }; -InputDeviceSettingsImplOzone::InputDeviceSettingsImplOzone() { +InputDeviceSettingsImplOzone::InputDeviceSettingsImplOzone() + : input_controller_( + ui::OzonePlatform::GetInstance()->GetInputController()) { + // Make sure the input controller does exist. + DCHECK(ui::OzonePlatform::GetInstance()->GetInputController()); } void InputDeviceSettingsImplOzone::TouchpadExists( const DeviceExistsCallback& callback) { - NOTIMPLEMENTED(); + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + callback.Run(input_controller_->HasTouchpad()); } void InputDeviceSettingsImplOzone::UpdateTouchpadSettings( @@ -60,28 +73,34 @@ void InputDeviceSettingsImplOzone::SetTouchpadSensitivity(int value) { DCHECK(value >= kMinPointerSensitivity && value <= kMaxPointerSensitivity); current_touchpad_settings_.SetSensitivity(value); + input_controller_->SetTouchpadSensitivity(value); } void InputDeviceSettingsImplOzone::SetNaturalScroll(bool enabled) { current_touchpad_settings_.SetNaturalScroll(enabled); + input_controller_->SetNaturalScroll(enabled); } void InputDeviceSettingsImplOzone::SetTapToClick(bool enabled) { current_touchpad_settings_.SetTapToClick(enabled); + input_controller_->SetTapToClick(enabled); } void InputDeviceSettingsImplOzone::SetThreeFingerClick(bool enabled) { // For Alex/ZGB. current_touchpad_settings_.SetThreeFingerClick(enabled); + input_controller_->SetThreeFingerClick(enabled); } void InputDeviceSettingsImplOzone::SetTapDragging(bool enabled) { current_touchpad_settings_.SetTapDragging(enabled); + input_controller_->SetTapDragging(enabled); } void InputDeviceSettingsImplOzone::MouseExists( const DeviceExistsCallback& callback) { - NOTIMPLEMENTED(); + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + callback.Run(input_controller_->HasMouse()); } void InputDeviceSettingsImplOzone::UpdateMouseSettings( @@ -93,10 +112,12 @@ void InputDeviceSettingsImplOzone::SetMouseSensitivity(int value) { DCHECK(value >= kMinPointerSensitivity && value <= kMaxPointerSensitivity); current_mouse_settings_.SetSensitivity(value); + input_controller_->SetMouseSensitivity(value); } void InputDeviceSettingsImplOzone::SetPrimaryButtonRight(bool right) { current_mouse_settings_.SetPrimaryButtonRight(right); + input_controller_->SetPrimaryButtonRight(right); } void InputDeviceSettingsImplOzone::ReapplyTouchpadSettings() {
diff --git a/chrome/browser/chromeos/timezone/timezone_unittest.cc b/chrome/browser/chromeos/timezone/timezone_unittest.cc index fcb3e63..5dcd30e 100644 --- a/chrome/browser/chromeos/timezone/timezone_unittest.cc +++ b/chrome/browser/chromeos/timezone/timezone_unittest.cc
@@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "chrome/browser/chromeos/geolocation/geoposition.h" #include "chrome/browser/chromeos/timezone/timezone_provider.h" -#include "content/public/test/test_browser_thread_bundle.h" #include "net/http/http_response_headers.h" #include "net/http/http_status_code.h" #include "net/url_request/test_url_fetcher_factory.h" @@ -195,7 +195,7 @@ class TimeZoneTest : public testing::Test { private: - content::TestBrowserThreadBundle thread_bundle_; + base::MessageLoop message_loop_; }; TEST_F(TimeZoneTest, ResponseOK) {
diff --git a/chrome/browser/component_updater/recovery_component_installer.cc b/chrome/browser/component_updater/recovery_component_installer.cc index 897230ea..9aadd24 100644 --- a/chrome/browser/component_updater/recovery_component_installer.cc +++ b/chrome/browser/component_updater/recovery_component_installer.cc
@@ -179,4 +179,12 @@ registry->RegisterStringPref(prefs::kRecoveryComponentVersion, "0.0.0.0"); } +void AcceptedElevatedRecoveryInstall(PrefService* prefs) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); +} + +void DeclinedElevatedRecoveryInstall(PrefService* prefs) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); +} + } // namespace component_updater
diff --git a/chrome/browser/component_updater/recovery_component_installer.h b/chrome/browser/component_updater/recovery_component_installer.h index 260083d..b0dfacd 100644 --- a/chrome/browser/component_updater/recovery_component_installer.h +++ b/chrome/browser/component_updater/recovery_component_installer.h
@@ -5,6 +5,8 @@ #ifndef CHROME_BROWSER_COMPONENT_UPDATER_RECOVERY_COMPONENT_INSTALLER_H_ #define CHROME_BROWSER_COMPONENT_UPDATER_RECOVERY_COMPONENT_INSTALLER_H_ +#include "base/callback_forward.h" + class PrefRegistrySimple; class PrefService; @@ -17,9 +19,21 @@ // update installation. This is a last resort safety mechanism. void RegisterRecoveryComponent(ComponentUpdateService* cus, PrefService* prefs); -// Register user preferences related to the recovery component. +// Registers user preferences related to the recovery component. void RegisterPrefsForRecoveryComponent(PrefRegistrySimple* registry); +// Notifies recovery component that agreed elevated install, so that it +// can launches an elevated install process. After that, clears +// preference flag prefs::kRecoveryComponentNeedsElevation. +// Note: the function is yet to be implemented. +void AcceptedElevatedRecoveryInstall(PrefService* prefs); + +// Notifies recovery component that elevated install is declined, so that it can +// removes the setup files. After that, clears preference flag +// prefs::kRecoveryComponentNeedsElevation. +// Note: the function is yet to be implemented. +void DeclinedElevatedRecoveryInstall(PrefService* prefs); + } // namespace component_updater #endif // CHROME_BROWSER_COMPONENT_UPDATER_RECOVERY_COMPONENT_INSTALLER_H_
diff --git a/chrome/browser/devtools/device/android_device_manager.cc b/chrome/browser/devtools/device/android_device_manager.cc index 458bb9d..6edd022 100644 --- a/chrome/browser/devtools/device/android_device_manager.cc +++ b/chrome/browser/devtools/device/android_device_manager.cc
@@ -211,7 +211,7 @@ typedef AndroidDeviceManager::DeviceProvider DeviceProvider; typedef AndroidDeviceManager::DeviceProviders DeviceProviders; typedef AndroidDeviceManager::DeviceDescriptors DeviceDescriptors; - typedef base::Callback<void(DeviceDescriptors*)> + typedef base::Callback<void(scoped_ptr<DeviceDescriptors>)> DescriptorsCallback; static void Start(scoped_refptr<base::MessageLoopProxy> device_message_loop, @@ -243,7 +243,7 @@ friend class base::RefCountedThreadSafe<DevicesRequest>; ~DevicesRequest() { response_message_loop_->PostTask(FROM_HERE, - base::Bind(callback_, descriptors_.release())); + base::Bind(callback_, base::Passed(&descriptors_))); } typedef std::vector<std::string> Serials; @@ -450,8 +450,8 @@ } // static -scoped_refptr<AndroidDeviceManager> AndroidDeviceManager::Create() { - return new AndroidDeviceManager(); +scoped_ptr<AndroidDeviceManager> AndroidDeviceManager::Create() { + return make_scoped_ptr(new AndroidDeviceManager()); } void AndroidDeviceManager::SetDeviceProviders( @@ -470,12 +470,13 @@ DevicesRequest::Start(handler_thread_->message_loop(), providers_, base::Bind(&AndroidDeviceManager::UpdateDevices, - this, + weak_factory_.GetWeakPtr(), callback)); } AndroidDeviceManager::AndroidDeviceManager() - : handler_thread_(HandlerThread::GetInstance()) { + : handler_thread_(HandlerThread::GetInstance()), + weak_factory_(this) { } AndroidDeviceManager::~AndroidDeviceManager() { @@ -484,8 +485,7 @@ void AndroidDeviceManager::UpdateDevices( const DevicesCallback& callback, - DeviceDescriptors* descriptors_raw) { - scoped_ptr<DeviceDescriptors> descriptors(descriptors_raw); + scoped_ptr<DeviceDescriptors> descriptors) { Devices response; DeviceWeakMap new_devices; for (DeviceDescriptors::const_iterator it = descriptors->begin();
diff --git a/chrome/browser/devtools/device/android_device_manager.h b/chrome/browser/devtools/device/android_device_manager.h index ec65e03..1ea8bd6 100644 --- a/chrome/browser/devtools/device/android_device_manager.h +++ b/chrome/browser/devtools/device/android_device_manager.h
@@ -8,6 +8,7 @@ #include <vector> #include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" #include "base/threading/non_thread_safe.h" #include "chrome/browser/profiles/profile.h" #include "content/public/browser/browser_thread.h" @@ -17,11 +18,7 @@ class StreamSocket; } -class AndroidDeviceManager - : public base::RefCountedThreadSafe< - AndroidDeviceManager, - content::BrowserThread::DeleteOnUIThread>, - public base::NonThreadSafe { +class AndroidDeviceManager : public base::NonThreadSafe { public: typedef base::Callback<void(int, const std::string&)> CommandCallback; typedef base::Callback<void(int result, scoped_ptr<net::StreamSocket>)> @@ -175,7 +172,9 @@ typedef std::vector<scoped_refptr<DeviceProvider> > DeviceProviders; - static scoped_refptr<AndroidDeviceManager> Create(); + virtual ~AndroidDeviceManager(); + + static scoped_ptr<AndroidDeviceManager> Create(); void SetDeviceProviders(const DeviceProviders& providers); @@ -207,20 +206,18 @@ base::Thread* thread_; }; - friend struct content::BrowserThread::DeleteOnThread< - content::BrowserThread::UI>; - friend class base::DeleteHelper<AndroidDeviceManager>; AndroidDeviceManager(); - virtual ~AndroidDeviceManager(); void UpdateDevices(const DevicesCallback& callback, - DeviceDescriptors* descriptors); + scoped_ptr<DeviceDescriptors> descriptors); typedef std::map<std::string, base::WeakPtr<Device> > DeviceWeakMap; scoped_refptr<HandlerThread> handler_thread_; DeviceProviders providers_; DeviceWeakMap devices_; + + base::WeakPtrFactory<AndroidDeviceManager> weak_factory_; }; #endif // CHROME_BROWSER_DEVTOOLS_DEVICE_ANDROID_DEVICE_MANAGER_H_
diff --git a/chrome/browser/devtools/device/devtools_android_bridge.h b/chrome/browser/devtools/device/devtools_android_bridge.h index a64dc1f..c351998 100644 --- a/chrome/browser/devtools/device/devtools_android_bridge.h +++ b/chrome/browser/devtools/device/devtools_android_bridge.h
@@ -291,7 +291,7 @@ const std::string& response); Profile* profile_; - scoped_refptr<AndroidDeviceManager> device_manager_; + const scoped_ptr<AndroidDeviceManager> device_manager_; typedef std::map<std::string, scoped_refptr<AndroidDeviceManager::Device>> DeviceMap;
diff --git a/chrome/browser/devtools/device/port_forwarding_controller.cc b/chrome/browser/devtools/device/port_forwarding_controller.cc index eb82daa..0a85f0b 100644 --- a/chrome/browser/devtools/device/port_forwarding_controller.cc +++ b/chrome/browser/devtools/device/port_forwarding_controller.cc
@@ -12,6 +12,7 @@ #include "base/memory/singleton.h" #include "base/message_loop/message_loop.h" #include "base/prefs/pref_service.h" +#include "base/profiler/scoped_tracker.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" @@ -90,6 +91,10 @@ } void OnResolved(int result) { + // TODO(vadimt): Remove ScopedTracker below once crbug.com/436634 is fixed. + tracked_objects::ScopedTracker tracking_profile( + FROM_HERE_WITH_EXPLICIT_FUNCTION("436634 SocketTunnel::OnResolved")); + if (result < 0) { SelfDestruct(); return;
diff --git a/chrome/browser/download/OWNERS b/chrome/browser/download/OWNERS index 93ed63f..1d06927 100644 --- a/chrome/browser/download/OWNERS +++ b/chrome/browser/download/OWNERS
@@ -7,4 +7,4 @@ per-file *_file_picker_chromeos.*=achuith@chromium.org per-file download_dir_policy_handler*=dconnelly@chromium.org -per-file download_dir_policy_handler*=joaodasilva@chromium.org +per-file download_dir_policy_handler*=mnissler@chromium.org
diff --git a/chrome/browser/errorpage_browsertest.cc b/chrome/browser/errorpage_browsertest.cc index dcab17dd..e2f66df 100644 --- a/chrome/browser/errorpage_browsertest.cc +++ b/chrome/browser/errorpage_browsertest.cc
@@ -932,6 +932,28 @@ EXPECT_EQ(kRequestsToFail + 1, interceptor()->requests()); } +IN_PROC_BROWSER_TEST_F(ErrorPageAutoReloadTest, ManualReloadNotSuppressed) { + GURL test_url("http://error.page.auto.reload"); + const int kRequestsToFail = 3; + InstallInterceptor(test_url, kRequestsToFail); + ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( + browser(), test_url, 2); + + EXPECT_EQ(2, interceptor()->failures()); + EXPECT_EQ(2, interceptor()->requests()); + + ToggleHelpBox(browser()); + EXPECT_TRUE(IsDisplayingNetError(browser(), net::ERR_CONNECTION_RESET)); + + content::WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + content::TestNavigationObserver nav_observer(web_contents, 1); + web_contents->GetMainFrame()->ExecuteJavaScript( + base::ASCIIToUTF16("document.getElementById('reload-button').click();")); + nav_observer.Wait(); + EXPECT_FALSE(IsDisplayingNetError(browser(), net::ERR_CONNECTION_RESET)); +} + // Interceptor that fails all requests with net::ERR_ADDRESS_UNREACHABLE. class AddressUnreachableInterceptor : public net::URLRequestInterceptor { public:
diff --git a/chrome/browser/extensions/api/declarative/declarative_apitest.cc b/chrome/browser/extensions/api/declarative/declarative_apitest.cc index 4de8d34..a6f51a7 100644 --- a/chrome/browser/extensions/api/declarative/declarative_apitest.cc +++ b/chrome/browser/extensions/api/declarative/declarative_apitest.cc
@@ -114,7 +114,7 @@ extensions::RulesRegistryService::Get(browser()->profile()); scoped_refptr<RulesRegistry> rules_registry = rules_registry_service->GetRulesRegistry( - RulesRegistry::WebViewKey(0, 0), + RulesRegistryService::kDefaultRulesRegistryID, extensions::declarative_webrequest_constants::kOnRequest); std::vector<linked_ptr<RulesRegistry::Rule> > rules; BrowserThread::PostTask(
diff --git a/chrome/browser/extensions/api/declarative/rules_registry_service_unittest.cc b/chrome/browser/extensions/api/declarative/rules_registry_service_unittest.cc index d35dab4a..15d3005 100644 --- a/chrome/browser/extensions/api/declarative/rules_registry_service_unittest.cc +++ b/chrome/browser/extensions/api/declarative/rules_registry_service_unittest.cc
@@ -55,7 +55,9 @@ }; TEST_F(RulesRegistryServiceTest, TestConstructionAndMultiThreading) { - const RulesRegistry::WebViewKey key(0, 0); + RulesRegistryService registry_service(NULL); + + int key = RulesRegistryService::kDefaultRulesRegistryID; TestRulesRegistry* ui_registry = new TestRulesRegistry(content::BrowserThread::UI, "ui", key); @@ -64,7 +66,6 @@ // Test registration. - RulesRegistryService registry_service(NULL); registry_service.RegisterRulesRegistry(make_scoped_refptr(ui_registry)); registry_service.RegisterRulesRegistry(make_scoped_refptr(io_registry)); @@ -78,19 +79,19 @@ "ui_task")); content::BrowserThread::PostTask( - content::BrowserThread::IO, FROM_HERE, - base::Bind(&InsertRule, registry_service.GetRulesRegistry(key, "io"), - "io_task")); + content::BrowserThread::IO, FROM_HERE, + base::Bind(&InsertRule, registry_service.GetRulesRegistry(key, "io"), + "io_task")); content::BrowserThread::PostTask( - content::BrowserThread::UI, FROM_HERE, - base::Bind(&VerifyNumberOfRules, - registry_service.GetRulesRegistry(key, "ui"), 1)); + content::BrowserThread::UI, FROM_HERE, + base::Bind(&VerifyNumberOfRules, + registry_service.GetRulesRegistry(key, "ui"), 1)); content::BrowserThread::PostTask( - content::BrowserThread::IO, FROM_HERE, - base::Bind(&VerifyNumberOfRules, - registry_service.GetRulesRegistry(key, "io"), 1)); + content::BrowserThread::IO, FROM_HERE, + base::Bind(&VerifyNumberOfRules, + registry_service.GetRulesRegistry(key, "io"), 1)); message_loop_.RunUntilIdle(); @@ -99,66 +100,16 @@ registry_service.SimulateExtensionUninstalled(kExtensionId); content::BrowserThread::PostTask( - content::BrowserThread::UI, FROM_HERE, - base::Bind(&VerifyNumberOfRules, - registry_service.GetRulesRegistry(key, "ui"), 0)); + content::BrowserThread::UI, FROM_HERE, + base::Bind(&VerifyNumberOfRules, + registry_service.GetRulesRegistry(key, "ui"), 0)); content::BrowserThread::PostTask( - content::BrowserThread::IO, FROM_HERE, - base::Bind(&VerifyNumberOfRules, - registry_service.GetRulesRegistry(key, "io"), 0)); + content::BrowserThread::IO, FROM_HERE, + base::Bind(&VerifyNumberOfRules, + registry_service.GetRulesRegistry(key, "io"), 0)); message_loop_.RunUntilIdle(); } -// This test verifies that removing rules registries by process ID works as -// intended. This test ensures that removing registries associated with one -// Webview embedder process does not remove registries associated with the -// other. -TEST_F(RulesRegistryServiceTest, TestWebViewKey) { - const int kEmbedderProcessID1 = 1; - const int kEmbedderProcessID2 = 2; - const int kWebViewInstanceID = 1; - - const RulesRegistry::WebViewKey key1(kEmbedderProcessID1, kWebViewInstanceID); - const RulesRegistry::WebViewKey key2(kEmbedderProcessID2, kWebViewInstanceID); - - TestRulesRegistry* ui_registry_key1 = - new TestRulesRegistry(content::BrowserThread::UI, "ui", key1); - TestRulesRegistry* ui_registry_key2 = - new TestRulesRegistry(content::BrowserThread::UI, "ui", key2); - - RulesRegistryService registry_service(NULL); - registry_service.RegisterRulesRegistry(make_scoped_refptr(ui_registry_key1)); - registry_service.RegisterRulesRegistry(make_scoped_refptr(ui_registry_key2)); - - content::BrowserThread::PostTask( - content::BrowserThread::UI, FROM_HERE, - base::Bind(&InsertRule, registry_service.GetRulesRegistry(key1, "ui"), - "ui_task")); - content::BrowserThread::PostTask( - content::BrowserThread::UI, FROM_HERE, - base::Bind(&InsertRule, registry_service.GetRulesRegistry(key2, "ui"), - "ui_task")); - message_loop_.RunUntilIdle(); - - registry_service.RemoveWebViewRulesRegistries(kEmbedderProcessID1); - EXPECT_FALSE(registry_service.GetRulesRegistry(key1, "ui").get()); - EXPECT_TRUE(registry_service.GetRulesRegistry(key2, "ui").get()); -} - -TEST_F(RulesRegistryServiceTest, TestWebViewWebRequestRegistryHasNoCache) { - const int kEmbedderProcessID = 1; - const int kWebViewInstanceID = 1; - const RulesRegistry::WebViewKey key(kEmbedderProcessID, kWebViewInstanceID); - TestingProfile profile; - RulesRegistryService registry_service(&profile); - RulesRegistry* registry = - registry_service.GetRulesRegistry( - key, - declarative_webrequest_constants::kOnRequest).get(); - EXPECT_TRUE(registry); - EXPECT_FALSE(registry->rules_cache_delegate_for_testing()); -} - } // namespace extensions
diff --git a/chrome/browser/extensions/api/declarative/rules_registry_with_cache_unittest.cc b/chrome/browser/extensions/api/declarative/rules_registry_with_cache_unittest.cc index 53744d7..e0cb6cc 100644 --- a/chrome/browser/extensions/api/declarative/rules_registry_with_cache_unittest.cc +++ b/chrome/browser/extensions/api/declarative/rules_registry_with_cache_unittest.cc
@@ -18,6 +18,7 @@ #include "chrome/test/base/testing_profile.h" #include "content/public/test/test_browser_thread_bundle.h" #include "extensions/browser/api/declarative/rules_cache_delegate.h" +#include "extensions/browser/api/declarative/rules_registry_service.h" #include "extensions/browser/api/declarative/test_rules_registry.h" #include "extensions/browser/extension_prefs.h" #include "extensions/browser/extension_registry.h" @@ -35,6 +36,7 @@ } namespace extensions { +const int kRulesRegistryID = RulesRegistryService::kDefaultRulesRegistryID; class RulesRegistryWithCacheTest : public testing::Test { public: @@ -44,7 +46,7 @@ /*event_name=*/"", content::BrowserThread::UI, &cache_delegate_, - RulesRegistry::WebViewKey(0, 0))) {} + kRulesRegistryID)) {} void SetUp() override { env_.GetExtensionPrefs(); // Force creation before adding extensions. @@ -233,10 +235,9 @@ RulesCacheDelegate::GetRulesStoredKey( event_name, profile()->IsOffTheRecord())); scoped_ptr<RulesCacheDelegate> cache_delegate(new RulesCacheDelegate(false)); - scoped_refptr<RulesRegistry> registry(new TestRulesRegistry( - profile(), event_name, content::BrowserThread::UI, - cache_delegate.get(), - RulesRegistry::WebViewKey(0, 0))); + scoped_refptr<RulesRegistry> registry( + new TestRulesRegistry(profile(), event_name, content::BrowserThread::UI, + cache_delegate.get(), kRulesRegistryID)); // 1. Test the handling of preferences. // Default value is always true. @@ -303,16 +304,14 @@ RulesCacheDelegate::GetRulesStoredKey( event_name2, profile()->IsOffTheRecord())); scoped_ptr<RulesCacheDelegate> cache_delegate1(new RulesCacheDelegate(false)); - scoped_refptr<RulesRegistry> registry1(new TestRulesRegistry( - profile(), event_name1, content::BrowserThread::UI, - cache_delegate1.get(), - RulesRegistry::WebViewKey(0, 0))); + scoped_refptr<RulesRegistry> registry1( + new TestRulesRegistry(profile(), event_name1, content::BrowserThread::UI, + cache_delegate1.get(), kRulesRegistryID)); scoped_ptr<RulesCacheDelegate> cache_delegate2(new RulesCacheDelegate(false)); - scoped_refptr<RulesRegistry> registry2(new TestRulesRegistry( - profile(), event_name2, content::BrowserThread::UI, - cache_delegate2.get(), - RulesRegistry::WebViewKey(0, 0))); + scoped_refptr<RulesRegistry> registry2( + new TestRulesRegistry(profile(), event_name2, content::BrowserThread::UI, + cache_delegate2.get(), kRulesRegistryID)); // Checkt the correct default values. EXPECT_TRUE(cache_delegate1->GetDeclarativeRulesStored(extension1_->id())); @@ -355,12 +354,9 @@ // 2. First run, adding a rule for the extension. scoped_ptr<RulesCacheDelegate> cache_delegate(new RulesCacheDelegate(false)); - scoped_refptr<TestRulesRegistry> registry(new TestRulesRegistry( - profile(), - "testEvent", - content::BrowserThread::UI, - cache_delegate.get(), - RulesRegistry::WebViewKey(0, 0))); + scoped_refptr<TestRulesRegistry> registry( + new TestRulesRegistry(profile(), "testEvent", content::BrowserThread::UI, + cache_delegate.get(), kRulesRegistryID)); AddRule(extension1_->id(), kRuleId, registry.get()); base::RunLoop().RunUntilIdle(); // Posted tasks store the added rule. @@ -368,12 +364,9 @@ // 3. Restart the TestRulesRegistry and see the rule still there. cache_delegate.reset(new RulesCacheDelegate(false)); - registry = new TestRulesRegistry( - profile(), - "testEvent", - content::BrowserThread::UI, - cache_delegate.get(), - RulesRegistry::WebViewKey(0, 0)); + registry = + new TestRulesRegistry(profile(), "testEvent", content::BrowserThread::UI, + cache_delegate.get(), kRulesRegistryID); base::RunLoop().RunUntilIdle(); // Posted tasks retrieve the stored rule. EXPECT_EQ(1, GetNumberOfRules(extension1_->id(), registry.get()));
diff --git a/chrome/browser/extensions/api/declarative_content/chrome_content_rules_registry.cc b/chrome/browser/extensions/api/declarative_content/chrome_content_rules_registry.cc index e764669..aca2cd6 100644 --- a/chrome/browser/extensions/api/declarative_content/chrome_content_rules_registry.cc +++ b/chrome/browser/extensions/api/declarative_content/chrome_content_rules_registry.cc
@@ -14,6 +14,7 @@ #include "content/public/browser/notification_source.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/web_contents.h" +#include "extensions/browser/api/declarative/rules_registry_service.h" #include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_system.h" #include "extensions/common/extension_messages.h" @@ -29,7 +30,7 @@ declarative_content_constants::kOnPageChanged, content::BrowserThread::UI, cache_delegate, - WebViewKey(0, 0)) { + RulesRegistryService::kDefaultRulesRegistryID) { extension_info_map_ = ExtensionSystem::Get(browser_context)->info_map(); registrar_.Add(this, @@ -166,13 +167,9 @@ DCHECK(content_rules_.find(rule_id) == content_rules_.end()); scoped_ptr<ContentRule> content_rule( - ContentRule::Create(url_matcher_.condition_factory(), - browser_context(), - extension, - extension_installation_time, - *rule, - ContentRule::ConsistencyChecker(), - &error)); + ContentRule::Create(url_matcher_.condition_factory(), browser_context(), + extension, extension_installation_time, *rule, + ContentRule::ConsistencyChecker(), &error)); if (!error.empty()) { // Clean up temporary condition sets created during rule creation. url_matcher_.ClearUnusedConditionSets();
diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc index b49807d..4474755 100644 --- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc +++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc
@@ -18,6 +18,7 @@ #include "chrome/common/extensions/extension_test_util.h" #include "components/url_matcher/url_matcher_constants.h" #include "content/public/test/test_browser_thread.h" +#include "extensions/browser/api/declarative/rules_registry_service.h" #include "extensions/browser/api/declarative_webrequest/webrequest_constants.h" #include "extensions/browser/api/web_request/web_request_api_helpers.h" #include "net/base/request_priority.h" @@ -50,11 +51,10 @@ class TestWebRequestRulesRegistry : public WebRequestRulesRegistry { public: - TestWebRequestRulesRegistry( - scoped_refptr<InfoMap> extension_info_map) + TestWebRequestRulesRegistry(scoped_refptr<InfoMap> extension_info_map) : WebRequestRulesRegistry(NULL /*profile*/, NULL /* cache_delegate */, - WebViewKey(0, 0)), + RulesRegistryService::kDefaultRulesRegistryID), num_clear_cache_calls_(0) { SetExtensionInfoMapForTesting(extension_info_map); }
diff --git a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc index aa24dae..ca228e6 100644 --- a/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc +++ b/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api.cc
@@ -166,6 +166,7 @@ l10n_util::GetStringFUTF16( IDS_EASY_UNLOCK_PAIRING_CHANGED_NOTIFICATION_MESSAGE, device_type)); + // TODO(isherman): Remove this string. strings->SetString( "phoneChangedNotificationUpdateButton", l10n_util::GetStringUTF16( @@ -244,9 +245,10 @@ "setupAndroidSmartLockHeaderTitle", l10n_util::GetStringUTF16( IDS_EASY_UNLOCK_SETUP_ANDROID_SMART_LOCK_HEADER_TITLE)); - strings->SetString("setupAndroidSmartLockHeaderText", - l10n_util::GetStringUTF16( - IDS_EASY_UNLOCK_SETUP_ANDROID_SMART_LOCK_HEADER_TEXT)); + strings->SetString( + "setupAndroidSmartLockHeaderText", + l10n_util::GetStringFUTF16( + IDS_EASY_UNLOCK_SETUP_ANDROID_SMART_LOCK_HEADER_TEXT, device_type)); strings->SetString( "setupAndroidSmartLockDoneButtonText", l10n_util::GetStringUTF16(
diff --git a/chrome/browser/extensions/api/enterprise_platform_keys_private/OWNERS b/chrome/browser/extensions/api/enterprise_platform_keys_private/OWNERS index 8f05b0f8..d7df737 100644 --- a/chrome/browser/extensions/api/enterprise_platform_keys_private/OWNERS +++ b/chrome/browser/extensions/api/enterprise_platform_keys_private/OWNERS
@@ -1,4 +1,3 @@ dkrahn@chromium.org mnissler@chromium.org -pastarmovj@chromium.org bartfab@chromium.org
diff --git a/chrome/browser/extensions/api/hotword_private/hotword_private_api.cc b/chrome/browser/extensions/api/hotword_private/hotword_private_api.cc index bd5ba2a..2c0a930 100644 --- a/chrome/browser/extensions/api/hotword_private/hotword_private_api.cc +++ b/chrome/browser/extensions/api/hotword_private/hotword_private_api.cc
@@ -4,6 +4,8 @@ #include "chrome/browser/extensions/api/hotword_private/hotword_private_api.h" +#include <string> + #include "base/i18n/rtl.h" #include "base/lazy_instance.h" #include "base/prefs/pref_service.h" @@ -145,12 +147,14 @@ result.available = false; result.enabled = false; result.always_on_enabled = false; + result.user_is_active = false; } else { result.available = hotword_service->IsServiceAvailable(); result.enabled = hotword_service->IsSometimesOnEnabled(); result.audio_logging_enabled = hotword_service->IsOptedIntoAudioLogging(); result.training_enabled = hotword_service->IsTraining(); result.always_on_enabled = hotword_service->IsAlwaysOnEnabled(); + result.user_is_active = hotword_service->UserIsActive(); } PrefService* prefs = GetProfile()->GetPrefs();
diff --git a/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc b/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc index a375d5f..8817775 100644 --- a/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc +++ b/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc
@@ -242,9 +242,9 @@ // returned. extensions::LaunchContainer launch_container = GetLaunchContainer(extensions::ExtensionPrefs::Get(context), extension); - OpenApplication(AppLaunchParams(Profile::FromBrowserContext(context), - extension, launch_container, - NEW_FOREGROUND_TAB)); + OpenApplication(AppLaunchParams( + Profile::FromBrowserContext(context), extension, launch_container, + NEW_FOREGROUND_TAB, extensions::SOURCE_MANAGEMENT_API)); extensions::RecordAppLaunchType(extension_misc::APP_LAUNCH_EXTENSION_API, extension->GetType());
diff --git a/chrome/browser/extensions/api/media_galleries/media_galleries_apitest.cc b/chrome/browser/extensions/api/media_galleries/media_galleries_apitest.cc index e338991c..b531f2bf 100644 --- a/chrome/browser/extensions/api/media_galleries/media_galleries_apitest.cc +++ b/chrome/browser/extensions/api/media_galleries/media_galleries_apitest.cc
@@ -21,12 +21,15 @@ #include "chrome/browser/media_galleries/media_galleries_scan_result_controller.h" #include "chrome/browser/media_galleries/media_galleries_test_util.h" #include "chrome/browser/media_galleries/media_scan_manager.h" +#include "chrome/browser/ui/extensions/app_launch_params.h" +#include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/common/chrome_paths.h" #include "components/storage_monitor/storage_info.h" #include "components/storage_monitor/storage_monitor.h" #include "content/public/browser/web_contents.h" #include "content/public/test/test_utils.h" #include "extensions/browser/extension_system.h" +#include "extensions/common/constants.h" #include "extensions/common/extension.h" #include "extensions/test/result_catcher.h" #include "media/base/test_data_util.h" @@ -470,10 +473,9 @@ ASSERT_TRUE(extension); extensions::ResultCatcher catcher; - AppLaunchParams params(browser()->profile(), - extension, - extensions::LAUNCH_CONTAINER_NONE, - NEW_WINDOW); + AppLaunchParams params(browser()->profile(), extension, + extensions::LAUNCH_CONTAINER_NONE, NEW_WINDOW, + extensions::SOURCE_UNTRACKED); params.command_line = *CommandLine::ForCurrentProcess(); OpenApplication(params);
diff --git a/chrome/browser/extensions/api/messaging/incognito_connectability.cc b/chrome/browser/extensions/api/messaging/incognito_connectability.cc index b6842c3..177ba48 100644 --- a/chrome/browser/extensions/api/messaging/incognito_connectability.cc +++ b/chrome/browser/extensions/api/messaging/incognito_connectability.cc
@@ -17,6 +17,9 @@ #include "extensions/common/extension.h" #include "ui/base/l10n/l10n_util.h" +using infobars::InfoBar; +using infobars::InfoBarManager; + namespace extensions { namespace { @@ -32,14 +35,18 @@ // Creates a confirmation infobar and delegate and adds the infobar to // |infobar_service|. - static void Create(InfoBarService* infobar_service, - const base::string16& message, - const InfoBarCallback& callback) { - infobar_service->AddInfoBar(ConfirmInfoBarDelegate::CreateInfoBar( + static InfoBar* Create(InfoBarManager* infobar_manager, + const base::string16& message, + const InfoBarCallback& callback) { + return infobar_manager->AddInfoBar(ConfirmInfoBarDelegate::CreateInfoBar( scoped_ptr<ConfirmInfoBarDelegate>( new IncognitoConnectabilityInfoBarDelegate(message, callback)))); } + // Set the infobar answered so that the callback is not executed when the + // delegate is destroyed. + void SetAnswered() { answered_ = true; } + private: IncognitoConnectabilityInfoBarDelegate(const base::string16& message, const InfoBarCallback& callback) @@ -136,17 +143,19 @@ return; } - ExtensionOriginPair extension_origin_pair = - ExtensionOriginPair(extension->id(), origin); - if (ContainsKey(pending_origins_, extension_origin_pair)) { - // We are already asking the user. - pending_origins_[extension_origin_pair].push_back(callback); + PendingOrigin& pending_origin = + pending_origins_[make_pair(extension->id(), origin)]; + InfoBarManager* infobar_manager = + InfoBarService::FromWebContents(web_contents); + TabContext& tab_context = pending_origin[infobar_manager]; + tab_context.callbacks.push_back(callback); + if (tab_context.infobar) { + // This tab is already displaying an infobar for this extension and origin. return; } // We need to ask the user. ++g_alert_count; - pending_origins_[extension_origin_pair].push_back(callback); switch (g_alert_mode) { // Production code should always be using INTERACTIVE. @@ -155,27 +164,35 @@ extension->is_app() ? IDS_EXTENSION_PROMPT_APP_CONNECT_FROM_INCOGNITO : IDS_EXTENSION_PROMPT_EXTENSION_CONNECT_FROM_INCOGNITO; - IncognitoConnectabilityInfoBarDelegate::Create( - InfoBarService::FromWebContents(web_contents), - l10n_util::GetStringFUTF16(template_id, - base::UTF8ToUTF16(origin.spec()), - base::UTF8ToUTF16(extension->name())), + tab_context.infobar = IncognitoConnectabilityInfoBarDelegate::Create( + infobar_manager, l10n_util::GetStringFUTF16( + template_id, base::UTF8ToUTF16(origin.spec()), + base::UTF8ToUTF16(extension->name())), base::Bind(&IncognitoConnectability::OnInteractiveResponse, - weak_factory_.GetWeakPtr(), extension->id(), origin)); + weak_factory_.GetWeakPtr(), extension->id(), origin, + infobar_manager)); break; } // Testing code can override to always allow or deny. case ScopedAlertTracker::ALWAYS_ALLOW: case ScopedAlertTracker::ALWAYS_DENY: - OnInteractiveResponse(extension->id(), origin, g_alert_mode); + OnInteractiveResponse(extension->id(), origin, infobar_manager, + g_alert_mode); break; } } +IncognitoConnectability::TabContext::TabContext() : infobar(nullptr) { +} + +IncognitoConnectability::TabContext::~TabContext() { +} + void IncognitoConnectability::OnInteractiveResponse( const std::string& extension_id, const GURL& origin, + InfoBarManager* infobar_manager, ScopedAlertTracker::Mode response) { switch (response) { case ScopedAlertTracker::ALWAYS_ALLOW: @@ -190,18 +207,41 @@ break; } - ExtensionOriginPair extension_origin_pair = - ExtensionOriginPair(extension_id, origin); - PendingAuthorizationMap::iterator pending_origin = - pending_origins_.find(extension_origin_pair); - DCHECK(pending_origin != pending_origins_.end()); + DCHECK(ContainsKey(pending_origins_, make_pair(extension_id, origin))); + PendingOrigin& pending_origin = + pending_origins_[make_pair(extension_id, origin)]; + DCHECK(ContainsKey(pending_origin, infobar_manager)); - std::vector<AuthorizationCallback> callbacks; - callbacks.swap(pending_origin->second); - pending_origins_.erase(pending_origin); + std::vector<base::Callback<void(bool)>> callbacks; + if (response == ScopedAlertTracker::INTERACTIVE) { + // No definitive answer for this extension and origin. Execute only the + // callbacks associated with this tab. + TabContext& tab_context = pending_origin[infobar_manager]; + callbacks.swap(tab_context.callbacks); + pending_origin.erase(infobar_manager); + } else { + // We have a definitive answer for this extension and origin. Close all + // other infobars and answer all the callbacks. + for (const auto& map_entry : pending_origin) { + InfoBarManager* other_infobar_manager = map_entry.first; + const TabContext& other_tab_context = map_entry.second; + if (other_infobar_manager != infobar_manager) { + // Disarm the delegate so that it doesn't think the infobar has been + // dismissed. + IncognitoConnectabilityInfoBarDelegate* delegate = + static_cast<IncognitoConnectabilityInfoBarDelegate*>( + other_tab_context.infobar->delegate()); + delegate->SetAnswered(); + other_infobar_manager->RemoveInfoBar(other_tab_context.infobar); + } + callbacks.insert(callbacks.end(), other_tab_context.callbacks.begin(), + other_tab_context.callbacks.end()); + } + pending_origins_.erase(make_pair(extension_id, origin)); + } + DCHECK(!callbacks.empty()); - - for (const AuthorizationCallback& callback : callbacks) { + for (const auto& callback : callbacks) { callback.Run(response == ScopedAlertTracker::ALWAYS_ALLOW); } }
diff --git a/chrome/browser/extensions/api/messaging/incognito_connectability.h b/chrome/browser/extensions/api/messaging/incognito_connectability.h index fd71387..2402ab8 100644 --- a/chrome/browser/extensions/api/messaging/incognito_connectability.h +++ b/chrome/browser/extensions/api/messaging/incognito_connectability.h
@@ -16,6 +16,11 @@ class WebContents; } +namespace infobars { +class InfoBar; +class InfoBarManager; +} + namespace extensions { class Extension; @@ -64,6 +69,18 @@ const base::Callback<void(bool)>& callback); private: + struct TabContext { + TabContext(); + ~TabContext(); + + // The infobar being shown in a given tab. The InfoBarManager maintains + // ownership of this object. This struct must always be destroyed before the + // infobar it tracks. + infobars::InfoBar* infobar; + // Connectability queries outstanding on this infobar. + std::vector<base::Callback<void(bool)>> callbacks; + }; + friend class BrowserContextKeyedAPIFactory<IncognitoConnectability>; explicit IncognitoConnectability(content::BrowserContext* context); @@ -71,15 +88,15 @@ typedef std::map<std::string, std::set<GURL> > ExtensionToOriginsMap; typedef std::pair<std::string, GURL> ExtensionOriginPair; - typedef base::Callback<void(bool)> AuthorizationCallback; - typedef std::map<ExtensionOriginPair, std::vector<AuthorizationCallback>> - PendingAuthorizationMap; + typedef std::map<infobars::InfoBarManager*, TabContext> PendingOrigin; + typedef std::map<ExtensionOriginPair, PendingOrigin> PendingOriginMap; // Called with the user's selection from the infobar. // |response == INTERACTIVE| indicates that the user closed the infobar // without selecting allow or deny. void OnInteractiveResponse(const std::string& extension_id, const GURL& origin, + infobars::InfoBarManager* infobar_manager, ScopedAlertTracker::Mode response); // Returns true if the (|extension|, |origin|) pair appears in the map. @@ -102,8 +119,11 @@ ExtensionToOriginsMap allowed_origins_; ExtensionToOriginsMap disallowed_origins_; - // These are origin pairs that are currently being prompted for. - PendingAuthorizationMap pending_origins_; + // This maps extension/origin pairs to the tabs with an infobar prompting for + // incognito connectability on them. This also stores a reference to the + // infobar and the set of callbacks (passed to Query) that will be called when + // the query is resolved. + PendingOriginMap pending_origins_; base::WeakPtrFactory<IncognitoConnectability> weak_factory_; };
diff --git a/chrome/browser/extensions/api/messaging/message_service.cc b/chrome/browser/extensions/api/messaging/message_service.cc index 80d672063..7ccd849 100644 --- a/chrome/browser/extensions/api/messaging/message_service.cc +++ b/chrome/browser/extensions/api/messaging/message_service.cc
@@ -118,7 +118,7 @@ }; struct MessageService::OpenChannelParams { - content::RenderProcessHost* source; + int source_process_id; scoped_ptr<base::DictionaryValue> source_tab; int source_frame_id; scoped_ptr<MessagePort> receiver; @@ -131,7 +131,7 @@ std::string tls_channel_id; // Takes ownership of receiver. - OpenChannelParams(content::RenderProcessHost* source, + OpenChannelParams(int source_process_id, scoped_ptr<base::DictionaryValue> source_tab, int source_frame_id, MessagePort* receiver, @@ -141,7 +141,7 @@ const GURL& source_url, const std::string& channel_name, bool include_tls_channel_id) - : source(source), + : source_process_id(source_process_id), source_frame_id(source_frame_id), receiver(receiver), receiver_port_id(receiver_port_id), @@ -321,9 +321,9 @@ } scoped_ptr<OpenChannelParams> params(new OpenChannelParams( - source, source_tab.Pass(), source_frame_id, nullptr, receiver_port_id, - source_extension_id, target_extension_id, source_url, channel_name, - include_tls_channel_id)); + source_process_id, source_tab.Pass(), source_frame_id, nullptr, + receiver_port_id, source_extension_id, target_extension_id, source_url, + channel_name, include_tls_channel_id)); pending_incognito_channels_[GET_CHANNEL_ID(params->receiver_port_id)] = PendingMessagesQueue(); @@ -463,29 +463,27 @@ } scoped_ptr<OpenChannelParams> params(new OpenChannelParams( - source, - scoped_ptr<base::DictionaryValue>(), // Source tab doesn't make sense - // for opening to tabs. - -1, // If there is no tab, then there is no frame either. - receiver.release(), - receiver_port_id, - extension_id, - extension_id, - GURL(), // Source URL doesn't make sense for opening to tabs. - channel_name, - false)); // Connections to tabs don't get TLS channel IDs. + source_process_id, + scoped_ptr<base::DictionaryValue>(), // Source tab doesn't make sense + // for opening to tabs. + -1, // If there is no tab, then there is no frame either. + receiver.release(), receiver_port_id, extension_id, extension_id, + GURL(), // Source URL doesn't make sense for opening to tabs. + channel_name, + false)); // Connections to tabs don't get TLS channel IDs. OpenChannelImpl(params.Pass()); } -bool MessageService::OpenChannelImpl(scoped_ptr<OpenChannelParams> params) { - if (!params->source) - return false; // Closed while in flight. +void MessageService::OpenChannelImpl(scoped_ptr<OpenChannelParams> params) { + content::RenderProcessHost* source = + content::RenderProcessHost::FromID(params->source_process_id); + if (!source) + return; // Closed while in flight. if (!params->receiver || !params->receiver->GetRenderProcessHost()) { - DispatchOnDisconnect(params->source, - params->receiver_port_id, + DispatchOnDisconnect(source, params->receiver_port_id, kReceivingEndDoesntExistError); - return false; + return; } // Add extra paranoid CHECKs, since we have crash reports of this being NULL. @@ -493,8 +491,7 @@ CHECK(params->receiver->GetRenderProcessHost()); MessageChannel* channel(new MessageChannel); - channel->opener.reset(new ExtensionMessagePort(params->source, - MSG_ROUTING_CONTROL, + channel->opener.reset(new ExtensionMessagePort(source, MSG_ROUTING_CONTROL, params->source_extension_id)); channel->receiver.reset(params->receiver.release()); @@ -518,7 +515,6 @@ // Keep both ends of the channel alive until the channel is closed. channel->opener->IncrementLazyKeepaliveCount(); channel->receiver->IncrementLazyKeepaliveCount(); - return true; } void MessageService::AddChannel(MessageChannel* channel, int receiver_port_id) { @@ -700,7 +696,7 @@ int channel_id = GET_CHANNEL_ID((*params)->receiver_port_id); pending_lazy_background_page_channels_[channel_id] = PendingLazyBackgroundPageChannel(context, extension->id()); - int source_id = (*params)->source->GetID(); + int source_id = (*params)->source_process_id; lazy_background_task_queue_->AddPendingTask( context, extension->id(), base::Bind(&MessageService::PendingLazyBackgroundPageOpenChannel, @@ -727,13 +723,20 @@ pending_messages.swap(pending_for_incognito->second); pending_incognito_channels_.erase(pending_for_incognito); + // Re-lookup the source process since it may no longer be valid. + content::RenderProcessHost* source = + content::RenderProcessHost::FromID(params->source_process_id); + if (!source) { + return; + } + if (!allowed) { - DispatchOnDisconnect(params->source, params->receiver_port_id, + DispatchOnDisconnect(source, params->receiver_port_id, kReceivingEndDoesntExistError); return; } - BrowserContext* context = params->source->GetBrowserContext(); + BrowserContext* context = source->GetBrowserContext(); // Note: we use the source's profile here. If the source is an incognito // process, we will use the incognito EPM to find the right extension process, @@ -762,7 +765,7 @@ const Extension* target_extension = registry->enabled_extensions().GetByID(params->target_extension_id); if (!target_extension) { - DispatchOnDisconnect(params->source, params->receiver_port_id, + DispatchOnDisconnect(source, params->receiver_port_id, kReceivingEndDoesntExistError); return; } @@ -792,14 +795,20 @@ pending_messages.swap(pending_for_tls_channel_id->second); pending_tls_channel_id_channels_.erase(pending_for_tls_channel_id); - BrowserContext* context = params->source->GetBrowserContext(); + // Re-lookup the source process since it may no longer be valid. + content::RenderProcessHost* source = + content::RenderProcessHost::FromID(params->source_process_id); + if (!source) { + return; + } + + BrowserContext* context = source->GetBrowserContext(); ExtensionRegistry* registry = ExtensionRegistry::Get(context); const Extension* target_extension = registry->enabled_extensions().GetByID(params->target_extension_id); if (!target_extension) { - DispatchOnDisconnect( - params->source, params->receiver_port_id, - kReceivingEndDoesntExistError); + DispatchOnDisconnect(source, params->receiver_port_id, + kReceivingEndDoesntExistError); return; } @@ -817,13 +826,6 @@ if (!host) return; // TODO(mpcomplete): notify source of disconnect? - // Re-lookup the source process since it may no longer be valid. - content::RenderProcessHost* source = - content::RenderProcessHost::FromID(source_process_id); - if (!source) - return; - - params->source = source; params->receiver.reset(new ExtensionMessagePort(host->render_process_host(), MSG_ROUTING_CONTROL, params->target_extension_id));
diff --git a/chrome/browser/extensions/api/messaging/message_service.h b/chrome/browser/extensions/api/messaging/message_service.h index ebf993c..d25219fd 100644 --- a/chrome/browser/extensions/api/messaging/message_service.h +++ b/chrome/browser/extensions/api/messaging/message_service.h
@@ -182,7 +182,7 @@ PendingLazyBackgroundPageChannelMap; // Common among OpenChannel* variants. - bool OpenChannelImpl(scoped_ptr<OpenChannelParams> params); + void OpenChannelImpl(scoped_ptr<OpenChannelParams> params); void CloseChannelImpl(MessageChannelMap::iterator channel_iter, int port_id,
diff --git a/chrome/browser/extensions/api/vpn_provider/OWNERS b/chrome/browser/extensions/api/vpn_provider/OWNERS new file mode 100644 index 0000000..9e75e8cd --- /dev/null +++ b/chrome/browser/extensions/api/vpn_provider/OWNERS
@@ -0,0 +1,3 @@ +kaliamoorthi@chromium.org +bartfab@chromium.org +pneubeck@chromium.org
diff --git a/extensions/browser/api/vpn_provider/vpn_service_factory.cc b/chrome/browser/extensions/api/vpn_provider/vpn_service_factory.cc similarity index 80% rename from extensions/browser/api/vpn_provider/vpn_service_factory.cc rename to chrome/browser/extensions/api/vpn_provider/vpn_service_factory.cc index 198c6b7..a46b328 100644 --- a/extensions/browser/api/vpn_provider/vpn_service_factory.cc +++ b/chrome/browser/extensions/api/vpn_provider/vpn_service_factory.cc
@@ -4,8 +4,9 @@ #include "extensions/browser/api/vpn_provider/vpn_service_factory.h" -#include "base/logging.h" #include "base/memory/singleton.h" +#include "chrome/browser/chromeos/profiles/profile_helper.h" +#include "chrome/browser/profiles/profile.h" #include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/network/network_handler.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" @@ -15,9 +16,6 @@ namespace chromeos { -// TODO(kaliamoorthi): crbug.com/433843 Move the factory over to the chrome/* -// to be able to access profile helpers. - // static VpnService* VpnServiceFactory::GetForBrowserContext( content::BrowserContext* context) { @@ -49,12 +47,15 @@ KeyedService* VpnServiceFactory::BuildServiceInstanceFor( content::BrowserContext* context) const { - // TODO(kaliamoorthi): As of now VpnService instances are created for every - // profile including login profile, eliminate this. - DCHECK(NetworkHandler::IsInitialized()); - DCHECK(DBusThreadManager::IsInitialized()); + if (!chromeos::ProfileHelper::IsPrimaryProfile( + Profile::FromBrowserContext(context))) { + return nullptr; + } return new VpnService( - context, extensions::ExtensionRegistry::Get(context), + context, + chromeos::ProfileHelper::GetUserIdHashFromProfile( + Profile::FromBrowserContext(context)), + extensions::ExtensionRegistry::Get(context), extensions::EventRouter::Get(context), DBusThreadManager::Get()->GetShillThirdPartyVpnDriverClient(), NetworkHandler::Get()->network_configuration_handler(),
diff --git a/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc b/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc index e6db533..046b672 100644 --- a/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc +++ b/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
@@ -181,7 +181,8 @@ void SetUp() override { ASSERT_TRUE(profile_manager_.SetUp()); ChromeNetworkDelegate::InitializePrefsOnUIThread( - &enable_referrers_, NULL, NULL, profile_.GetTestingPrefService()); + &enable_referrers_, NULL, NULL, NULL, NULL, + profile_.GetTestingPrefService()); network_delegate_.reset( new ChromeNetworkDelegate(event_router_.get(), &enable_referrers_)); network_delegate_->set_profile(&profile_); @@ -779,7 +780,8 @@ void SetUp() override { ASSERT_TRUE(profile_manager_.SetUp()); ChromeNetworkDelegate::InitializePrefsOnUIThread( - &enable_referrers_, NULL, NULL, profile_.GetTestingPrefService()); + &enable_referrers_, NULL, NULL, NULL, NULL, + profile_.GetTestingPrefService()); network_delegate_.reset( new ChromeNetworkDelegate(event_router_.get(), &enable_referrers_)); network_delegate_->set_profile(&profile_);
diff --git a/chrome/browser/extensions/browser_action_test_util.h b/chrome/browser/extensions/browser_action_test_util.h index 3e5b3165..6064b610 100644 --- a/chrome/browser/extensions/browser_action_test_util.h +++ b/chrome/browser/extensions/browser_action_test_util.h
@@ -7,11 +7,10 @@ #include <string> -#include "build/build_config.h" #include "ui/gfx/native_widget_types.h" class Browser; -class ExtensionAction; +class ToolbarActionsBarDelegate; namespace gfx { class Image; @@ -21,7 +20,16 @@ class BrowserActionTestUtil { public: - explicit BrowserActionTestUtil(Browser* browser) : browser_(browser) {} + // Constructs a BrowserActionTestUtil that uses the |browser|'s default + // browser action container. + explicit BrowserActionTestUtil(Browser* browser) + : browser_(browser), bar_delegate_(nullptr) {} + + // Constructs a BrowserActionTestUtil that will use the |bar_delegate| as the + // browser action container to test. + BrowserActionTestUtil(Browser* browser, + ToolbarActionsBarDelegate* bar_delegate) + : browser_(browser), bar_delegate_(bar_delegate) {} // Returns the number of browser action buttons in the window toolbar. int NumberOfBrowserActions(); @@ -82,6 +90,10 @@ private: Browser* browser_; // weak + + // If non-null, this is a set view to test with, rather than using the + // |browser|'s default container. + ToolbarActionsBarDelegate* bar_delegate_; // weak }; #endif // CHROME_BROWSER_EXTENSIONS_BROWSER_ACTION_TEST_UTIL_H_
diff --git a/chrome/browser/extensions/extension_action_test_util.cc b/chrome/browser/extensions/extension_action_test_util.cc index bb7736d..cab838e 100644 --- a/chrome/browser/extensions/extension_action_test_util.cc +++ b/chrome/browser/extensions/extension_action_test_util.cc
@@ -4,16 +4,23 @@ #include "chrome/browser/extensions/extension_action_test_util.h" +#include "base/run_loop.h" #include "chrome/browser/extensions/extension_action.h" #include "chrome/browser/extensions/extension_action_manager.h" #include "chrome/browser/extensions/extension_toolbar_model.h" +#include "chrome/browser/extensions/extension_toolbar_model_factory.h" #include "chrome/browser/extensions/location_bar_controller.h" #include "chrome/browser/extensions/tab_helper.h" +#include "chrome/browser/extensions/test_extension_system.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/sessions/session_tab_helper.h" +#include "components/crx_file/id_util.h" #include "content/public/browser/web_contents.h" #include "extensions/common/extension.h" +#include "extensions/common/extension_builder.h" #include "extensions/common/feature_switch.h" +#include "extensions/common/manifest_constants.h" +#include "extensions/common/value_builder.h" namespace extensions { namespace extension_action_test_util { @@ -61,6 +68,42 @@ return count; } +// Creates a new ExtensionToolbarModel for the given |context|. +KeyedService* BuildToolbarModel(content::BrowserContext* context) { + return new extensions::ExtensionToolbarModel( + Profile::FromBrowserContext(context), + extensions::ExtensionPrefs::Get(context)); +} + +// Creates a new ExtensionToolbarModel for the given profile, optionally +// triggering the extension system's ready signal. +ExtensionToolbarModel* CreateToolbarModelImpl(Profile* profile, + bool wait_for_ready) { + ExtensionToolbarModel* model = ExtensionToolbarModel::Get(profile); + if (model) + return model; + + // No existing model means it's a new profile (since we, by default, don't + // create the ToolbarModel in testing). + ExtensionToolbarModelFactory::GetInstance()->SetTestingFactory( + profile, &BuildToolbarModel); + model = ExtensionToolbarModel::Get(profile); + if (wait_for_ready) { + // Fake the extension system ready signal. + // HACK ALERT! In production, the ready task on ExtensionSystem (and most + // everything else on it, too) is shared between incognito and normal + // profiles, but a TestExtensionSystem doesn't have the concept of "shared". + // Because of this, we have to set any new profile's TestExtensionSystem's + // ready task, too. + static_cast<TestExtensionSystem*>(ExtensionSystem::Get(profile))-> + SetReady(); + // Run tasks posted to TestExtensionSystem. + base::RunLoop().RunUntilIdle(); + } + + return model; +} + } // namespace size_t GetVisiblePageActionCount(content::WebContents* web_contents) { @@ -71,5 +114,42 @@ return GetPageActionCount(web_contents, false); } +scoped_refptr<const Extension> CreateActionExtension(const std::string& name, + ActionType action_type) { + DictionaryBuilder manifest; + manifest.Set("name", name) + .Set("description", "An extension") + .Set("manifest_version", 2) + .Set("version", "1.0.0"); + + const char* action_key = nullptr; + switch (action_type) { + case NO_ACTION: + break; + case PAGE_ACTION: + action_key = manifest_keys::kPageAction; + break; + case BROWSER_ACTION: + action_key = manifest_keys::kBrowserAction; + break; + } + + if (action_key) + manifest.Set(action_key, DictionaryBuilder().Pass()); + + return ExtensionBuilder().SetManifest(manifest.Pass()). + SetID(crx_file::id_util::GenerateId(name)). + Build(); +} + +ExtensionToolbarModel* CreateToolbarModelForProfile(Profile* profile) { + return CreateToolbarModelImpl(profile, true); +} + +ExtensionToolbarModel* CreateToolbarModelForProfileWithoutWaitingForReady( + Profile* profile) { + return CreateToolbarModelImpl(profile, false); +} + } // namespace extension_action_test_util } // namespace extensions
diff --git a/chrome/browser/extensions/extension_action_test_util.h b/chrome/browser/extensions/extension_action_test_util.h index 45afa000..ddad3a44 100644 --- a/chrome/browser/extensions/extension_action_test_util.h +++ b/chrome/browser/extensions/extension_action_test_util.h
@@ -5,15 +5,31 @@ #ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_ACTION_TEST_UTIL_H_ #define CHROME_BROWSER_EXTENSIONS_EXTENSION_ACTION_TEST_UTIL_H_ +#include <string> + #include "base/basictypes.h" +#include "base/memory/ref_counted.h" + +class Profile; namespace content { class WebContents; } namespace extensions { +class Extension; +class ExtensionToolbarModel; + namespace extension_action_test_util { +// The different possible types of actions for an extension to have (we use +// this instead of ActionInfo::Type because we want a "none" option). +enum ActionType { + NO_ACTION, + PAGE_ACTION, + BROWSER_ACTION +}; + // TODO(devlin): Should we also pull out methods to test browser actions? // Returns the number of page actions that are visible in the given @@ -24,6 +40,23 @@ // |web_contents|. size_t GetTotalPageActionCount(content::WebContents* web_contents); +// Creates and returns an extension with the given |name| with the given +// |action_type|. +// Does not add the extension to the extension service or registry. +scoped_refptr<const Extension> CreateActionExtension(const std::string& name, + ActionType action_type); + +// Creates a new ExtensionToolbarModel for the given |profile|, and associates +// it with the profile as a keyed service. +// This should only be used in unit tests (since it assumes the existence of +// a TestExtensionSystem), but if running a browser test, the model should +// already be created. +ExtensionToolbarModel* CreateToolbarModelForProfile(Profile* profile); +// Like above, but doesn't run the ExtensionSystem::ready() task for the new +// model. +ExtensionToolbarModel* CreateToolbarModelForProfileWithoutWaitingForReady( + Profile* profile); + } // namespace extension_action_test_util } // namespace extensions
diff --git a/chrome/browser/extensions/extension_apitest.cc b/chrome/browser/extensions/extension_apitest.cc index ecf88fd1..d8c696f 100644 --- a/chrome/browser/extensions/extension_apitest.cc +++ b/chrome/browser/extensions/extension_apitest.cc
@@ -11,11 +11,13 @@ #include "chrome/browser/extensions/unpacked_installer.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/extensions/app_launch_params.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/test/base/ui_test_utils.h" #include "extensions/browser/api/test/test_api.h" #include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_system.h" +#include "extensions/common/constants.h" #include "extensions/common/extension.h" #include "extensions/common/extension_set.h" #include "extensions/test/result_catcher.h" @@ -308,10 +310,9 @@ else ui_test_utils::NavigateToURL(browser(), url); } else if (launch_platform_app) { - AppLaunchParams params(browser()->profile(), - extension, - extensions::LAUNCH_CONTAINER_NONE, - NEW_WINDOW); + AppLaunchParams params(browser()->profile(), extension, + extensions::LAUNCH_CONTAINER_NONE, NEW_WINDOW, + extensions::SOURCE_UNTRACKED); params.command_line = *CommandLine::ForCurrentProcess(); OpenApplication(params); }
diff --git a/chrome/browser/extensions/extension_messages_apitest.cc b/chrome/browser/extensions/extension_messages_apitest.cc index cae5667..64894ac6 100644 --- a/chrome/browser/extensions/extension_messages_apitest.cc +++ b/chrome/browser/extensions/extension_messages_apitest.cc
@@ -10,12 +10,14 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/string_piece.h" #include "base/strings/stringprintf.h" +#include "base/strings/utf_string_conversions.h" #include "base/synchronization/waitable_event.h" #include "base/values.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/extensions/api/messaging/incognito_connectability.h" #include "chrome/browser/extensions/extension_apitest.h" #include "chrome/browser/extensions/test_extension_dir.h" +#include "chrome/browser/infobars/infobar_service.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" @@ -773,6 +775,69 @@ CanConnectAndSendMessagesToFrame(incognito_frame, app.get(), NULL)); } +// Tests connection from incognito tabs when there are multiple tabs open to the +// same origin. The user should only need to accept the connection request once. +IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest, + FromIncognitoPromptApp) { + InitializeTestServer(); + + scoped_refptr<const Extension> app = LoadChromiumConnectableApp(); + ASSERT_TRUE(app->is_platform_app()); + + // Open an incognito browser with two tabs displaying "chromium.org". + Browser* incognito_browser = ui_test_utils::OpenURLOffTheRecord( + profile()->GetOffTheRecordProfile(), chromium_org_url()); + content::RenderFrameHost* incognito_frame1 = + incognito_browser->tab_strip_model() + ->GetActiveWebContents() + ->GetMainFrame(); + InfoBarService* infobar_service1 = InfoBarService::FromWebContents( + incognito_browser->tab_strip_model()->GetActiveWebContents()); + + CHECK(ui_test_utils::OpenURLOffTheRecord(profile()->GetOffTheRecordProfile(), + chromium_org_url()) == + incognito_browser); + content::RenderFrameHost* incognito_frame2 = + incognito_browser->tab_strip_model() + ->GetActiveWebContents() + ->GetMainFrame(); + InfoBarService* infobar_service2 = InfoBarService::FromWebContents( + incognito_browser->tab_strip_model()->GetActiveWebContents()); + EXPECT_EQ(2, incognito_browser->tab_strip_model()->count()); + EXPECT_NE(incognito_frame1, incognito_frame2); + + // Trigger a infobars in both tabs by trying to send messages. + std::string script = + base::StringPrintf("assertions.trySendMessage('%s')", app->id().c_str()); + CHECK(content::ExecuteScript(incognito_frame1, script)); + CHECK(content::ExecuteScript(incognito_frame2, script)); + EXPECT_EQ(1U, infobar_service1->infobar_count()); + EXPECT_EQ(1U, infobar_service2->infobar_count()); + + // Navigating away will dismiss the infobar on the active tab only. + ui_test_utils::NavigateToURL(incognito_browser, google_com_url()); + EXPECT_EQ(1U, infobar_service1->infobar_count()); + EXPECT_EQ(0U, infobar_service2->infobar_count()); + + // Navigate back and accept the infobar this time. Both should be dismissed. + { + IncognitoConnectability::ScopedAlertTracker alert_tracker( + IncognitoConnectability::ScopedAlertTracker::ALWAYS_ALLOW); + + ui_test_utils::NavigateToURL(incognito_browser, chromium_org_url()); + incognito_frame2 = incognito_browser->tab_strip_model() + ->GetActiveWebContents() + ->GetMainFrame(); + EXPECT_NE(incognito_frame1, incognito_frame2); + + EXPECT_EQ(1U, infobar_service1->infobar_count()); + EXPECT_EQ(OK, CanConnectAndSendMessagesToFrame(incognito_frame2, app.get(), + NULL)); + EXPECT_EQ(1, alert_tracker.GetAndResetAlertCount()); + EXPECT_EQ(0U, infobar_service1->infobar_count()); + } +} + IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest, FromIncognitoAllowExtension) { InitializeTestServer();
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc index b4e4820..ab5ee16 100644 --- a/chrome/browser/extensions/extension_service.cc +++ b/chrome/browser/extensions/extension_service.cc
@@ -793,9 +793,14 @@ return false; } - if (block_extensions_ && - CanBlockExtension(GetInstalledExtension(extension_id))) - return false; + // Blocked extensions aren't marked as such in prefs, thus if + // |block_extensions_| is true then CanBlockExtension() must be called with an + // Extension object. If the |extension_id| is not loaded, assume not enabled. + if (block_extensions_) { + const Extension* extension = GetInstalledExtension(extension_id); + if (!extension || CanBlockExtension(extension)) + return false; + } // If the extension hasn't been loaded yet, check the prefs for it. Assume // enabled unless otherwise noted. @@ -2248,6 +2253,7 @@ // Helper method to determine if an extension can be blocked. bool ExtensionService::CanBlockExtension(const Extension* extension) const { + DCHECK(extension); return extension->location() != Manifest::COMPONENT && extension->location() != Manifest::EXTERNAL_COMPONENT && !system_->management_policy()->MustRemainEnabled(extension, NULL);
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc index ae5b0dd..17cb2d8b 100644 --- a/chrome/browser/extensions/extension_service_unittest.cc +++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -133,7 +133,7 @@ #include "ui/base/l10n/l10n_util.h" #include "url/gurl.h" -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) #include "chrome/browser/supervised_user/supervised_user_service.h" #include "chrome/browser/supervised_user/supervised_user_service_factory.h" #endif @@ -3769,6 +3769,15 @@ ASSERT_TRUE(IsBlocked(good0)); } +// Tests that IsEnabledExtension won't crash on an uninstalled extension. +TEST_F(ExtensionServiceTest, IsEnabledExtensionBlockedAndNotInstalled) { + InitializeEmptyExtensionService(); + + service()->BlockAllExtensions(); + + service()->IsExtensionEnabled(theme_crx); +} + // Will not install extension blacklisted by policy. TEST_F(ExtensionServiceTest, BlacklistedByPolicyWillNotInstall) { InitializeEmptyExtensionServiceWithTestingPrefs(); @@ -6531,7 +6540,7 @@ // TODO(akalin): Figure out a way to test |info.ShouldAllowInstall()|. } -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) TEST_F(ExtensionServiceTest, SupervisedUser_InstallOnlyAllowedByCustodian) { ExtensionServiceInitParams params = CreateDefaultInitParams(); params.profile_is_supervised = true; @@ -6686,7 +6695,7 @@ EXPECT_FALSE( registry()->GenerateInstalledExtensionsSet()->Contains(extension_ids[1])); } -#endif // defined(ENABLE_MANAGED_USERS) +#endif // defined(ENABLE_SUPERVISED_USERS) TEST_F(ExtensionServiceTest, InstallPriorityExternalUpdateUrl) { InitializeEmptyExtensionService();
diff --git a/chrome/browser/extensions/extension_storage_monitor_browsertest.cc b/chrome/browser/extensions/extension_storage_monitor_browsertest.cc index d2a3966..b96930a8 100644 --- a/chrome/browser/extensions/extension_storage_monitor_browsertest.cc +++ b/chrome/browser/extensions/extension_storage_monitor_browsertest.cc
@@ -9,12 +9,14 @@ #include "chrome/browser/extensions/extension_browsertest.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_storage_monitor.h" +#include "chrome/browser/ui/extensions/app_launch_params.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "content/public/test/test_utils.h" #include "extensions/browser/extension_prefs.h" #include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_system.h" #include "extensions/browser/test_extension_registry_observer.h" +#include "extensions/common/constants.h" #include "extensions/test/extension_test_message_listener.h" #include "ui/message_center/message_center.h" #include "ui/message_center/message_center_observer.h" @@ -179,8 +181,8 @@ NotificationObserver notification_observer( GetNotificationId(extension->id())); - OpenApplication(AppLaunchParams( - profile(), extension, LAUNCH_CONTAINER_NONE, NEW_WINDOW)); + OpenApplication(AppLaunchParams(profile(), extension, LAUNCH_CONTAINER_NONE, + NEW_WINDOW, extensions::SOURCE_UNTRACKED)); ASSERT_TRUE(launched_listener.WaitUntilSatisfied()); // Instruct the app to write |num_bytes| of data.
diff --git a/chrome/browser/extensions/extension_toolbar_model.cc b/chrome/browser/extensions/extension_toolbar_model.cc index 7f4c931..e3667d6 100644 --- a/chrome/browser/extensions/extension_toolbar_model.cc +++ b/chrome/browser/extensions/extension_toolbar_model.cc
@@ -151,18 +151,10 @@ ExtensionRegistry::Get(profile_)->enabled_extensions().GetByID( extension_action->extension_id()); // Notify observers if the extension exists and is in the model. - ExtensionList::const_iterator iter = - std::find(toolbar_items_.begin(), toolbar_items_.end(), extension); - if (iter != toolbar_items_.end()) { + if (std::find(toolbar_items_.begin(), toolbar_items_.end(), extension) != + toolbar_items_.end()) { FOR_EACH_OBSERVER( Observer, observers_, ToolbarExtensionUpdated(extension)); - // If the action was in the overflow menu, we have to alert observers that - // the toolbar needs to be reordered (to show the action). - if (static_cast<size_t>(iter - toolbar_items_.begin()) >= - visible_icon_count()) { - FOR_EACH_OBSERVER( - Observer, observers_, OnToolbarReorderNecessary(web_contents)); - } } } @@ -594,49 +586,6 @@ } } -size_t ExtensionToolbarModel::GetVisibleIconCountForTab( - content::WebContents* web_contents) const { - if (all_icons_visible()) - return visible_icon_count(); // Already displaying all actions. - - ExtensionActionAPI* extension_action_api = ExtensionActionAPI::Get(profile_); - size_t total_icons = visible_icon_count(); - for (size_t i = total_icons; i < toolbar_items_.size(); ++i) { - if (extension_action_api->ExtensionWantsToRun(toolbar_items_[i].get(), - web_contents)) - ++total_icons; - } - return total_icons; -} - -ExtensionList ExtensionToolbarModel::GetItemOrderForTab( - content::WebContents* web_contents) const { - // If we're highlighting, the items are always the same. - if (is_highlighting_) - return highlighted_items_; - - // Start by initializing the array to be the same as toolbar items (this isn't - // any more expensive than initializing it to be of the same size with all - // nulls, and saves us time at the end). - ExtensionList result = toolbar_items_; - if (toolbar_items_.empty()) - return result; - - ExtensionList overflowed_actions_wanting_to_run; - ExtensionActionAPI* extension_action_api = ExtensionActionAPI::Get(profile_); - size_t boundary = visible_icon_count(); - // Rotate any actions that want to run to the boundary between visible and - // overflowed actions. - for (ExtensionList::iterator iter = result.begin() + boundary; - iter != result.end(); ++iter) { - if (extension_action_api->ExtensionWantsToRun(iter->get(), web_contents)) { - std::rotate(result.begin() + boundary, iter, iter + 1); - ++boundary; - } - } - return result; -} - bool ExtensionToolbarModel::ShowExtensionActionPopup( const Extension* extension, Browser* browser,
diff --git a/chrome/browser/extensions/extension_toolbar_model.h b/chrome/browser/extensions/extension_toolbar_model.h index 867ee67f..34aadc9 100644 --- a/chrome/browser/extensions/extension_toolbar_model.h +++ b/chrome/browser/extensions/extension_toolbar_model.h
@@ -85,12 +85,6 @@ // can catch up. virtual void OnToolbarModelInitialized() = 0; - // Signals that the toolbar needs to be reordered for the given - // |web_contents|. This is caused by an overflowed action wanting to run, - // and needing to "pop itself out". - virtual void OnToolbarReorderNecessary( - content::WebContents* web_contents) = 0; - // Returns the browser associated with the Observer. virtual Browser* GetBrowser() = 0; @@ -135,16 +129,6 @@ void OnExtensionToolbarPrefChange(); - // Returns the item order for a given tab. This can be different from the - // base item order if the action wants to run on the given page, and needs to - // be popped out of overflow. - ExtensionList GetItemOrderForTab(content::WebContents* web_contents) const; - - // Returns the visible icon count for a given tab. This can be different from - // the base item order if the action wants to run on the given page and needs - // to be popped out of overflow. - size_t GetVisibleIconCountForTab(content::WebContents* web_contents) const; - // Finds the Observer associated with |browser| and tells it to display a // popup for the given |extension|. If |grant_active_tab| is true, this // grants active tab permissions to the |extension|; only do this because of
diff --git a/chrome/browser/extensions/extension_toolbar_model_unittest.cc b/chrome/browser/extensions/extension_toolbar_model_unittest.cc index 952527c..2791d65 100644 --- a/chrome/browser/extensions/extension_toolbar_model_unittest.cc +++ b/chrome/browser/extensions/extension_toolbar_model_unittest.cc
@@ -9,10 +9,10 @@ #include "base/strings/stringprintf.h" #include "chrome/browser/extensions/api/extension_action/extension_action_api.h" #include "chrome/browser/extensions/extension_action_manager.h" +#include "chrome/browser/extensions/extension_action_test_util.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_service_test_base.h" #include "chrome/browser/extensions/extension_toolbar_model.h" -#include "chrome/browser/extensions/extension_toolbar_model_factory.h" #include "chrome/browser/extensions/extension_util.h" #include "chrome/browser/extensions/test_extension_dir.h" #include "chrome/browser/extensions/test_extension_system.h" @@ -28,10 +28,7 @@ #include "extensions/browser/extension_system.h" #include "extensions/browser/test_extension_registry_observer.h" #include "extensions/common/extension.h" -#include "extensions/common/extension_builder.h" #include "extensions/common/feature_switch.h" -#include "extensions/common/manifest_constants.h" -#include "extensions/common/value_builder.h" #if defined(USE_AURA) #include "ui/aura/env.h" @@ -41,124 +38,6 @@ namespace { -// A helper class to create test web contents (tabs) for unit tests, without -// inheriting from RenderViewTestHarness. Can create web contents, and will -// clean up after itself upon destruction. Owns all created web contents. -// A few notes: -// - Works well allocated on the stack, because it should be destroyed before -// associated browser context. -// - Doesn't play nice with web contents created any other way (because of -// the implementation of RenderViewHostTestEnabler). But if you are creating -// web contents already, what do you need this for? ;) -// - This will call aura::Env::Create/DeleteInstance(), because that's needed -// for web contents. Nothing else should call it first. (This could be -// tweaked by passing in a flag, if there's need.) -// TODO(devlin): Look around and see if this class is needed elsewhere; if so, -// move it there and expand the API a bit (methods to, e.g., delete/close a -// web contents, access existing web contents, etc). -class TestWebContentsFactory { - public: - TestWebContentsFactory(); - ~TestWebContentsFactory(); - - // Creates a new WebContents with the given |context|, and returns it. - content::WebContents* CreateWebContents(content::BrowserContext* context); - - private: - // The test factory (and friends) for creating test web contents. - scoped_ptr<content::RenderViewHostTestEnabler> rvh_enabler_; - - // The vector of web contents that this class created. - ScopedVector<content::WebContents> web_contents_; - - DISALLOW_COPY_AND_ASSIGN(TestWebContentsFactory); -}; - -TestWebContentsFactory::TestWebContentsFactory() - : rvh_enabler_(new content::RenderViewHostTestEnabler()) { -#if defined(USE_AURA) - aura::Env::CreateInstance(true); -#endif -} - -TestWebContentsFactory::~TestWebContentsFactory() { - web_contents_.clear(); - // Let any posted tasks for web contents deletion run. - base::RunLoop().RunUntilIdle(); - rvh_enabler_.reset(); - // Let any posted tasks for RenderProcess/ViewHost deletion run. - base::RunLoop().RunUntilIdle(); - -#if defined(USE_AURA) - aura::Env::DeleteInstance(); -#endif -} - -content::WebContents* TestWebContentsFactory::CreateWebContents( - content::BrowserContext* context) { - scoped_ptr<content::WebContents> web_contents( - content::WebContentsTester::CreateTestWebContents(context, nullptr)); - DCHECK(web_contents); - web_contents_.push_back(web_contents.release()); - return web_contents_.back(); -} - -// Creates a new ExtensionToolbarModel for the given |context|. -KeyedService* BuildToolbarModel(content::BrowserContext* context) { - return new ExtensionToolbarModel(Profile::FromBrowserContext(context), - ExtensionPrefs::Get(context)); -} - -// Given a |profile|, assigns the testing keyed service function to -// BuildToolbarModel() and uses it to create and initialize a new -// ExtensionToolbarModel. -// |wait_for_ready| indicates whether or not to post the ExtensionSystem's -// ready task. -ExtensionToolbarModel* CreateToolbarModelForProfile(Profile* profile, - bool wait_for_ready) { - ExtensionToolbarModel* model = ExtensionToolbarModel::Get(profile); - if (model) - return model; - - // No existing model means it's a new profile (since we, by default, don't - // create the ToolbarModel in testing). - ExtensionToolbarModelFactory::GetInstance()->SetTestingFactory( - profile, &BuildToolbarModel); - model = ExtensionToolbarModel::Get(profile); - if (wait_for_ready) { - // Fake the extension system ready signal. - // HACK ALERT! In production, the ready task on ExtensionSystem (and most - // everything else on it, too) is shared between incognito and normal - // profiles, but a TestExtensionSystem doesn't have the concept of "shared". - // Because of this, we have to set any new profile's TestExtensionSystem's - // ready task, too. - static_cast<TestExtensionSystem*>(ExtensionSystem::Get(profile))-> - SetReady(); - // Run tasks posted to TestExtensionSystem. - base::RunLoop().RunUntilIdle(); - } - - return model; -} - -// Create an extension. If |action_key| is non-NULL, it should point to either -// kBrowserAction or kPageAction, and the extension will have the associated -// action. -scoped_refptr<const Extension> GetActionExtension(const std::string& name, - const char* action_key) { - DictionaryBuilder manifest; - manifest.Set("name", name) - .Set("description", "An extension") - .Set("manifest_version", 2) - .Set("version", "1.0.0"); - if (action_key) - manifest.Set(action_key, DictionaryBuilder().Pass()); - - return ExtensionBuilder().SetManifest(manifest.Pass()) - .SetID(crx_file::id_util::GenerateId(name)) - .Build(); -} - // A simple observer that tracks the number of times certain events occur. class ExtensionToolbarModelTestObserver : public ExtensionToolbarModel::Observer { @@ -171,7 +50,6 @@ size_t moved_count() const { return moved_count_; } int highlight_mode_count() const { return highlight_mode_count_; } size_t initialized_count() const { return initialized_count_; } - size_t reorder_count() const { return reorder_count_; } private: // ExtensionToolbarModel::Observer: @@ -203,10 +81,6 @@ void OnToolbarModelInitialized() override { ++initialized_count_; } - void OnToolbarReorderNecessary(content::WebContents* web_contents) override { - ++reorder_count_; - } - Browser* GetBrowser() override { return NULL; } ExtensionToolbarModel* model_; @@ -217,7 +91,6 @@ // Int because it could become negative (if something goes wrong). int highlight_mode_count_; size_t initialized_count_; - size_t reorder_count_; }; ExtensionToolbarModelTestObserver::ExtensionToolbarModelTestObserver( @@ -226,8 +99,7 @@ removed_count_(0), moved_count_(0), highlight_mode_count_(0), - initialized_count_(0), - reorder_count_(0) { + initialized_count_(0) { model_->AddObserver(this); } @@ -308,7 +180,8 @@ void ExtensionToolbarModelUnitTest::Init() { InitializeEmptyExtensionService(); - toolbar_model_ = CreateToolbarModelForProfile(profile(), true); + toolbar_model_ = + extension_action_test_util::CreateToolbarModelForProfile(profile()); model_observer_.reset(new ExtensionToolbarModelTestObserver(toolbar_model_)); } @@ -347,11 +220,12 @@ } testing::AssertionResult ExtensionToolbarModelUnitTest::AddActionExtensions() { - browser_action_extension_ = - GetActionExtension("browser_action", manifest_keys::kBrowserAction); - page_action_extension_ = - GetActionExtension("page_action", manifest_keys::kPageAction); - no_action_extension_ = GetActionExtension("no_action", NULL); + browser_action_extension_ = extension_action_test_util::CreateActionExtension( + "browser_action", extension_action_test_util::BROWSER_ACTION); + page_action_extension_ = extension_action_test_util::CreateActionExtension( + "page_action", extension_action_test_util::PAGE_ACTION); + no_action_extension_ = extension_action_test_util::CreateActionExtension( + "no_action", extension_action_test_util::NO_ACTION); ExtensionList extensions; extensions.push_back(browser_action_extension_); @@ -363,12 +237,12 @@ testing::AssertionResult ExtensionToolbarModelUnitTest::AddBrowserActionExtensions() { - browser_action_a_ = - GetActionExtension("browser_actionA", manifest_keys::kBrowserAction); - browser_action_b_ = - GetActionExtension("browser_actionB", manifest_keys::kBrowserAction); - browser_action_c_ = - GetActionExtension("browser_actionC", manifest_keys::kBrowserAction); + browser_action_a_ = extension_action_test_util::CreateActionExtension( + "browser_actionA", extension_action_test_util::BROWSER_ACTION); + browser_action_b_ = extension_action_test_util::CreateActionExtension( + "browser_actionB", extension_action_test_util::BROWSER_ACTION); + browser_action_c_ = extension_action_test_util::CreateActionExtension( + "browser_actionC", extension_action_test_util::BROWSER_ACTION); ExtensionList extensions; extensions.push_back(browser_action_a_); @@ -408,7 +282,8 @@ // Load an extension with no browser action. scoped_refptr<const Extension> extension1 = - GetActionExtension("no_action", NULL); + extension_action_test_util::CreateActionExtension( + "no_action", extension_action_test_util::NO_ACTION); ASSERT_TRUE(AddExtension(extension1)); // This extension should not be in the model (has no browser action). @@ -418,7 +293,8 @@ // Load an extension with a browser action. scoped_refptr<const Extension> extension2 = - GetActionExtension("browser_action", manifest_keys::kBrowserAction); + extension_action_test_util::CreateActionExtension( + "browser_action", extension_action_test_util::BROWSER_ACTION); ASSERT_TRUE(AddExtension(extension2)); // We should now find our extension in the model. @@ -896,7 +772,8 @@ // Get an incognito profile and toolbar. ExtensionToolbarModel* incognito_model = - CreateToolbarModelForProfile(profile()->GetOffTheRecordProfile(), true); + extension_action_test_util::CreateToolbarModelForProfile( + profile()->GetOffTheRecordProfile()); ExtensionToolbarModelTestObserver incognito_observer(incognito_model); EXPECT_EQ(0u, incognito_observer.moved_count()); @@ -1001,7 +878,8 @@ // Get an incognito profile and toolbar. ExtensionToolbarModel* incognito_model = - CreateToolbarModelForProfile(profile()->GetOffTheRecordProfile(), true); + extension_action_test_util::CreateToolbarModelForProfile( + profile()->GetOffTheRecordProfile()); ExtensionToolbarModelTestObserver incognito_observer(incognito_model); // Right now, no extensions are enabled in incognito mode. @@ -1115,181 +993,13 @@ EXPECT_EQ(extension_b, GetExtensionAtIndex(2u)); } -// Test that toolbar actions can pop themselves out of overflow if they want -// to act on a given web contents. -TEST_F(ExtensionToolbarModelUnitTest, ToolbarActionsPopOutToAct) { - // Extensions popping themselves out to act is part of the toolbar redesign, - // and hidden behind a flag. - FeatureSwitch::ScopedOverride enable_redesign( - FeatureSwitch::extension_action_redesign(), true); - Init(); - TestWebContentsFactory web_contents_factory; - - ASSERT_TRUE(AddActionExtensions()); - - // We should start in the order of "browser action" "page action" "no action" - // and have all extensions visible. - EXPECT_EQ(3u, num_toolbar_items()); - EXPECT_TRUE(toolbar_model()->all_icons_visible()); - EXPECT_EQ(browser_action(), GetExtensionAtIndex(0u)); - EXPECT_EQ(page_action(), GetExtensionAtIndex(1u)); - EXPECT_EQ(no_action(), GetExtensionAtIndex(2u)); - - // Shrink the model to only show one action, and move the page action to the - // end. - toolbar_model()->SetVisibleIconCount(1); - toolbar_model()->MoveExtensionIcon(page_action()->id(), 2u); - - // Quickly verify that the move/visible count worked. - EXPECT_EQ(1u, toolbar_model()->visible_icon_count()); - EXPECT_EQ(browser_action(), GetExtensionAtIndex(0u)); - EXPECT_EQ(no_action(), GetExtensionAtIndex(1u)); - EXPECT_EQ(page_action(), GetExtensionAtIndex(2u)); - - // Create two test web contents, and a session tab helper for each. We need - // a session tab helper, since we rely on tab ids. - content::WebContents* web_contents = - web_contents_factory.CreateWebContents(profile()); - ASSERT_TRUE(web_contents); - SessionTabHelper::CreateForWebContents(web_contents); - content::WebContents* second_web_contents = - web_contents_factory.CreateWebContents(profile()); - ASSERT_TRUE(second_web_contents); - SessionTabHelper::CreateForWebContents(second_web_contents); - - // Find the tab ids, ensure that the two web contents have different ids, and - // verify that neither is -1 (invalid). - int tab_id = SessionTabHelper::IdForTab(web_contents); - int second_tab_id = SessionTabHelper::IdForTab(second_web_contents); - EXPECT_NE(tab_id, second_tab_id); - EXPECT_NE(-1, second_tab_id); - EXPECT_NE(-1, tab_id); - - // First, check the model order for the first tab. Since we haven't changed - // anything (i.e., no extensions want to act), this should be the same as we - // left it: "browser action", "no action", "page action", with only one - // visible. - ExtensionList tab_order = toolbar_model()->GetItemOrderForTab(web_contents); - ASSERT_EQ(3u, tab_order.size()); - EXPECT_EQ(browser_action(), tab_order[0].get()); - EXPECT_EQ(no_action(), tab_order[1].get()); - EXPECT_EQ(page_action(), tab_order[2].get()); - EXPECT_EQ(1u, toolbar_model()->GetVisibleIconCountForTab(web_contents)); - // And we should have no notifications to reorder the toolbar. - EXPECT_EQ(0u, observer()->reorder_count()); - - // Make "page action" want to act by making it's page action visible on the - // first tab, and notify the API of the change. - ExtensionActionManager* action_manager = - ExtensionActionManager::Get(profile()); - ExtensionAction* action = action_manager->GetExtensionAction(*page_action()); - ASSERT_TRUE(action); - action->SetIsVisible(tab_id, true); - ExtensionActionAPI* extension_action_api = ExtensionActionAPI::Get(profile()); - extension_action_api->NotifyChange(action, web_contents, profile()); - - // This should result in "page action" being popped out of the overflow menu. - // This has two visible effects: - // - page action should move to the second index (the one right after the last - // originally-visible). - // - The visible count should increase by one (so page action is visible). - tab_order = toolbar_model()->GetItemOrderForTab(web_contents); - ASSERT_EQ(3u, tab_order.size()); - EXPECT_EQ(browser_action(), tab_order[0].get()); - EXPECT_EQ(page_action(), tab_order[1].get()); - EXPECT_EQ(no_action(), tab_order[2].get()); - EXPECT_EQ(2u, toolbar_model()->GetVisibleIconCountForTab(web_contents)); - // We should also have been told to reorder the toolbar. - EXPECT_EQ(1u, observer()->reorder_count()); - - // This should not have any effect on the second tab, which should still have - // the original order and visible count. - tab_order = toolbar_model()->GetItemOrderForTab(second_web_contents); - ASSERT_EQ(3u, tab_order.size()); - EXPECT_EQ(browser_action(), tab_order[0].get()); - EXPECT_EQ(no_action(), tab_order[1].get()); - EXPECT_EQ(page_action(), tab_order[2].get()); - EXPECT_EQ(1u, - toolbar_model()->GetVisibleIconCountForTab(second_web_contents)); - - // Now, set the action to be hidden again, and notify of the change. - action->SetIsVisible(tab_id, false); - extension_action_api->NotifyChange(action, web_contents, profile()); - // The order and visible count should return to normal (the page action should - // move back to its original index in overflow). So, order should be "browser - // action", "no action", "page action". - tab_order = toolbar_model()->GetItemOrderForTab(web_contents); - ASSERT_EQ(3u, tab_order.size()); - EXPECT_EQ(browser_action(), tab_order[0].get()); - EXPECT_EQ(no_action(), tab_order[1].get()); - EXPECT_EQ(page_action(), tab_order[2].get()); - EXPECT_EQ(1u, toolbar_model()->GetVisibleIconCountForTab(web_contents)); - // This should also result in a reorder. - EXPECT_EQ(2u, observer()->reorder_count()); - - // Move page action to the first index (so it's naturally visible), and make - // it want to act. - toolbar_model()->MoveExtensionIcon(page_action()->id(), 0u); - action->SetIsVisible(tab_id, true); - extension_action_api->NotifyChange(action, web_contents, profile()); - // Since the action is already visible, this should have no effect - the order - // and visible count should remain unchanged. Order is "page action", "browser - // action", "no action". - tab_order = toolbar_model()->GetItemOrderForTab(web_contents); - ASSERT_EQ(3u, tab_order.size()); - EXPECT_EQ(page_action(), tab_order[0].get()); - EXPECT_EQ(browser_action(), tab_order[1].get()); - EXPECT_EQ(no_action(), tab_order[2].get()); - EXPECT_EQ(1u, toolbar_model()->GetVisibleIconCountForTab(web_contents)); - - // We should still be able to increase the size of the model, and to move the - // page action. - toolbar_model()->SetVisibleIconCount(2); - toolbar_model()->MoveExtensionIcon(page_action()->id(), 1u); - tab_order = toolbar_model()->GetItemOrderForTab(web_contents); - ASSERT_EQ(3u, tab_order.size()); - EXPECT_EQ(browser_action(), tab_order[0].get()); - EXPECT_EQ(page_action(), tab_order[1].get()); - EXPECT_EQ(no_action(), tab_order[2].get()); - EXPECT_EQ(2u, toolbar_model()->GetVisibleIconCountForTab(web_contents)); - - // Neither of the above operations should have precipitated a reorder. - EXPECT_EQ(2u, observer()->reorder_count()); - - // If we moved the page action, the move should remain in effect even after - // the action no longer wants to act. - action->SetIsVisible(tab_id, false); - extension_action_api->NotifyChange(action, web_contents, profile()); - tab_order = toolbar_model()->GetItemOrderForTab(web_contents); - ASSERT_EQ(3u, tab_order.size()); - EXPECT_EQ(browser_action(), tab_order[0].get()); - EXPECT_EQ(page_action(), tab_order[1].get()); - EXPECT_EQ(no_action(), tab_order[2].get()); - EXPECT_EQ(2u, toolbar_model()->GetVisibleIconCountForTab(web_contents)); - // The above change should *not* require a reorder, because the extension is - // in a new, visible spot and doesn't need to change its position. - EXPECT_EQ(2u, observer()->reorder_count()); - - // Test the edge case of having no icons visible. - toolbar_model()->SetVisibleIconCount(0); - EXPECT_EQ(0u, toolbar_model()->GetVisibleIconCountForTab(web_contents)); - action->SetIsVisible(tab_id, true); - extension_action_api->NotifyChange(action, web_contents, profile()); - tab_order = toolbar_model()->GetItemOrderForTab(web_contents); - ASSERT_EQ(3u, tab_order.size()); - EXPECT_EQ(page_action(), tab_order[0].get()); - EXPECT_EQ(browser_action(), tab_order[1].get()); - EXPECT_EQ(no_action(), tab_order[2].get()); - EXPECT_EQ(1u, toolbar_model()->GetVisibleIconCountForTab(web_contents)); - EXPECT_EQ(3u, observer()->reorder_count()); -} - // Test that observers receive no Added notifications until after the // ExtensionSystem has initialized. TEST_F(ExtensionToolbarModelUnitTest, ModelWaitsForExtensionSystemReady) { InitializeEmptyExtensionService(); ExtensionToolbarModel* toolbar_model = - CreateToolbarModelForProfile(profile(), false); + extension_action_test_util:: + CreateToolbarModelForProfileWithoutWaitingForReady(profile()); ExtensionToolbarModelTestObserver model_observer(toolbar_model); EXPECT_TRUE(AddBrowserActionExtensions());
diff --git a/chrome/browser/extensions/tab_helper.cc b/chrome/browser/extensions/tab_helper.cc index bb1a06d9..19100e4 100644 --- a/chrome/browser/extensions/tab_helper.cc +++ b/chrome/browser/extensions/tab_helper.cc
@@ -148,11 +148,7 @@ } bool TabHelper::CanCreateBookmarkApp() const { -#if defined(OS_MACOSX) - return false; -#else return IsValidBookmarkAppUrl(web_contents()->GetURL()); -#endif } void TabHelper::AddScriptExecutionObserver(ScriptExecutionObserver* observer) { @@ -295,7 +291,6 @@ } void TabHelper::OnDidGetWebApplicationInfo(const WebApplicationInfo& info) { -#if !defined(OS_MACOSX) web_app_info_ = info; NavigationEntry* entry = @@ -305,12 +300,14 @@ last_committed_page_id_ = -1; switch (pending_web_app_action_) { +#if !defined(OS_MACOSX) case CREATE_SHORTCUT: { chrome::ShowCreateWebAppShortcutsDialog( web_contents()->GetTopLevelNativeWindow(), web_contents()); break; } +#endif case CREATE_HOSTED_APP: { if (web_app_info_.app_url.is_empty()) web_app_info_.app_url = web_contents()->GetURL(); @@ -340,7 +337,6 @@ // fails. if (pending_web_app_action_ != CREATE_HOSTED_APP) pending_web_app_action_ = NONE; -#endif } void TabHelper::OnInlineWebstoreInstall(int install_id,
diff --git a/chrome/browser/extensions/updater/OWNERS b/chrome/browser/extensions/updater/OWNERS index f433f3f..c10d338 100644 --- a/chrome/browser/extensions/updater/OWNERS +++ b/chrome/browser/extensions/updater/OWNERS
@@ -1,3 +1,2 @@ asargent@chromium.org -joaodasilva@chromium.org mek@chromium.org
diff --git a/chrome/browser/feedback/show_feedback_page.cc b/chrome/browser/feedback/show_feedback_page.cc index 828dee0..e8fe488b 100644 --- a/chrome/browser/feedback/show_feedback_page.cc +++ b/chrome/browser/feedback/show_feedback_page.cc
@@ -8,7 +8,10 @@ #include "chrome/browser/extensions/api/feedback_private/feedback_private_api.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_manager.h" +#include "chrome/browser/ui/ash/multi_user/multi_user_util.h" +#include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h" #include "chrome/browser/ui/browser_finder.h" +#include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "content/public/browser/web_contents.h" #include "url/gurl.h" @@ -61,6 +64,20 @@ profile = profile->GetOriginalProfile(); DCHECK(profile); +#if defined(OS_CHROMEOS) + // Obtains the display profile ID on which the Feedback window should show. + chrome::MultiUserWindowManager* const window_manager = + chrome::MultiUserWindowManager::GetInstance(); + const std::string display_profile_id = + window_manager && browser + ? window_manager->GetUserPresentingWindow( + browser->window()->GetNativeWindow()) + : ""; + profile = display_profile_id.empty() + ? profile + : multi_user_util::GetProfileFromUserID(display_profile_id); +#endif + extensions::FeedbackPrivateAPI* api = extensions::FeedbackPrivateAPI::GetFactoryInstance()->Get(profile);
diff --git a/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc b/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc index 254b14e..c9025969 100644 --- a/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc +++ b/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.h" #include "base/json/json_string_value_serializer.h" +#include "base/prefs/pref_service.h" #include "base/sys_info.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/metrics/chrome_metrics_service_accessor.h" @@ -12,6 +13,7 @@ #include "chrome/browser/sync/about_sync_util.h" #include "chrome/browser/sync/profile_sync_service_factory.h" #include "chrome/common/chrome_version_info.h" +#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h" #include "content/public/browser/browser_thread.h" #include "extensions/browser/extension_registry.h" #include "extensions/common/extension.h" @@ -22,6 +24,7 @@ const char kSyncDataKey[] = "about_sync_data"; const char kExtensionsListKey[] = "extensions"; +const char kDataReductionProxyKey[] = "data_reduction_proxy"; const char kChromeVersionTag[] = "CHROME VERSION"; #if !defined(OS_CHROMEOS) const char kOsVersionTag[] = "OS VERSION"; @@ -56,6 +59,7 @@ PopulateSyncLogs(&response); PopulateExtensionInfoLogs(&response); + PopulateDataReductionProxyLogs(&response); callback.Run(&response); } @@ -126,4 +130,15 @@ (*response)[kExtensionsListKey] = extensions_list; } +void ChromeInternalLogSource::PopulateDataReductionProxyLogs( + SystemLogsResponse* response) { + PrefService* prefs = ProfileManager::GetActiveUserProfile()->GetPrefs(); + bool is_data_reduction_proxy_enabled = prefs->HasPrefPath( + data_reduction_proxy::prefs::kDataReductionProxyEnabled) && + prefs->GetBoolean( + data_reduction_proxy::prefs::kDataReductionProxyEnabled); + (*response)[kDataReductionProxyKey] = is_data_reduction_proxy_enabled ? + "enabled" : "disabled"; +} + } // namespace system_logs
diff --git a/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.h b/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.h index f533965..a4a7c61 100644 --- a/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.h +++ b/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.h
@@ -21,6 +21,7 @@ private: void PopulateSyncLogs(SystemLogsResponse* response); void PopulateExtensionInfoLogs(SystemLogsResponse* response); + void PopulateDataReductionProxyLogs(SystemLogsResponse* response); DISALLOW_COPY_AND_ASSIGN(ChromeInternalLogSource); };
diff --git a/chrome/browser/google/google_update_win.cc b/chrome/browser/google/google_update_win.cc index adeb33c..69ac3ac6 100644 --- a/chrome/browser/google/google_update_win.cc +++ b/chrome/browser/google/google_update_win.cc
@@ -8,15 +8,16 @@ #include <atlcom.h> #include "base/bind.h" +#include "base/callback.h" #include "base/files/file_path.h" -#include "base/message_loop/message_loop.h" +#include "base/location.h" #include "base/metrics/histogram.h" #include "base/metrics/sparse_histogram.h" #include "base/path_service.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" -#include "base/threading/thread.h" -#include "base/win/scoped_comptr.h" +#include "base/task_runner.h" +#include "base/thread_task_runner_handle.h" #include "base/win/windows_version.h" #include "chrome/grit/generated_resources.h" #include "chrome/installer/util/browser_distribution.h" @@ -24,25 +25,24 @@ #include "chrome/installer/util/helper.h" #include "chrome/installer/util/install_util.h" #include "content/public/browser/browser_thread.h" -#include "google_update/google_update_idl.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/win/atl_module.h" -#include "ui/views/widget/widget.h" - -using content::BrowserThread; namespace { +OnDemandAppsClassFactory* g_google_update_factory = nullptr; + // Check if the currently running instance can be updated by Google Update. // Returns GOOGLE_UPDATE_NO_ERROR only if the instance running is a Google // Chrome distribution installed in a standard location. GoogleUpdateErrorCode CanUpdateCurrentChrome( - const base::FilePath& chrome_exe_path) { + const base::FilePath& chrome_exe_path, + bool system_level) { #if !defined(GOOGLE_CHROME_BUILD) return CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY; #else - // TODO(tommi): Check if using the default distribution is always the right - // thing to do. + DCHECK_NE(InstallUtil::IsPerUserInstall(chrome_exe_path.value().c_str()), + system_level); BrowserDistribution* dist = BrowserDistribution::GetDistribution(); base::FilePath user_exe_path = installer::GetChromeInstallPath(false, dist); base::FilePath machine_exe_path = installer::GetChromeInstallPath(true, dist); @@ -50,16 +50,10 @@ user_exe_path.value()) && !base::FilePath::CompareEqualIgnoreCase(chrome_exe_path.value(), machine_exe_path.value())) { - LOG(ERROR) << L"Google Update cannot update Chrome installed in a " - << L"non-standard location: " << chrome_exe_path.value().c_str() - << L". The standard location is: " - << user_exe_path.value().c_str() - << L" or " << machine_exe_path.value().c_str() << L"."; return CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY; } - base::string16 app_guid = installer::GetAppGuidForUpdates( - !InstallUtil::IsPerUserInstall(chrome_exe_path.value().c_str())); + base::string16 app_guid = installer::GetAppGuidForUpdates(system_level); DCHECK(!app_guid.empty()); GoogleUpdateSettings::UpdatePolicy update_policy = @@ -80,15 +74,17 @@ // hwnd must refer to a foregound window in order to get the UAC prompt // showing up in the foreground if running on Vista. It can also be NULL if // background UAC prompts are desired. -HRESULT CoCreateInstanceAsAdmin(REFCLSID class_id, REFIID interface_id, - HWND hwnd, void** interface_ptr) { +HRESULT CoCreateInstanceAsAdmin(REFCLSID class_id, + REFIID interface_id, + gfx::AcceleratedWidget hwnd, + void** interface_ptr) { if (!interface_ptr) return E_POINTER; // For Vista, need to instantiate the COM server via the elevation // moniker. This ensures that the UAC dialog shows up. if (base::win::GetVersion() >= base::win::VERSION_VISTA) { - wchar_t class_id_as_string[MAX_PATH] = {0}; + wchar_t class_id_as_string[MAX_PATH] = {}; StringFromGUID2(class_id, class_id_as_string, arraysize(class_id_as_string)); @@ -96,125 +92,102 @@ base::StringPrintf(L"Elevation:Administrator!new:%ls", class_id_as_string); - BIND_OPTS3 bind_opts; - memset(&bind_opts, 0, sizeof(bind_opts)); + BIND_OPTS3 bind_opts = {}; bind_opts.cbStruct = sizeof(bind_opts); bind_opts.dwClassContext = CLSCTX_LOCAL_SERVER; bind_opts.hwnd = hwnd; - return CoGetObject(elevation_moniker_name.c_str(), &bind_opts, - interface_id, reinterpret_cast<void**>(interface_ptr)); + return CoGetObject(elevation_moniker_name.c_str(), &bind_opts, interface_id, + interface_ptr); } - return CoCreateInstance(class_id, NULL, CLSCTX_LOCAL_SERVER, - interface_id, - reinterpret_cast<void**>(interface_ptr)); + return CoCreateInstance(class_id, NULL, CLSCTX_LOCAL_SERVER, interface_id, + interface_ptr); +} + +HRESULT CreateOnDemandAppsClass( + bool system_level, + bool install_if_newer, + gfx::AcceleratedWidget elevation_window, + base::win::ScopedComPtr<IGoogleUpdate>* on_demand) { + if (g_google_update_factory) + return g_google_update_factory->Run(on_demand); + + // For a user-level install, update checks and updates can both be done by a + // normal user with the UserAppsClass. + if (!system_level) + return on_demand->CreateInstance(CLSID_OnDemandUserAppsClass); + + // For a system-level install, update checks can be done by a normal user with + // the MachineAppsClass. + if (!install_if_newer) + return on_demand->CreateInstance(CLSID_OnDemandMachineAppsClass); + + // For a system-level install, an update requires Admin privileges for writing + // to %ProgramFiles%. Elevate while instantiating the MachineAppsClass. + return CoCreateInstanceAsAdmin(CLSID_OnDemandMachineAppsClass, + IID_IGoogleUpdate, elevation_window, + on_demand->ReceiveVoid()); } -} // namespace +// GoogleUpdateJobObserver ----------------------------------------------------- // The GoogleUpdateJobObserver COM class is responsible for receiving status -// reports from google Update. It keeps track of the progress as GoogleUpdate -// notifies this observer and ends the message loop that is spinning in once -// GoogleUpdate reports that it is done. -class GoogleUpdateJobObserver - : public CComObjectRootEx<CComSingleThreadModel>, - public IJobObserver { +// reports from google Update. It keeps track of the progress as Google Update +// notifies this observer and runs a completion callback once Google Update +// reports that it is done. +class GoogleUpdateJobObserver : public CComObjectRootEx<CComSingleThreadModel>, + public IJobObserver { public: BEGIN_COM_MAP(GoogleUpdateJobObserver) COM_INTERFACE_ENTRY(IJobObserver) END_COM_MAP() - GoogleUpdateJobObserver() - : result_(UPGRADE_ERROR) { - } - virtual ~GoogleUpdateJobObserver() {} + GoogleUpdateJobObserver(); + virtual ~GoogleUpdateJobObserver(); - // Notifications from Google Update: - STDMETHOD(OnShow)() { - return S_OK; - } - STDMETHOD(OnCheckingForUpdate)() { - result_ = UPGRADE_CHECK_STARTED; - return S_OK; - } - STDMETHOD(OnUpdateAvailable)(const TCHAR* version_string) { - result_ = UPGRADE_IS_AVAILABLE; - new_version_ = version_string; - return S_OK; - } - STDMETHOD(OnWaitingToDownload)() { - return S_OK; - } - STDMETHOD(OnDownloading)(int time_remaining_ms, int pos) { - return S_OK; - } - STDMETHOD(OnWaitingToInstall)() { - return S_OK; - } - STDMETHOD(OnInstalling)() { - result_ = UPGRADE_STARTED; - return S_OK; - } - STDMETHOD(OnPause)() { - return S_OK; - } - STDMETHOD(OnComplete)(LegacyCompletionCodes code, const TCHAR* text) { - switch (code) { - case COMPLETION_CODE_SUCCESS_CLOSE_UI: - case COMPLETION_CODE_SUCCESS: { - if (result_ == UPGRADE_STARTED) - result_ = UPGRADE_SUCCESSFUL; - else if (result_ == UPGRADE_CHECK_STARTED) - result_ = UPGRADE_ALREADY_UP_TO_DATE; - break; - } - case COMPLETION_CODE_ERROR: - error_message_ = text; - default: { - NOTREACHED(); - result_ = UPGRADE_ERROR; - break; - } - } - - event_sink_ = NULL; - - // No longer need to spin the message loop that started spinning in - // InitiateGoogleUpdateCheck. - base::MessageLoop::current()->Quit(); - return S_OK; - } - STDMETHOD(SetEventSink)(IProgressWndEvents* event_sink) { - event_sink_ = event_sink; - return S_OK; + // Sets the callback to be invoked when Google Update reports that the job is + // done. + void set_on_complete_callback(const base::Closure& on_complete_callback) { + on_complete_callback_ = on_complete_callback; } // Returns the results of the update operation. - STDMETHOD(GetResult)(GoogleUpdateUpgradeResult* result) { + GoogleUpdateUpgradeResult result() const { // Intermediary steps should never be reported to the client. - DCHECK(result_ != UPGRADE_STARTED && result_ != UPGRADE_CHECK_STARTED); - - *result = result_; - return S_OK; + DCHECK_NE(UPGRADE_STARTED, result_); + DCHECK_NE(UPGRADE_CHECK_STARTED, result_); + return result_; } // Returns which version Google Update found on the server (if a more // recent version was found). Otherwise, this will be blank. - STDMETHOD(GetVersionInfo)(base::string16* version_string) { - *version_string = new_version_; - return S_OK; - } + base::string16 new_version() const { return new_version_; } // Returns the Google Update supplied error string that describes the error // that occurred during the update check/upgrade. - STDMETHOD(GetErrorMessage)(base::string16* error_message) { - *error_message = error_message_; - return S_OK; - } + base::string16 error_message() const { return error_message_; } private: + // IJobObserver: + STDMETHOD(OnShow)(); + STDMETHOD(OnCheckingForUpdate)(); + STDMETHOD(OnUpdateAvailable)(const TCHAR* version_string); + STDMETHOD(OnWaitingToDownload)(); + STDMETHOD(OnDownloading)(int time_remaining_ms, int pos); + STDMETHOD(OnWaitingToInstall)(); + STDMETHOD(OnInstalling)(); + STDMETHOD(OnPause)(); + STDMETHOD(OnComplete)(LegacyCompletionCodes code, const TCHAR* text); + STDMETHOD(SetEventSink)(IProgressWndEvents* event_sink); + + // The task runner associated with the thread in which the job runs. + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + + // A callback to be run to complete processing; + base::Closure on_complete_callback_; + // The status/result of the Google Update operation. GoogleUpdateUpgradeResult result_; @@ -227,195 +200,321 @@ // Allows us control the upgrade process to a small degree. After OnComplete // has been called, this object can not be used. base::win::ScopedComPtr<IProgressWndEvents> event_sink_; + + DISALLOW_COPY_AND_ASSIGN(GoogleUpdateJobObserver); }; -//////////////////////////////////////////////////////////////////////////////// -// GoogleUpdate, public: - -GoogleUpdate::GoogleUpdate() - : listener_(NULL) { +GoogleUpdateJobObserver::GoogleUpdateJobObserver() + : task_runner_(base::ThreadTaskRunnerHandle::Get()), + result_(UPGRADE_ERROR) { } -GoogleUpdate::~GoogleUpdate() { +GoogleUpdateJobObserver::~GoogleUpdateJobObserver() { } -void GoogleUpdate::CheckForUpdate(bool install_if_newer, HWND window) { - // Need to shunt this request over to InitiateGoogleUpdateCheck and have - // it run in the file thread. - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, - base::Bind(&GoogleUpdate::InitiateGoogleUpdateCheck, this, - install_if_newer, window, base::MessageLoop::current())); +STDMETHODIMP GoogleUpdateJobObserver::OnShow() { + return S_OK; } -//////////////////////////////////////////////////////////////////////////////// -// GoogleUpdate, private: +STDMETHODIMP GoogleUpdateJobObserver::OnCheckingForUpdate() { + result_ = UPGRADE_CHECK_STARTED; + return S_OK; +} -void GoogleUpdate::InitiateGoogleUpdateCheck(bool install_if_newer, - HWND window, - base::MessageLoop* main_loop) { +STDMETHODIMP GoogleUpdateJobObserver::OnUpdateAvailable( + const TCHAR* version_string) { + result_ = UPGRADE_IS_AVAILABLE; + new_version_ = version_string; + return S_OK; +} + +STDMETHODIMP GoogleUpdateJobObserver::OnWaitingToDownload() { + return S_OK; +} + +STDMETHODIMP GoogleUpdateJobObserver::OnDownloading(int time_remaining_ms, + int pos) { + return S_OK; +} + +STDMETHODIMP GoogleUpdateJobObserver::OnWaitingToInstall() { + return S_OK; +} + +STDMETHODIMP GoogleUpdateJobObserver::OnInstalling() { + result_ = UPGRADE_STARTED; + return S_OK; +} + +STDMETHODIMP GoogleUpdateJobObserver::OnPause() { + return S_OK; +} + +STDMETHODIMP GoogleUpdateJobObserver::OnComplete(LegacyCompletionCodes code, + const TCHAR* text) { + if (code == COMPLETION_CODE_ERROR) { + error_message_ = text; + result_ = UPGRADE_ERROR; + } else { + // Everything that isn't an error is some form of success. Chrome doesn't + // support any of the fancy codes (e.g., COMPLETION_CODE_REBOOT), but they + // shouldn't be generated anyway. + LOG_IF(DFATAL, (code != COMPLETION_CODE_SUCCESS && + code != COMPLETION_CODE_SUCCESS_CLOSE_UI)) + << "Unexpected LegacyCompletionCode from IGoogleUpdate: " << code; + if (result_ == UPGRADE_STARTED) + result_ = UPGRADE_SUCCESSFUL; + else if (result_ == UPGRADE_CHECK_STARTED) + result_ = UPGRADE_ALREADY_UP_TO_DATE; + } + + event_sink_ = NULL; + + task_runner_->PostTask(FROM_HERE, on_complete_callback_); + return S_OK; +} + +STDMETHODIMP GoogleUpdateJobObserver::SetEventSink( + IProgressWndEvents* event_sink) { + event_sink_ = event_sink; + return S_OK; +} + + +// UpdateCheckDriver ----------------------------------------------------------- + +// A driver that is created and destroyed on the caller's thread and drives +// Google Update on another. +class UpdateCheckDriver { + public: + // Runs an update check on |task_runner|, invoking |callback| on the caller's + // thread upon completion. |task_runner| must run a TYPE_UI message loop if + // the default IGoogleUpdate on-demand COM class is used. + static void RunUpdateCheck(const scoped_refptr<base::TaskRunner>& task_runner, + bool install_if_newer, + gfx::AcceleratedWidget elevation_window, + const UpdateCheckCallback& callback); + + private: + friend class base::DeleteHelper<UpdateCheckDriver>; + + explicit UpdateCheckDriver(const UpdateCheckCallback& callback); + + // Runs the caller's update check callback with the results of the operation. + ~UpdateCheckDriver(); + + // Starts an update check. + void BeginUpdateCheck(bool install_if_newer, + gfx::AcceleratedWidget elevation_window); + + // Helper function for starting an update check. Returns true if the check was + // properly started, in which case CompleteUpdateCheck will be invoked upon + // completion to return results to the caller on its own thread. + bool BeginUpdateCheckInternal(bool install_if_newer, + gfx::AcceleratedWidget elevation_window); + + // Invoked when results are in from Google Update. + void CompleteUpdateCheck(); + + // Prepares |results| to return the upgrade error indicated by |error_code| + // and |hr|. The string " -- system level" is included in the generated error + // message when |system_level| is true. + void OnUpgradeError(GoogleUpdateErrorCode error_code, + HRESULT hr, + bool system_level); + + // The caller's task runner, on which |result_callback_| will be run. + scoped_refptr<base::SingleThreadTaskRunner> result_runner_; + + // The caller's callback to be run when the update check is compelte. + UpdateCheckCallback result_callback_; + + // The results of the update check. + GoogleUpdateUpgradeResult result_; + GoogleUpdateErrorCode error_code_; + base::string16 error_message_; + base::string16 version_; + HRESULT hresult_; + + // A direct pointer to the job observer by which the driver is notified of + // interesting events from Google Update. + CComObject<GoogleUpdateJobObserver>* job_observer_; + + // A scoped pointer to |job_observer_| that holds a reference to it, keeping + // it alive. + base::win::ScopedComPtr<IJobObserver> job_holder_; + + // The on-demand updater that is doing the work. + base::win::ScopedComPtr<IGoogleUpdate> on_demand_; + + DISALLOW_COPY_AND_ASSIGN(UpdateCheckDriver); +}; + +// static +void UpdateCheckDriver::RunUpdateCheck( + const scoped_refptr<base::TaskRunner>& task_runner, + bool install_if_newer, + gfx::AcceleratedWidget elevation_window, + const UpdateCheckCallback& callback) { + // The driver is owned by itself, and will self-destruct when its work is + // done. + UpdateCheckDriver* driver = new UpdateCheckDriver(callback); + task_runner->PostTask( + FROM_HERE, + base::Bind(&UpdateCheckDriver::BeginUpdateCheck, base::Unretained(driver), + install_if_newer, elevation_window)); +} + +// Runs on the caller's thread. +UpdateCheckDriver::UpdateCheckDriver(const UpdateCheckCallback& callback) + : result_runner_(base::ThreadTaskRunnerHandle::Get()), + result_callback_(callback), + result_(UPGRADE_ERROR), + error_code_(GOOGLE_UPDATE_NO_ERROR), + hresult_(S_OK), + job_observer_(nullptr) { +} + +UpdateCheckDriver::~UpdateCheckDriver() { + DCHECK(result_runner_->BelongsToCurrentThread()); + // If there is an error, then error_code must not be blank, and vice versa. + DCHECK_NE(result_ == UPGRADE_ERROR, error_code_ == GOOGLE_UPDATE_NO_ERROR); + UMA_HISTOGRAM_ENUMERATION("GoogleUpdate.UpgradeResult", result_, + NUM_UPGRADE_RESULTS); + if (result_ == UPGRADE_ERROR) { + UMA_HISTOGRAM_ENUMERATION("GoogleUpdate.UpdateErrorCode", error_code_, + NUM_ERROR_CODES); + if (hresult_ != S_OK) + UMA_HISTOGRAM_SPARSE_SLOWLY("GoogleUpdate.ErrorHresult", hresult_); + } + result_callback_.Run(result_, error_code_, error_message_, version_); +} + +void UpdateCheckDriver::BeginUpdateCheck( + bool install_if_newer, + gfx::AcceleratedWidget elevation_window) { + // Return results immediately if the driver is not waiting for Google Update. + if (!BeginUpdateCheckInternal(install_if_newer, elevation_window)) + result_runner_->DeleteSoon(FROM_HERE, this); +} + +bool UpdateCheckDriver::BeginUpdateCheckInternal( + bool install_if_newer, + gfx::AcceleratedWidget elevation_window) { base::FilePath chrome_exe; if (!PathService::Get(base::DIR_EXE, &chrome_exe)) NOTREACHED(); - GoogleUpdateErrorCode error_code = CanUpdateCurrentChrome(chrome_exe); - if (error_code != GOOGLE_UPDATE_NO_ERROR) { - main_loop->PostTask( - FROM_HERE, - base::Bind(&GoogleUpdate::ReportResults, this, - UPGRADE_ERROR, error_code, base::string16())); - return; + const bool system_level = + !InstallUtil::IsPerUserInstall(chrome_exe.value().c_str()); + + // The failures handled here are: + // CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY, + // GOOGLE_UPDATE_DISABLED_BY_POLICY, and + // GOOGLE_UPDATE_DISABLED_BY_POLICY_AUTO_ONLY. + error_code_ = CanUpdateCurrentChrome(chrome_exe, system_level); + if (error_code_ != GOOGLE_UPDATE_NO_ERROR) { + // These failures are handled in the UX with custom messages. + result_ = UPGRADE_ERROR; + return false; } // Make sure ATL is initialized in this module. ui::win::CreateATLModuleIfNeeded(); - CComObject<GoogleUpdateJobObserver>* job_observer; HRESULT hr = - CComObject<GoogleUpdateJobObserver>::CreateInstance(&job_observer); + CComObject<GoogleUpdateJobObserver>::CreateInstance(&job_observer_); if (hr != S_OK) { // Most of the error messages come straight from Google Update. This one is // deemed worthy enough to also warrant its own error. - GoogleUpdateErrorCode error = GOOGLE_UPDATE_JOB_SERVER_CREATION_FAILED; - base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr); - ReportFailure( - hr, error, - l10n_util::GetStringFUTF16(IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED, - error_code), - main_loop); - return; + OnUpgradeError(GOOGLE_UPDATE_JOB_SERVER_CREATION_FAILED, hr, false); + return false; } + // Hold a reference on the observer for the lifetime of the driver. + job_holder_ = job_observer_; - base::win::ScopedComPtr<IJobObserver> job_holder(job_observer); + job_observer_->set_on_complete_callback(base::Bind( + &UpdateCheckDriver::CompleteUpdateCheck, base::Unretained(this))); - base::win::ScopedComPtr<IGoogleUpdate> on_demand; - - bool system_level = false; - - if (InstallUtil::IsPerUserInstall(chrome_exe.value().c_str())) { - hr = on_demand.CreateInstance(CLSID_OnDemandUserAppsClass); - } else { - // The Update operation needs Admin privileges for writing - // to %ProgramFiles%. On Vista, need to elevate before instantiating - // the updater instance. - if (!install_if_newer) { - hr = on_demand.CreateInstance(CLSID_OnDemandMachineAppsClass); - } else { - hr = CoCreateInstanceAsAdmin(CLSID_OnDemandMachineAppsClass, - IID_IGoogleUpdate, window, - reinterpret_cast<void**>(on_demand.Receive())); - } - system_level = true; - } - + hr = CreateOnDemandAppsClass(system_level, install_if_newer, elevation_window, + &on_demand_); if (hr != S_OK) { - GoogleUpdateErrorCode error = GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND; - base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr); - if (system_level) - error_code += L" -- system level"; - ReportFailure(hr, error, - l10n_util::GetStringFUTF16( - IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED, - error_code), - main_loop); - return; + OnUpgradeError(GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND, hr, system_level); + return false; } base::string16 app_guid = installer::GetAppGuidForUpdates(system_level); DCHECK(!app_guid.empty()); - if (!install_if_newer) - hr = on_demand->CheckForUpdate(app_guid.c_str(), job_observer); + if (install_if_newer) + hr = on_demand_->Update(app_guid.c_str(), job_observer_); else - hr = on_demand->Update(app_guid.c_str(), job_observer); + hr = on_demand_->CheckForUpdate(app_guid.c_str(), job_observer_); if (hr != S_OK) { - GoogleUpdateErrorCode error = GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR; - base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr); - ReportFailure(hr, error, - l10n_util::GetStringFUTF16( - IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED, - error_code), - main_loop); - return; + OnUpgradeError(GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR, hr, + system_level); + return false; } - - // Need to spin the message loop while Google Update is running so that it - // can report back to us through GoogleUpdateJobObserver. This message loop - // will terminate once Google Update sends us the completion status - // (success/error). See OnComplete(). - base::MessageLoop::current()->Run(); - - GoogleUpdateUpgradeResult results; - hr = job_observer->GetResult(&results); - - if (hr != S_OK) { - GoogleUpdateErrorCode error = GOOGLE_UPDATE_GET_RESULT_CALL_FAILED; - base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr); - ReportFailure(hr, error, - l10n_util::GetStringFUTF16( - IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED, - error_code), - main_loop); - return; - } - - if (results == UPGRADE_ERROR) { - base::string16 error_message; - job_observer->GetErrorMessage(&error_message); - ReportFailure(hr, GOOGLE_UPDATE_ERROR_UPDATING, error_message, main_loop); - return; - } - - hr = job_observer->GetVersionInfo(&version_available_); - if (hr != S_OK) { - GoogleUpdateErrorCode error = GOOGLE_UPDATE_GET_VERSION_INFO_FAILED; - base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr); - ReportFailure(hr, error, - l10n_util::GetStringFUTF16( - IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED, - error_code), - main_loop); - return; - } - - main_loop->PostTask( - FROM_HERE, - base::Bind(&GoogleUpdate::ReportResults, this, - results, GOOGLE_UPDATE_NO_ERROR, base::string16())); - job_holder = NULL; - on_demand = NULL; + return true; } -void GoogleUpdate::ReportResults(GoogleUpdateUpgradeResult results, - GoogleUpdateErrorCode error_code, - const base::string16& error_message) { - // If there is an error, then error code must not be blank, and vice versa. - DCHECK(results == UPGRADE_ERROR ? error_code != GOOGLE_UPDATE_NO_ERROR : - error_code == GOOGLE_UPDATE_NO_ERROR); - UMA_HISTOGRAM_ENUMERATION( - "GoogleUpdate.UpgradeResult", results, NUM_UPGRADE_RESULTS); - if (results == UPGRADE_ERROR) { - UMA_HISTOGRAM_ENUMERATION( - "GoogleUpdate.UpdateErrorCode", error_code, NUM_ERROR_CODES); +void UpdateCheckDriver::CompleteUpdateCheck() { + result_ = job_observer_->result(); + if (result_ == UPGRADE_ERROR) { + error_code_ = GOOGLE_UPDATE_ERROR_UPDATING; + error_message_ = job_observer_->error_message(); + } else { + version_ = job_observer_->new_version(); } - if (listener_) { - listener_->OnReportResults( - results, error_code, error_message, version_available_); - } + + // Release the reference on the COM objects before bouncing back to the + // caller's thread. + on_demand_.Release(); + job_holder_.Release(); + job_observer_ = nullptr; + + result_runner_->DeleteSoon(FROM_HERE, this); } -bool GoogleUpdate::ReportFailure(HRESULT hr, - GoogleUpdateErrorCode error_code, - const base::string16& error_message, - base::MessageLoop* main_loop) { - DLOG(ERROR) << "Communication with Google Update failed: " << hr - << " error: " << error_code - << ", message: " << error_message.c_str(); - UMA_HISTOGRAM_SPARSE_SLOWLY("GoogleUpdate.ErrorHresult", hr); - main_loop->PostTask( - FROM_HERE, - base::Bind(&GoogleUpdate::ReportResults, this, - UPGRADE_ERROR, error_code, error_message)); - return false; +void UpdateCheckDriver::OnUpgradeError(GoogleUpdateErrorCode error_code, + HRESULT hr, + bool system_level) { + result_ = UPGRADE_ERROR; + error_code_ = error_code; + hresult_ = hr; + base::string16 error_msg = + base::StringPrintf(L"%d: 0x%x", error_code_, hresult_); + if (system_level) + error_msg += L" -- system level"; + error_message_ = l10n_util::GetStringFUTF16( + IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED, error_msg); +} + +} // namespace + + +// Globals --------------------------------------------------------------------- + +void BeginUpdateCheck(const scoped_refptr<base::TaskRunner>& task_runner, + bool install_if_newer, + gfx::AcceleratedWidget elevation_window, + const UpdateCheckCallback& callback) { + UpdateCheckDriver::RunUpdateCheck(task_runner, install_if_newer, + elevation_window, callback); +} + + +// Private API exposed for testing. -------------------------------------------- + +void SetGoogleUpdateFactoryForTesting( + const OnDemandAppsClassFactory& google_update_factory) { + if (g_google_update_factory) { + delete g_google_update_factory; + g_google_update_factory = nullptr; + } + if (!google_update_factory.is_null()) { + g_google_update_factory = + new OnDemandAppsClassFactory(google_update_factory); + } }
diff --git a/chrome/browser/google/google_update_win.h b/chrome/browser/google/google_update_win.h index 659f393..75119e8 100644 --- a/chrome/browser/google/google_update_win.h +++ b/chrome/browser/google/google_update_win.h
@@ -6,17 +6,16 @@ #define CHROME_BROWSER_GOOGLE_GOOGLE_UPDATE_WIN_H_ #include "base/basictypes.h" +#include "base/callback_forward.h" #include "base/memory/ref_counted.h" #include "base/strings/string16.h" +#include "base/win/scoped_comptr.h" #include "google_update/google_update_idl.h" +#include "ui/gfx/native_widget_types.h" namespace base { -class MessageLoop; -} - -namespace views { -class Widget; -} +class TaskRunner; +} // namespace base // The status of the upgrade. UPGRADE_STARTED and UPGRADE_CHECK_STARTED are // internal states and will not be reported as results to the listener. @@ -52,10 +51,10 @@ // Google Update OnDemand COM class reported an error during a check for // update (or while upgrading). GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR = 4, - // A call to GetResults failed. - GOOGLE_UPDATE_GET_RESULT_CALL_FAILED = 5, - // A call to GetVersionInfo failed. - GOOGLE_UPDATE_GET_VERSION_INFO_FAILED = 6, + // A call to GetResults failed. DEPRECATED. + // GOOGLE_UPDATE_GET_RESULT_CALL_FAILED = 5, + // A call to GetVersionInfo failed. DEPRECATED + // GOOGLE_UPDATE_GET_VERSION_INFO_FAILED = 6, // An error occurred while upgrading (or while checking for update). // Check the Google Update log in %TEMP% for more details. GOOGLE_UPDATE_ERROR_UPDATING = 7, @@ -68,84 +67,34 @@ NUM_ERROR_CODES }; -// The GoogleUpdateStatusListener interface is used by components to receive -// notifications about the results of an Google Update operation. -class GoogleUpdateStatusListener { - public: - // This function is called when Google Update has finished its operation and - // wants to notify us about the results. |results| represents what the end - // state is, |error_code| represents what error occurred, |error_message| is a - // string version of the same (might be blank) and |version| specifies what - // new version Google Update detected (or installed). This value can be a - // blank string, if the version tag in the Update{} block (in Google Update's - // server config for Chrome) is blank. - virtual void OnReportResults(GoogleUpdateUpgradeResult results, - GoogleUpdateErrorCode error_code, - const base::string16& error_message, - const base::string16& version) = 0; -}; +// A callback run when a check for updates has completed. |result| indicates the +// end state of the operation. When |result| is UPGRADE_ERROR, |error_code| and +// |error_message| indicate the the nature of the error. When |result| is +// UPGRADE_IS_AVAILABLE or UPGRADE_SUCCESSFUL, |version| may indicate the new +// version Google Update detected (it may, however, be empty). +typedef base::Callback<void(GoogleUpdateUpgradeResult result, + GoogleUpdateErrorCode error_code, + const base::string16& error_message, + const base::string16& version)> UpdateCheckCallback; -//////////////////////////////////////////////////////////////////////////////// -// -// The Google Update class is responsible for communicating with Google Update -// and get it to perform operations on our behalf (for example, CheckForUpdate). -// This class will report back to its parent via the GoogleUpdateStatusListener -// interface and will delete itself after reporting back. -// -//////////////////////////////////////////////////////////////////////////////// -class GoogleUpdate : public base::RefCountedThreadSafe<GoogleUpdate> { - public: - GoogleUpdate(); +// Begins an asynchronous update check on |task_runner|, which must run a +// TYPE_UI message loop. If |install_if_newer| is true, an update will be +// applied. |elevation_window| is the window which should own any necessary +// elevation UI. |callback| will be run on the caller's thread when the check +// completes. +void BeginUpdateCheck(const scoped_refptr<base::TaskRunner>& task_runner, + bool install_if_newer, + gfx::AcceleratedWidget elevation_window, + const UpdateCheckCallback& callback); - // Ask Google Update to see if a new version is available. If the parameter - // |install_if_newer| is true then Google Update will also install that new - // version. - // |window| should point to a foreground window. This is needed to ensure - // that Vista/Windows 7 UAC prompts show up in the foreground. It may also - // be null. - void CheckForUpdate(bool install_if_newer, HWND window); +// A type of callback supplied by tests to provide a custom IGoogleUpdate +// implementation. +typedef base::Callback<HRESULT(base::win::ScopedComPtr<IGoogleUpdate>*)> + OnDemandAppsClassFactory; - // Pass NULL to clear the listener - void set_status_listener(GoogleUpdateStatusListener* listener) { - listener_ = listener; - } - - private: - friend class base::RefCountedThreadSafe<GoogleUpdate>; - - virtual ~GoogleUpdate(); - - // This function reports failure from the Google Update operation to the - // listener. - // Note, after this function completes, this object will have deleted itself. - bool ReportFailure(HRESULT hr, GoogleUpdateErrorCode error_code, - const base::string16& error_message, - base::MessageLoop* main_loop); - - // The update check needs to run on another thread than the main thread, and - // therefore CheckForUpdate will delegate to this function. |main_loop| points - // to the message loop that the response must come from. - // |window| should point to a foreground window. This is needed to ensure that - // Vista/Windows 7 UAC prompts show up in the foreground. It may also be null. - void InitiateGoogleUpdateCheck(bool install_if_newer, HWND window, - base::MessageLoop* main_loop); - - // This function reports the results of the GoogleUpdate operation to the - // listener. If results indicates an error, the |error_code| and - // |error_message| will indicate which error occurred. - // Note, after this function completes, this object will have deleted itself. - void ReportResults(GoogleUpdateUpgradeResult results, - GoogleUpdateErrorCode error_code, - const base::string16& error_message); - - // Which version string Google Update found (if a new one was available). - // Otherwise, this will be blank. - base::string16 version_available_; - - // The listener who is interested in finding out the result of the operation. - GoogleUpdateStatusListener* listener_; - - DISALLOW_COPY_AND_ASSIGN(GoogleUpdate); -}; +// For use by tests that wish to provide a custom IGoogleUpdate implementation +// independent of Google Update's. +void SetGoogleUpdateFactoryForTesting( + const OnDemandAppsClassFactory& google_update_factory); #endif // CHROME_BROWSER_GOOGLE_GOOGLE_UPDATE_WIN_H_
diff --git a/chrome/browser/google/google_update_win_unittest.cc b/chrome/browser/google/google_update_win_unittest.cc new file mode 100644 index 0000000..82f2e69 --- /dev/null +++ b/chrome/browser/google/google_update_win_unittest.cc
@@ -0,0 +1,580 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/google/google_update_win.h" + +#include <windows.h> +#include <atlbase.h> +#include <atlcom.h> + +#include <queue> + +#include "base/base_paths.h" +#include "base/memory/ref_counted.h" +#include "base/path_service.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/stringprintf.h" +#include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_path_override.h" +#include "base/test/test_reg_util_win.h" +#include "base/test/test_simple_task_runner.h" +#include "base/thread_task_runner_handle.h" +#include "base/version.h" +#include "base/win/registry.h" +#include "chrome/installer/util/browser_distribution.h" +#include "chrome/installer/util/google_update_settings.h" +#include "chrome/installer/util/helper.h" +#include "google_update/google_update_idl.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/win/atl_module.h" +#include "version.h" + +using ::testing::DoAll; +using ::testing::Invoke; +using ::testing::IsEmpty; +using ::testing::Return; +using ::testing::SetArgPointee; +using ::testing::StrEq; +using ::testing::Unused; +using ::testing::Values; +using ::testing::_; + +namespace { + +class UpdateCheckCallbackReceiver { + public: + UpdateCheckCallbackReceiver() {} + virtual ~UpdateCheckCallbackReceiver() {} + virtual void OnUpdateCheckCallback(GoogleUpdateUpgradeResult result, + GoogleUpdateErrorCode error_code, + const base::string16& error_message, + const base::string16& version) = 0; + UpdateCheckCallback GetCallback() { + return base::Bind(&UpdateCheckCallbackReceiver::UpdateCheckCallback, + base::Unretained(this)); + } + + private: + void UpdateCheckCallback(GoogleUpdateUpgradeResult result, + GoogleUpdateErrorCode error_code, + const base::string16& error_message, + const base::string16& version) { + OnUpdateCheckCallback(result, error_code, error_message, version); + } + + DISALLOW_COPY_AND_ASSIGN(UpdateCheckCallbackReceiver); +}; + +class MockUpdateCheckCallbackReceiver : public UpdateCheckCallbackReceiver { + public: + MockUpdateCheckCallbackReceiver() {} + MOCK_METHOD4(OnUpdateCheckCallback, + void(GoogleUpdateUpgradeResult, + GoogleUpdateErrorCode, + const base::string16&, + const base::string16&)); + + private: + DISALLOW_COPY_AND_ASSIGN(MockUpdateCheckCallbackReceiver); +}; + +class GoogleUpdateFactory { + public: + virtual ~GoogleUpdateFactory() {} + virtual HRESULT Create(base::win::ScopedComPtr<IGoogleUpdate>* on_demand) = 0; +}; + +class MockGoogleUpdateFactory : public GoogleUpdateFactory { + public: + MockGoogleUpdateFactory() {} + MOCK_METHOD1(Create, HRESULT(base::win::ScopedComPtr<IGoogleUpdate>*)); + + private: + DISALLOW_COPY_AND_ASSIGN(MockGoogleUpdateFactory); +}; + +// A mock IGoogleUpdate on-demand update class that can run an IJobObserver +// through a set of states. +class MockOnDemand : public CComObjectRootEx<CComSingleThreadModel>, + public IGoogleUpdate { + public: + BEGIN_COM_MAP(MockOnDemand) + COM_INTERFACE_ENTRY(IGoogleUpdate) + END_COM_MAP() + + MockOnDemand() : task_runner_(base::ThreadTaskRunnerHandle::Get()) {} + + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, + CheckForUpdate, + HRESULT(const wchar_t*, IJobObserver*)); + MOCK_METHOD2_WITH_CALLTYPE(STDMETHODCALLTYPE, + Update, + HRESULT(const wchar_t*, IJobObserver*)); + + void OnCheckRunUpToDateSequence(const base::char16* app_guid) { + EXPECT_CALL(*this, CheckForUpdate(StrEq(app_guid), _)) + .WillOnce(DoAll(Invoke(this, &MockOnDemand::BeginUpToDateSequence), + Return(S_OK))); + } + + void OnCheckRunUpdateAvailableSequence(const base::char16* app_guid, + const base::string16& new_version) { + new_version_ = new_version; + EXPECT_CALL(*this, CheckForUpdate(StrEq(app_guid), _)) + .WillOnce( + DoAll(Invoke(this, &MockOnDemand::BeginUpdateAvailableSequence), + Return(S_OK))); + } + + void OnUpdateRunInstallUpdateSequence(const base::char16* app_guid, + const base::string16& new_version) { + new_version_ = new_version; + EXPECT_CALL(*this, Update(StrEq(app_guid), _)) + .WillOnce(DoAll(Invoke(this, &MockOnDemand::BeginInstallUpdateSequence), + Return(S_OK))); + } + + void OnUpdateRunUpdateErrorSequence(const base::char16* app_guid, + const base::char16* error_text) { + error_text_ = error_text; + EXPECT_CALL(*this, Update(StrEq(app_guid), _)) + .WillOnce(DoAll(Invoke(this, &MockOnDemand::BeginUpdateErrorSequence), + Return(S_OK))); + } + + private: + enum State { + STATE_CHECKING, + STATE_COMPLETE_SUCCESS, + STATE_UPDATE_AVAILABLE, + STATE_WAITING_TO_DOWNLOAD, + STATE_DOWNLOADING_25, + STATE_DOWNLOADING_100, + STATE_WAITING_TO_INSTALL, + STATE_INSTALLING, + STATE_COMPLETE_ERROR, + }; + + void BeginUpToDateSequence(Unused, IJobObserver* job_observer_ptr) { + job_observer_ = job_observer_ptr; + states_.push(STATE_CHECKING); + states_.push(STATE_COMPLETE_SUCCESS); + task_runner_->PostTask( + FROM_HERE, base::Bind(&MockOnDemand::Advance, base::Unretained(this))); + } + + void BeginUpdateAvailableSequence(Unused, IJobObserver* job_observer_ptr) { + job_observer_ = job_observer_ptr; + states_.push(STATE_CHECKING); + states_.push(STATE_UPDATE_AVAILABLE); + states_.push(STATE_COMPLETE_SUCCESS); + task_runner_->PostTask( + FROM_HERE, base::Bind(&MockOnDemand::Advance, base::Unretained(this))); + } + + void BeginInstallUpdateSequence(Unused, IJobObserver* job_observer_ptr) { + job_observer_ = job_observer_ptr; + states_.push(STATE_CHECKING); + states_.push(STATE_UPDATE_AVAILABLE); + states_.push(STATE_WAITING_TO_DOWNLOAD); + states_.push(STATE_DOWNLOADING_25); + states_.push(STATE_DOWNLOADING_100); + states_.push(STATE_WAITING_TO_INSTALL); + states_.push(STATE_INSTALLING); + states_.push(STATE_COMPLETE_SUCCESS); + task_runner_->PostTask( + FROM_HERE, base::Bind(&MockOnDemand::Advance, base::Unretained(this))); + } + + void BeginUpdateErrorSequence(Unused, IJobObserver* job_observer_ptr) { + job_observer_ = job_observer_ptr; + states_.push(STATE_CHECKING); + states_.push(STATE_UPDATE_AVAILABLE); + states_.push(STATE_WAITING_TO_DOWNLOAD); + states_.push(STATE_DOWNLOADING_25); + states_.push(STATE_DOWNLOADING_100); + states_.push(STATE_WAITING_TO_INSTALL); + states_.push(STATE_INSTALLING); + states_.push(STATE_COMPLETE_ERROR); + task_runner_->PostTask( + FROM_HERE, base::Bind(&MockOnDemand::Advance, base::Unretained(this))); + } + + // Advance to the next state. If this state is non-terminal, a task is posted + // to advance to the next state a bit later. + void Advance() { + ASSERT_FALSE(states_.empty()); + switch (states_.front()) { + case STATE_CHECKING: + EXPECT_EQ(S_OK, job_observer_->OnCheckingForUpdate()); + break; + case STATE_COMPLETE_SUCCESS: + EXPECT_EQ(S_OK, + job_observer_->OnComplete(COMPLETION_CODE_SUCCESS, nullptr)); + break; + case STATE_UPDATE_AVAILABLE: + EXPECT_EQ(S_OK, job_observer_->OnUpdateAvailable(new_version_.c_str())); + break; + case STATE_WAITING_TO_DOWNLOAD: + EXPECT_EQ(S_OK, job_observer_->OnWaitingToDownload()); + break; + case STATE_DOWNLOADING_25: + EXPECT_EQ(S_OK, job_observer_->OnDownloading(47, 25)); + break; + case STATE_DOWNLOADING_100: + EXPECT_EQ(S_OK, job_observer_->OnDownloading(42, 100)); + break; + case STATE_WAITING_TO_INSTALL: + EXPECT_EQ(S_OK, job_observer_->OnWaitingToInstall()); + break; + case STATE_INSTALLING: + EXPECT_EQ(S_OK, job_observer_->OnInstalling()); + break; + case STATE_COMPLETE_ERROR: + EXPECT_EQ(S_OK, job_observer_->OnComplete(COMPLETION_CODE_ERROR, + error_text_.c_str())); + break; + } + states_.pop(); + if (states_.empty()) { + // Drop the reference to the observer when the terminal state is reached. + job_observer_ = nullptr; + } else { + task_runner_->PostTask(FROM_HERE, base::Bind(&MockOnDemand::Advance, + base::Unretained(this))); + } + } + + // The task runner on which the state machine runs. + scoped_refptr<base::TaskRunner> task_runner_; + + // The new version for a successful update check or update. + base::string16 new_version_; + + // Error text to be supplied for an unsuccessful update check or update. + base::string16 error_text_; + + // The set of states to be run on an IJobObserver. + std::queue<State> states_; + + // The IJobObserver given to either CheckForUpdate() or Update() that is being + // driven through the desired state transitions. + base::win::ScopedComPtr<IJobObserver> job_observer_; + + DISALLOW_COPY_AND_ASSIGN(MockOnDemand); +}; + +} // namespace + +class GoogleUpdateWinTest : public ::testing::TestWithParam<bool> { + public: + static void SetUpTestCase() { ui::win::CreateATLModuleIfNeeded(); } + + protected: + GoogleUpdateWinTest() + : task_runner_(new base::TestSimpleTaskRunner()), + task_runner_handle_(task_runner_), + system_level_(GetParam()), + mock_on_demand_(nullptr) {} + + void SetUp() override { + ::testing::TestWithParam<bool>::SetUp(); + + // Override FILE_EXE so that it looks like the test is running from the + // standard install location for this mode (system-level or user-level). + base::FilePath file_exe; + ASSERT_TRUE(PathService::Get(base::FILE_EXE, &file_exe)); + base::FilePath install_dir(installer::GetChromeInstallPath( + system_level_, BrowserDistribution::GetDistribution())); + file_exe_override_.reset(new base::ScopedPathOverride( + base::FILE_EXE, install_dir.Append(file_exe.BaseName()), + true /* is_absolute */, false /* create */)); + + // Override these paths so that they can be found after the registry + // override manager is in place. + base::FilePath temp; + PathService::Get(base::DIR_PROGRAM_FILES, &temp); + program_files_override_.reset( + new base::ScopedPathOverride(base::DIR_PROGRAM_FILES, temp)); + PathService::Get(base::DIR_PROGRAM_FILESX86, &temp); + program_files_x86_override_.reset( + new base::ScopedPathOverride(base::DIR_PROGRAM_FILESX86, temp)); + PathService::Get(base::DIR_LOCAL_APP_DATA, &temp); + local_app_data_override_.reset( + new base::ScopedPathOverride(base::DIR_LOCAL_APP_DATA, temp)); + + // Override the registry so that tests can freely push state to it. + registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER); + registry_override_manager_.OverrideRegistry(HKEY_LOCAL_MACHINE); + + // Chrome is installed as multi-install. + const HKEY root = system_level_ ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; + base::win::RegKey key(root, kClients, KEY_WRITE | KEY_WOW64_32KEY); + ASSERT_EQ(ERROR_SUCCESS, + key.CreateKey(kChromeGuid, KEY_WRITE | KEY_WOW64_32KEY)); + ASSERT_EQ(ERROR_SUCCESS, + key.WriteValue( + L"pv", base::ASCIIToUTF16(CHROME_VERSION_STRING).c_str())); + ASSERT_EQ(ERROR_SUCCESS, + key.Create(root, kClientState, KEY_WRITE | KEY_WOW64_32KEY)); + ASSERT_EQ(ERROR_SUCCESS, + key.CreateKey(kChromeGuid, KEY_WRITE | KEY_WOW64_32KEY)); + ASSERT_EQ(ERROR_SUCCESS, + key.WriteValue(L"UninstallArguments", + L"--uninstall --multi-install --chrome")); + + // Provide an IGoogleUpdate on-demand update class factory so that this test + // can provide a mocked-out instance. + SetGoogleUpdateFactoryForTesting( + base::Bind(&GoogleUpdateFactory::Create, + base::Unretained(&mock_google_update_factory_))); + // Configure the factory to return a generic failure by default. + ON_CALL(mock_google_update_factory_, Create(_)) + .WillByDefault(Return(E_FAIL)); + + // Create a mock IGoogleUpdate on-demand update class + ASSERT_EQ(S_OK, CComObject<MockOnDemand>::CreateInstance(&mock_on_demand_)); + on_demand_holder_ = mock_on_demand_; + // Configure the mock to return a generic failure by default. + ON_CALL(*mock_on_demand_, CheckForUpdate(_, _)) + .WillByDefault(Return(E_FAIL)); + ON_CALL(*mock_on_demand_, Update(_, _)).WillByDefault(Return(E_FAIL)); + + // Compute a newer version. + base::Version current_version(CHROME_VERSION_STRING); + new_version_ = base::StringPrintf(L"%hu.%hu.%hu.%hu", + current_version.components()[0], + current_version.components()[1], + current_version.components()[2] + 1, + current_version.components()[3]); + } + + void TearDown() override { + // Remove the test's IGoogleUpdate on-demand update class factory. + SetGoogleUpdateFactoryForTesting(OnDemandAppsClassFactory()); + } + + // Set the default update policy in the registry. + void SetDefaultUpdatePolicy(GoogleUpdateSettings::UpdatePolicy policy) const { + base::win::RegKey policy_key(HKEY_LOCAL_MACHINE, kPoliciesKey, + KEY_SET_VALUE); + ASSERT_EQ(ERROR_SUCCESS, policy_key.WriteValue(kUpdateDefault, policy)); + } + + // Stuffs |policy| in the registry for the app identified by |app_guid|. + void SetAppUpdatePolicy(const base::char16* app_guid, + GoogleUpdateSettings::UpdatePolicy policy) const { + base::string16 value_name(L"Update"); + value_name += app_guid; + base::win::RegKey policy_key(HKEY_LOCAL_MACHINE, kPoliciesKey, + KEY_SET_VALUE); + ASSERT_EQ(ERROR_SUCCESS, policy_key.WriteValue(value_name.c_str(), policy)); + } + + static const base::char16 kPoliciesKey[]; + static const base::char16 kUpdateDefault[]; + static const base::char16 kClients[]; + static const base::char16 kClientState[]; + static const base::char16 kChromeGuid[]; + static const base::char16 kChromeBinariesGuid[]; + + scoped_refptr<base::TestSimpleTaskRunner> task_runner_; + base::ThreadTaskRunnerHandle task_runner_handle_; + bool system_level_; + scoped_ptr<base::ScopedPathOverride> file_exe_override_; + scoped_ptr<base::ScopedPathOverride> program_files_override_; + scoped_ptr<base::ScopedPathOverride> program_files_x86_override_; + scoped_ptr<base::ScopedPathOverride> local_app_data_override_; + registry_util::RegistryOverrideManager registry_override_manager_; + MockUpdateCheckCallbackReceiver callback_receiver_; + MockGoogleUpdateFactory mock_google_update_factory_; + CComObject<MockOnDemand>* mock_on_demand_; + base::win::ScopedComPtr<IGoogleUpdate> on_demand_holder_; + base::string16 new_version_; + + DISALLOW_COPY_AND_ASSIGN(GoogleUpdateWinTest); +}; + +// static +const base::char16 GoogleUpdateWinTest::kPoliciesKey[] = + L"SOFTWARE\\Policies\\Google\\Update"; +const base::char16 GoogleUpdateWinTest::kUpdateDefault[] = L"UpdateDefault"; +const base::char16 GoogleUpdateWinTest::kClients[] = + L"Software\\Google\\Update\\Clients"; +const base::char16 GoogleUpdateWinTest::kClientState[] = + L"Software\\Google\\Update\\ClientState"; +const base::char16 GoogleUpdateWinTest::kChromeGuid[] = + L"{8A69D345-D564-463c-AFF1-A69D9E530F96}"; +const base::char16 GoogleUpdateWinTest::kChromeBinariesGuid[] = + L"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}"; + +// Test that an update check fails with the proper error code if Chrome isn't in +// one of the expected install directories. +TEST_P(GoogleUpdateWinTest, InvalidInstallDirectory) { + // Override FILE_EXE so that it looks like the test is running from a + // non-standard location. + base::FilePath file_exe; + base::FilePath dir_temp; + ASSERT_TRUE(PathService::Get(base::FILE_EXE, &file_exe)); + ASSERT_TRUE(PathService::Get(base::DIR_TEMP, &dir_temp)); + file_exe_override_.reset(); + file_exe_override_.reset(new base::ScopedPathOverride( + base::FILE_EXE, dir_temp.Append(file_exe.BaseName()), + true /* is_absolute */, false /* create */)); + + EXPECT_CALL( + callback_receiver_, + OnUpdateCheckCallback(UPGRADE_ERROR, + CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY, _, _)); + BeginUpdateCheck(task_runner_, false, 0, callback_receiver_.GetCallback()); + task_runner_->RunUntilIdle(); +} + +#if defined(GOOGLE_CHROME_BUILD) + +TEST_P(GoogleUpdateWinTest, AllUpdatesDisabledByPolicy) { + // Disable updates altogether. + SetDefaultUpdatePolicy(GoogleUpdateSettings::UPDATES_DISABLED); + + EXPECT_CALL(callback_receiver_, + OnUpdateCheckCallback(UPGRADE_ERROR, + GOOGLE_UPDATE_DISABLED_BY_POLICY, _, _)); + BeginUpdateCheck(task_runner_, false, 0, callback_receiver_.GetCallback()); + task_runner_->RunUntilIdle(); +} + +TEST_P(GoogleUpdateWinTest, MultiUpdatesDisabledByPolicy) { + // Disable updates altogether. + SetAppUpdatePolicy(kChromeBinariesGuid, + GoogleUpdateSettings::UPDATES_DISABLED); + + EXPECT_CALL(callback_receiver_, + OnUpdateCheckCallback(UPGRADE_ERROR, + GOOGLE_UPDATE_DISABLED_BY_POLICY, _, _)); + BeginUpdateCheck(task_runner_, false, 0, callback_receiver_.GetCallback()); + task_runner_->RunUntilIdle(); +} + +TEST_P(GoogleUpdateWinTest, AllManualUpdatesDisabledByPolicy) { + // Disable updates altogether. + SetDefaultUpdatePolicy(GoogleUpdateSettings::AUTO_UPDATES_ONLY); + + EXPECT_CALL( + callback_receiver_, + OnUpdateCheckCallback(UPGRADE_ERROR, + GOOGLE_UPDATE_DISABLED_BY_POLICY_AUTO_ONLY, _, _)); + BeginUpdateCheck(task_runner_, false, 0, callback_receiver_.GetCallback()); + task_runner_->RunUntilIdle(); +} + +TEST_P(GoogleUpdateWinTest, MultiManualUpdatesDisabledByPolicy) { + // Disable updates altogether. + SetAppUpdatePolicy(kChromeBinariesGuid, + GoogleUpdateSettings::AUTO_UPDATES_ONLY); + + EXPECT_CALL( + callback_receiver_, + OnUpdateCheckCallback(UPGRADE_ERROR, + GOOGLE_UPDATE_DISABLED_BY_POLICY_AUTO_ONLY, _, _)); + BeginUpdateCheck(task_runner_, false, 0, callback_receiver_.GetCallback()); + task_runner_->RunUntilIdle(); +} + +TEST_P(GoogleUpdateWinTest, NoGoogleUpdateForCheck) { + // The factory should be called upon: let it fail. + EXPECT_CALL(mock_google_update_factory_, Create(_)); + + // Expect the appropriate error when the on-demand class cannot be created. + EXPECT_CALL(callback_receiver_, + OnUpdateCheckCallback( + UPGRADE_ERROR, GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND, _, _)); + BeginUpdateCheck(task_runner_, false, 0, callback_receiver_.GetCallback()); + task_runner_->RunUntilIdle(); +} + +TEST_P(GoogleUpdateWinTest, NoGoogleUpdateForUpgrade) { + // The factory should be called upon: let it fail. + EXPECT_CALL(mock_google_update_factory_, Create(_)); + + // Expect the appropriate error when the on-demand class cannot be created. + EXPECT_CALL(callback_receiver_, + OnUpdateCheckCallback( + UPGRADE_ERROR, GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND, _, _)); + BeginUpdateCheck(task_runner_, true, 0, callback_receiver_.GetCallback()); + task_runner_->RunUntilIdle(); +} + +TEST_P(GoogleUpdateWinTest, FailUpdateCheck) { + // The factory should be called upon: let it return the mock on-demand class. + EXPECT_CALL(mock_google_update_factory_, Create(_)) + .WillOnce(DoAll(SetArgPointee<0>(mock_on_demand_), Return(S_OK))); + // The mock on-demand class should be called. + EXPECT_CALL(*mock_on_demand_, CheckForUpdate(StrEq(kChromeBinariesGuid), _)); + + EXPECT_CALL( + callback_receiver_, + OnUpdateCheckCallback(UPGRADE_ERROR, + GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR, _, _)); + BeginUpdateCheck(task_runner_, false, 0, callback_receiver_.GetCallback()); + task_runner_->RunUntilIdle(); +} + +TEST_P(GoogleUpdateWinTest, UpdateCheckNoUpdate) { + EXPECT_CALL(mock_google_update_factory_, Create(_)) + .WillOnce(DoAll(SetArgPointee<0>(mock_on_demand_), Return(S_OK))); + mock_on_demand_->OnCheckRunUpToDateSequence(kChromeBinariesGuid); + + EXPECT_CALL(callback_receiver_, + OnUpdateCheckCallback(UPGRADE_ALREADY_UP_TO_DATE, + GOOGLE_UPDATE_NO_ERROR, IsEmpty(), _)); + BeginUpdateCheck(task_runner_, false, 0, callback_receiver_.GetCallback()); + task_runner_->RunUntilIdle(); +} + +TEST_P(GoogleUpdateWinTest, UpdateCheckUpdateAvailable) { + EXPECT_CALL(mock_google_update_factory_, Create(_)) + .WillOnce(DoAll(SetArgPointee<0>(mock_on_demand_), Return(S_OK))); + mock_on_demand_->OnCheckRunUpdateAvailableSequence(kChromeBinariesGuid, + new_version_); + + EXPECT_CALL( + callback_receiver_, + OnUpdateCheckCallback(UPGRADE_IS_AVAILABLE, GOOGLE_UPDATE_NO_ERROR, + IsEmpty(), StrEq(new_version_))); + BeginUpdateCheck(task_runner_, false, 0, callback_receiver_.GetCallback()); + task_runner_->RunUntilIdle(); +} + +TEST_P(GoogleUpdateWinTest, UpdateInstalled) { + EXPECT_CALL(mock_google_update_factory_, Create(_)) + .WillOnce(DoAll(SetArgPointee<0>(mock_on_demand_), Return(S_OK))); + mock_on_demand_->OnUpdateRunInstallUpdateSequence(kChromeBinariesGuid, + new_version_); + + EXPECT_CALL(callback_receiver_, + OnUpdateCheckCallback(UPGRADE_SUCCESSFUL, GOOGLE_UPDATE_NO_ERROR, + IsEmpty(), StrEq(new_version_))); + BeginUpdateCheck(task_runner_, true, 0, callback_receiver_.GetCallback()); + task_runner_->RunUntilIdle(); +} + +TEST_P(GoogleUpdateWinTest, UpdateFailed) { + static const base::char16 kError[] = L"It didn't work."; + EXPECT_CALL(mock_google_update_factory_, Create(_)) + .WillOnce(DoAll(SetArgPointee<0>(mock_on_demand_), Return(S_OK))); + mock_on_demand_->OnUpdateRunUpdateErrorSequence(kChromeBinariesGuid, kError); + + EXPECT_CALL(callback_receiver_, + OnUpdateCheckCallback(UPGRADE_ERROR, GOOGLE_UPDATE_ERROR_UPDATING, + StrEq(kError), IsEmpty())); + BeginUpdateCheck(task_runner_, true, 0, callback_receiver_.GetCallback()); + task_runner_->RunUntilIdle(); +} + +#endif // defined(GOOGLE_CHROME_BUILD) + +INSTANTIATE_TEST_CASE_P(UserLevel, GoogleUpdateWinTest, Values(false)); + +INSTANTIATE_TEST_CASE_P(SystemLevel, GoogleUpdateWinTest, Values(true));
diff --git a/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.cc b/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.cc index 2af5a8b..8c4c8f6 100644 --- a/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.cc +++ b/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.cc
@@ -152,7 +152,7 @@ MenuManager* menu_manager = MenuManager::Get( Profile::FromBrowserContext(web_view_guest()->browser_context())); menu_manager->RemoveAllContextItems(MenuItem::ExtensionKey( - web_view_guest()->embedder_extension_id(), + web_view_guest()->owner_extension_id(), web_view_guest()->view_instance_id())); }
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc index 32bc814..7cbcf7b3 100644 --- a/chrome/browser/io_thread.cc +++ b/chrome/browser/io_thread.cc
@@ -479,6 +479,8 @@ &system_enable_referrers_, NULL, NULL, + NULL, + NULL, local_state); ssl_config_service_manager_.reset( SSLConfigServiceManager::CreateDefaultManager(local_state));
diff --git a/chrome/browser/jumplist_win.cc b/chrome/browser/jumplist_win.cc index a14f316..1eb72f59 100644 --- a/chrome/browser/jumplist_win.cc +++ b/chrome/browser/jumplist_win.cc
@@ -22,7 +22,6 @@ #include "chrome/browser/history/top_sites.h" #include "chrome/browser/metrics/jumplist_metrics_win.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_avatar_icon_util.h" #include "chrome/browser/profiles/profile_info_cache.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/sessions/tab_restore_service.h" @@ -596,7 +595,7 @@ gfx::Image avatar; bool is_rectangle; - profiles::GetTransparentBackgroundProfileAvatar( + avatar_menu_->GetImageForMenuButton( item.profile_path, &avatar, &is_rectangle); link->set_icon_data(avatar.AsBitmap()); new_profile_switcher.push_back(link);
diff --git a/chrome/browser/media/encrypted_media_istypesupported_browsertest.cc b/chrome/browser/media/encrypted_media_istypesupported_browsertest.cc index 7fd257b6..5e46ac9 100644 --- a/chrome/browser/media/encrypted_media_istypesupported_browsertest.cc +++ b/chrome/browser/media/encrypted_media_istypesupported_browsertest.cc
@@ -46,7 +46,7 @@ // Note: Widevine is not available on platforms using components because // RegisterPepperCdm() cannot set the codecs. // TODO(ddorwin): Enable these tests after we have the ability to use the CUS -// in these tests. See http://crbug.com/311724. +// in these tests. See http://crbug.com/356833. #if defined(WIDEVINE_CDM_AVAILABLE) && !defined(WIDEVINE_CDM_IS_COMPONENT) #define EXPECT_WV EXPECT_TRUE #define EXPECT_WVMP4 EXPECT_TRUE @@ -343,28 +343,11 @@ #endif // defined(ENABLE_PEPPER_CDMS) }; -// For Widevine tests, ensure that the Widevine adapter is loaded. +// TODO(sandersd): Register the Widevine CDM if it is a component. A component +// CDM registered using RegisterPepperCdm() declares support for audio codecs, +// but not the other codecs we expect. http://crbug.com/356833. class EncryptedMediaIsTypeSupportedWidevineTest : public EncryptedMediaIsTypeSupportedTest { -#if defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS) && \ - defined(WIDEVINE_CDM_IS_COMPONENT) - protected: - virtual void SetUpCommandLine(CommandLine* command_line) override { - // File name of the adapter on different platforms. - const char adapter_file_name[] = -#if defined(OS_MACOSX) - "widevinecdmadapter.plugin"; -#elif defined(OS_WIN) - "widevinecdmadapter.dll"; -#else // OS_LINUX, etc. - "libwidevinecdmadapter.so"; -#endif - - const std::string pepper_name("application/x-ppapi-widevine-cdm"); - RegisterPepperCdm(command_line, adapter_file_name, pepper_name); - } -#endif // defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS) && - // defined(WIDEVINE_CDM_IS_COMPONENT) }; #if defined(ENABLE_PEPPER_CDMS) @@ -849,11 +832,7 @@ IN_PROC_BROWSER_TEST_F(EncryptedMediaIsTypeSupportedWidevineTest, Widevine_Basic) { -#if defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT) - EXPECT_TRUE(IsConcreteSupportedKeySystem(kWidevineAlpha)); -#else EXPECT_WV(IsConcreteSupportedKeySystem(kWidevineAlpha)); -#endif EXPECT_WV(IsSupportedKeySystemWithMediaMimeType( "video/webm", no_codecs(), kWidevineAlpha)); }
diff --git a/chrome/browser/net/OWNERS b/chrome/browser/net/OWNERS index c1f330e5..6419ed1 100644 --- a/chrome/browser/net/OWNERS +++ b/chrome/browser/net/OWNERS
@@ -16,6 +16,6 @@ willchan@chromium.org per-file disk_cache_dir_policy_handler*=dconnelly@chromium.org -per-file disk_cache_dir_policy_handler*=joaodasilva@chromium.org -per-file proxy_policy_handler*=joaodasilva@chromium.org +per-file disk_cache_dir_policy_handler*=mnissler@chromium.org +per-file proxy_policy_handler*=mnissler@chromium.org per-file proxy_policy_handler*=dconnelly@chromium.org
diff --git a/chrome/browser/net/chrome_network_delegate.cc b/chrome/browser/net/chrome_network_delegate.cc index 0ca475f..ae84c3e 100644 --- a/chrome/browser/net/chrome_network_delegate.cc +++ b/chrome/browser/net/chrome_network_delegate.cc
@@ -251,7 +251,9 @@ : profile_(NULL), enable_referrers_(enable_referrers), enable_do_not_track_(NULL), + force_safe_search_(NULL), force_google_safe_search_(NULL), + force_youtube_safety_mode_(NULL), data_reduction_proxy_enabled_(NULL), #if defined(ENABLE_CONFIGURATION_POLICY) url_blacklist_manager_(NULL), @@ -309,7 +311,9 @@ void ChromeNetworkDelegate::InitializePrefsOnUIThread( BooleanPrefMember* enable_referrers, BooleanPrefMember* enable_do_not_track, + BooleanPrefMember* force_safe_search, BooleanPrefMember* force_google_safe_search, + BooleanPrefMember* force_youtube_safety_mode, PrefService* pref_service) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); enable_referrers->Init(prefs::kEnableReferrers, pref_service); @@ -320,11 +324,22 @@ enable_do_not_track->MoveToThread( BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)); } + if (force_safe_search) { + force_safe_search->Init(prefs::kForceSafeSearch, pref_service); + force_safe_search->MoveToThread( + BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)); + } if (force_google_safe_search) { - force_google_safe_search->Init(prefs::kForceSafeSearch, pref_service); + force_google_safe_search->Init(prefs::kForceGoogleSafeSearch, pref_service); force_google_safe_search->MoveToThread( BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)); } + if (force_youtube_safety_mode) { + force_youtube_safety_mode->Init(prefs::kForceYouTubeSafetyMode, + pref_service); + force_youtube_safety_mode->MoveToThread( + BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)); + } } // static @@ -395,8 +410,9 @@ client_hints_->GetDevicePixelRatioHeader(), true); } - bool force_safe_search = force_google_safe_search_ && - force_google_safe_search_->GetValue(); + bool force_safe_search = + (force_safe_search_ && force_safe_search_->GetValue()) || + (force_google_safe_search_ && force_google_safe_search_->GetValue()); net::CompletionCallback wrapped_callback = callback; if (force_safe_search) { @@ -445,9 +461,10 @@ net::URLRequest* request, const net::CompletionCallback& callback, net::HttpRequestHeaders* headers) { - bool force_safe_search = force_google_safe_search_ && - force_google_safe_search_->GetValue(); - if (force_safe_search) + bool force_safety_mode = + (force_safe_search_ && force_safe_search_->GetValue()) || + (force_youtube_safety_mode_ && force_youtube_safety_mode_->GetValue()); + if (force_safety_mode) safe_search_util::ForceYouTubeSafetyMode(request, headers); TRACE_EVENT_ASYNC_STEP_PAST0("net", "URLRequest", request, "SendRequest");
diff --git a/chrome/browser/net/chrome_network_delegate.h b/chrome/browser/net/chrome_network_delegate.h index 8a13b1e..ed0a939f 100644 --- a/chrome/browser/net/chrome_network_delegate.h +++ b/chrome/browser/net/chrome_network_delegate.h
@@ -131,11 +131,21 @@ enable_do_not_track_ = enable_do_not_track; } + void set_force_safe_search( + BooleanPrefMember* force_safe_search) { + force_safe_search_ = force_safe_search; + } + void set_force_google_safe_search( BooleanPrefMember* force_google_safe_search) { force_google_safe_search_ = force_google_safe_search; } + void set_force_youtube_safety_mode( + BooleanPrefMember* force_youtube_safety_mode) { + force_youtube_safety_mode_ = force_youtube_safety_mode; + } + void set_data_reduction_proxy_enabled_pref( BooleanPrefMember* data_reduction_proxy_enabled) { data_reduction_proxy_enabled_ = data_reduction_proxy_enabled; @@ -199,7 +209,9 @@ static void InitializePrefsOnUIThread( BooleanPrefMember* enable_referrers, BooleanPrefMember* enable_do_not_track, + BooleanPrefMember* force_safe_search, BooleanPrefMember* force_google_safe_search, + BooleanPrefMember* force_youtube_safety_mode, PrefService* pref_service); // When called, all file:// URLs will now be accessible. If this is not @@ -286,7 +298,9 @@ // Weak, owned by our owner. BooleanPrefMember* enable_referrers_; BooleanPrefMember* enable_do_not_track_; + BooleanPrefMember* force_safe_search_; BooleanPrefMember* force_google_safe_search_; + BooleanPrefMember* force_youtube_safety_mode_; BooleanPrefMember* data_reduction_proxy_enabled_; // Weak, owned by our owner.
diff --git a/chrome/browser/net/chrome_network_delegate_unittest.cc b/chrome/browser/net/chrome_network_delegate_unittest.cc index 0dc2baa..4b722dd 100644 --- a/chrome/browser/net/chrome_network_delegate_unittest.cc +++ b/chrome/browser/net/chrome_network_delegate_unittest.cc
@@ -9,12 +9,11 @@ #include "base/message_loop/message_loop.h" #include "base/prefs/pref_member.h" #include "chrome/browser/content_settings/cookie_settings.h" +#include "chrome/browser/net/safe_search_util.h" #include "chrome/common/pref_names.h" -#include "chrome/common/url_constants.h" #include "chrome/test/base/testing_pref_service_syncable.h" #include "chrome/test/base/testing_profile.h" #include "content/public/test/test_browser_thread_bundle.h" -#include "net/base/completion_callback.h" #include "net/base/request_priority.h" #include "net/url_request/url_request.h" #include "net/url_request/url_request_test_util.h" @@ -105,7 +104,11 @@ void SetUp() override { ChromeNetworkDelegate::InitializePrefsOnUIThread( - &enable_referrers_, NULL, &force_google_safe_search_, + &enable_referrers_, + NULL, + &force_safe_search_, + &force_google_safe_search_, + &force_youtube_safety_mode_, profile_.GetTestingPrefService()); } @@ -113,12 +116,19 @@ scoped_ptr<net::NetworkDelegate> CreateNetworkDelegate() { scoped_ptr<ChromeNetworkDelegate> network_delegate( new ChromeNetworkDelegate(forwarder(), &enable_referrers_)); + network_delegate->set_force_safe_search(&force_safe_search_); network_delegate->set_force_google_safe_search(&force_google_safe_search_); + network_delegate->set_force_youtube_safety_mode( + &force_youtube_safety_mode_); return network_delegate.Pass(); } - void SetSafeSearch(bool value) { - force_google_safe_search_.SetValue(value); + void SetSafeSearch(bool safe_search, + bool google_safe_search, + bool youtube_safety_mode) { + force_safe_search_.SetValue(safe_search); + force_google_safe_search_.SetValue(google_safe_search); + force_youtube_safety_mode_.SetValue(youtube_safety_mode); } void SetDelegate(net::NetworkDelegate* delegate) { @@ -126,21 +136,23 @@ context_.set_network_delegate(network_delegate_); } - // Does a request using the |url_string| URL and verifies that the expected - // string is equal to the query part (between ? and #) of the final url of - // that request. - void CheckAddedParameters(const std::string& url_string, - const std::string& expected_query_parameters) { - // Show the URL in the trace so we know where we failed. - SCOPED_TRACE(url_string); + // Does a request to an arbitrary URL and verifies that the SafeSearch + // enforcement utility functions were called/not called as expected. + void QueryURL(bool expect_google_safe_search, + bool expect_youtube_safety_mode) { + safe_search_util::ClearForceGoogleSafeSearchCountForTesting(); + safe_search_util::ClearForceYouTubeSafetyModeCountForTesting(); scoped_ptr<net::URLRequest> request(context_.CreateRequest( - GURL(url_string), net::DEFAULT_PRIORITY, &delegate_, NULL)); + GURL("http://anyurl.com"), net::DEFAULT_PRIORITY, &delegate_, NULL)); request->Start(); base::MessageLoop::current()->RunUntilIdle(); - EXPECT_EQ(expected_query_parameters, request->url().query()); + EXPECT_EQ(expect_google_safe_search ? 1 : 0, + safe_search_util::GetForceGoogleSafeSearchCountForTesting()); + EXPECT_EQ(expect_youtube_safety_mode ? 1 : 0, + safe_search_util::GetForceYouTubeSafetyModeCountForTesting()); } private: @@ -158,143 +170,31 @@ #endif TestingProfile profile_; BooleanPrefMember enable_referrers_; + BooleanPrefMember force_safe_search_; BooleanPrefMember force_google_safe_search_; + BooleanPrefMember force_youtube_safety_mode_; scoped_ptr<net::URLRequest> request_; net::TestURLRequestContext context_; net::NetworkDelegate* network_delegate_; net::TestDelegate delegate_; }; -TEST_F(ChromeNetworkDelegateSafeSearchTest, SafeSearchOn) { - // Tests with SafeSearch on, request parameters should be rewritten. - const std::string kSafeParameter = chrome::kSafeSearchSafeParameter; - const std::string kSsuiParameter = chrome::kSafeSearchSsuiParameter; - const std::string kBothParameters = kSafeParameter + "&" + kSsuiParameter; - SetSafeSearch(true); +TEST_F(ChromeNetworkDelegateSafeSearchTest, SafeSearch) { scoped_ptr<net::NetworkDelegate> delegate(CreateNetworkDelegate()); SetDelegate(delegate.get()); - // Test the home page. - CheckAddedParameters("http://google.com/", kBothParameters); + // Loop over all combinations of the three policies. + for (int i = 0; i < 8; i++) { + bool safe_search = i % 2; + bool google_safe_search = (i / 2) % 2; + bool youtube_safety_mode = i / 4; + SetSafeSearch(safe_search, google_safe_search, youtube_safety_mode); - // Test the search home page. - CheckAddedParameters("http://google.com/webhp", - kBothParameters); - - // Test different valid search pages with parameters. - CheckAddedParameters("http://google.com/search?q=google", - "q=google&" + kBothParameters); - - CheckAddedParameters("http://google.com/?q=google", - "q=google&" + kBothParameters); - - CheckAddedParameters("http://google.com/webhp?q=google", - "q=google&" + kBothParameters); - - // Test the valid pages with safe set to off. - CheckAddedParameters("http://google.com/search?q=google&safe=off", - "q=google&" + kBothParameters); - - CheckAddedParameters("http://google.com/?q=google&safe=off", - "q=google&" + kBothParameters); - - CheckAddedParameters("http://google.com/webhp?q=google&safe=off", - "q=google&" + kBothParameters); - - CheckAddedParameters("http://google.com/webhp?q=google&%73afe=off", - "q=google&%73afe=off&" + kBothParameters); - - // Test the home page, different TLDs. - CheckAddedParameters("http://google.de/", kBothParameters); - CheckAddedParameters("http://google.ro/", kBothParameters); - CheckAddedParameters("http://google.nl/", kBothParameters); - - // Test the search home page, different TLD. - CheckAddedParameters("http://google.de/webhp", kBothParameters); - - // Test the search page with parameters, different TLD. - CheckAddedParameters("http://google.de/search?q=google", - "q=google&" + kBothParameters); - - // Test the home page with parameters, different TLD. - CheckAddedParameters("http://google.de/?q=google", - "q=google&" + kBothParameters); - - // Test the search page with the parameters set. - CheckAddedParameters("http://google.de/?q=google&" + kBothParameters, - "q=google&" + kBothParameters); - - // Test some possibly tricky combinations. - CheckAddedParameters("http://google.com/?q=goog&" + kSafeParameter + - "&ssui=one", - "q=goog&" + kBothParameters); - - CheckAddedParameters("http://google.de/?q=goog&unsafe=active&" + - kSsuiParameter, - "q=goog&unsafe=active&" + kBothParameters); - - CheckAddedParameters("http://google.de/?q=goog&safe=off&ssui=off", - "q=goog&" + kBothParameters); - - // Test various combinations where we should not add anything. - CheckAddedParameters("http://google.com/?q=goog&" + kSsuiParameter + "&" + - kSafeParameter, - "q=goog&" + kBothParameters); - - CheckAddedParameters("http://google.com/?" + kSsuiParameter + "&q=goog&" + - kSafeParameter, - "q=goog&" + kBothParameters); - - CheckAddedParameters("http://google.com/?" + kSsuiParameter + "&" + - kSafeParameter + "&q=goog", - "q=goog&" + kBothParameters); - - // Test that another website is not affected, without parameters. - CheckAddedParameters("http://google.com/finance", std::string()); - - // Test that another website is not affected, with parameters. - CheckAddedParameters("http://google.com/finance?q=goog", "q=goog"); - - // Test that another website is not affected with redirects, with parameters. - CheckAddedParameters("http://finance.google.com/?q=goog", "q=goog"); - - // Test with percent-encoded data (%26 is &) - CheckAddedParameters("http://google.com/?q=%26%26%26&" + kSsuiParameter + - "&" + kSafeParameter + "¶m=%26%26%26", - "q=%26%26%26¶m=%26%26%26&" + kBothParameters); -} - -TEST_F(ChromeNetworkDelegateSafeSearchTest, SafeSearchOff) { - // Tests with SafeSearch settings off, delegate should not alter requests. - SetSafeSearch(false); - scoped_ptr<net::NetworkDelegate> delegate(CreateNetworkDelegate()); - SetDelegate(delegate.get()); - - // Test the home page. - CheckAddedParameters("http://google.com/", std::string()); - - // Test the search home page. - CheckAddedParameters("http://google.com/webhp", std::string()); - - // Test the home page with parameters. - CheckAddedParameters("http://google.com/search?q=google", - "q=google"); - - // Test the search page with parameters. - CheckAddedParameters("http://google.com/?q=google", - "q=google"); - - // Test the search webhp page with parameters. - CheckAddedParameters("http://google.com/webhp?q=google", - "q=google"); - - // Test the home page with parameters and safe set to off. - CheckAddedParameters("http://google.com/search?q=google&safe=off", - "q=google&safe=off"); - - // Test the home page with parameters and safe set to active. - CheckAddedParameters("http://google.com/search?q=google&safe=active", - "q=google&safe=active"); + // The old "SafeSearch" policy implies both Google and YouTube. + bool expect_google_safe_search = safe_search || google_safe_search; + bool expect_youtube_safety_mode = safe_search || youtube_safety_mode; + QueryURL(expect_google_safe_search, expect_youtube_safety_mode); + } } // Privacy Mode disables Channel Id if cookies are blocked (cr223191) @@ -314,7 +214,7 @@ void SetUp() override { ChromeNetworkDelegate::InitializePrefsOnUIThread( - &enable_referrers_, NULL, NULL, + &enable_referrers_, NULL, NULL, NULL, NULL, profile_.GetTestingPrefService()); }
diff --git a/chrome/browser/net/chrome_url_request_context_getter.cc b/chrome/browser/net/chrome_url_request_context_getter.cc index ab3ed5d1..8372c24 100644 --- a/chrome/browser/net/chrome_url_request_context_getter.cc +++ b/chrome/browser/net/chrome_url_request_context_getter.cc
@@ -8,6 +8,7 @@ #include "base/compiler_specific.h" #include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop_proxy.h" +#include "base/profiler/scoped_tracker.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/io_thread.h" #include "chrome/browser/profiles/profile.h" @@ -179,6 +180,11 @@ // Lazily create a URLRequestContext using our factory. net::URLRequestContext* ChromeURLRequestContextGetter::GetURLRequestContext() { + // TODO(vadimt): Remove ScopedTracker below once crbug.com/436671 is fixed. + tracked_objects::ScopedTracker tracking_profile( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "436671 ChromeURLRequestContextGetter::GetURLRequestContext")); + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); if (factory_.get()) {
diff --git a/chrome/browser/net/predictor.cc b/chrome/browser/net/predictor.cc index b448a5a..2c4882c 100644 --- a/chrome/browser/net/predictor.cc +++ b/chrome/browser/net/predictor.cc
@@ -450,6 +450,10 @@ // Overloaded Resolve() to take a vector of names. void Predictor::ResolveList(const UrlList& urls, UrlInfo::ResolutionMotivation motivation) { + // TODO(vadimt): Remove ScopedTracker below once crbug.com/436671 is fixed. + tracked_objects::ScopedTracker tracking_profile( + FROM_HERE_WITH_EXPLICIT_FUNCTION("436671 Predictor::ResolveList")); + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); for (UrlList::const_iterator it = urls.begin(); it < urls.end(); ++it) { @@ -779,6 +783,11 @@ void Predictor::DnsPrefetchMotivatedList( const UrlList& urls, UrlInfo::ResolutionMotivation motivation) { + // TODO(vadimt): Remove ScopedTracker below once crbug.com/436671 is fixed. + tracked_objects::ScopedTracker tracking_profile( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "436671 Predictor::DnsPrefetchMotivatedList")); + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) || BrowserThread::CurrentlyOn(BrowserThread::IO)); if (!predictor_enabled_)
diff --git a/chrome/browser/net/safe_search_util.cc b/chrome/browser/net/safe_search_util.cc index 322fc2d0..29f095d 100644 --- a/chrome/browser/net/safe_search_util.cc +++ b/chrome/browser/net/safe_search_util.cc
@@ -23,6 +23,9 @@ namespace { +int g_force_google_safe_search_count_for_test = 0; +int g_force_youtube_safety_mode_count_for_test = 0; + const char kYouTubeSafetyModeHeaderName[] = "YouTube-Safety-Mode"; const char kYouTubeSafetyModeHeaderValue[] = "Active"; @@ -70,6 +73,8 @@ // enforces that the SafeSearch query parameters are set to active. // Sets the query part of |new_url| with the new value of the parameters. void ForceGoogleSafeSearch(const net::URLRequest* request, GURL* new_url) { + ++g_force_google_safe_search_count_for_test; + if (!google_util::IsGoogleSearchUrl(request->url()) && !google_util::IsGoogleHomePageUrl(request->url())) return; @@ -88,6 +93,8 @@ // setting YouTube's Safety Mode header. void ForceYouTubeSafetyMode(const net::URLRequest* request, net::HttpRequestHeaders* headers) { + ++g_force_youtube_safety_mode_count_for_test; + if (!google_util::IsYoutubeDomainUrl( request->url(), google_util::ALLOW_SUBDOMAIN, @@ -98,4 +105,20 @@ kYouTubeSafetyModeHeaderValue); } +int GetForceGoogleSafeSearchCountForTesting() { + return g_force_google_safe_search_count_for_test; +} + +int GetForceYouTubeSafetyModeCountForTesting() { + return g_force_youtube_safety_mode_count_for_test; +} + +void ClearForceGoogleSafeSearchCountForTesting() { + g_force_google_safe_search_count_for_test = 0; +} + +void ClearForceYouTubeSafetyModeCountForTesting() { + g_force_youtube_safety_mode_count_for_test = 0; +} + } // namespace safe_search_util
diff --git a/chrome/browser/net/safe_search_util.h b/chrome/browser/net/safe_search_util.h index 81211a96..2e9a0edb 100644 --- a/chrome/browser/net/safe_search_util.h +++ b/chrome/browser/net/safe_search_util.h
@@ -24,6 +24,11 @@ void ForceYouTubeSafetyMode(const net::URLRequest* request, net::HttpRequestHeaders* headers); +int GetForceGoogleSafeSearchCountForTesting(); +int GetForceYouTubeSafetyModeCountForTesting(); +void ClearForceGoogleSafeSearchCountForTesting(); +void ClearForceYouTubeSafetyModeCountForTesting(); + } // namespace safe_search_util #endif // CHROME_BROWSER_NET_SAFE_SEARCH_UTIL_H_
diff --git a/chrome/browser/net/safe_search_util_unittest.cc b/chrome/browser/net/safe_search_util_unittest.cc index fbf2989..da23ffa3 100644 --- a/chrome/browser/net/safe_search_util_unittest.cc +++ b/chrome/browser/net/safe_search_util_unittest.cc
@@ -6,6 +6,7 @@ #include "base/message_loop/message_loop.h" #include "base/strings/string_piece.h" +#include "chrome/common/url_constants.h" #include "net/http/http_request_headers.h" #include "net/url_request/url_request_test_util.h" #include "testing/gtest/include/gtest/gtest.h" @@ -16,27 +17,128 @@ SafeSearchUtilTest() {} ~SafeSearchUtilTest() override {} + scoped_ptr<net::URLRequest> CreateRequest(const std::string& url) { + return context_.CreateRequest(GURL(url), net::DEFAULT_PRIORITY, NULL, NULL); + } + scoped_ptr<net::URLRequest> CreateYoutubeRequest() { - return context_.CreateRequest(GURL("http://www.youtube.com"), - net::DEFAULT_PRIORITY, - NULL, - NULL); + return CreateRequest("http://www.youtube.com"); } scoped_ptr<net::URLRequest> CreateNonYoutubeRequest() { - return context_.CreateRequest(GURL("http://www.notyoutube.com"), - net::DEFAULT_PRIORITY, - NULL, - NULL); + return CreateRequest("http://www.notyoutube.com"); + } + + // Does a request using the |url_string| URL and verifies that the expected + // string is equal to the query part (between ? and #) of the final url of + // that request. + void CheckAddedParameters(const std::string& url_string, + const std::string& expected_query_parameters) { + // Show the URL in the trace so we know where we failed. + SCOPED_TRACE(url_string); + + scoped_ptr<net::URLRequest> request(CreateRequest(url_string)); + GURL result(url_string); + safe_search_util::ForceGoogleSafeSearch(request.get(), &result); + + EXPECT_EQ(expected_query_parameters, result.query()); } base::MessageLoop message_loop_; net::TestURLRequestContext context_; }; -// ForceGoogleSafeSearch is already tested quite extensively in -// ChromeNetworkDelegateSafeSearchTest (in chrome_network_delegate_unittest.cc), -// so we won't test it again here. +TEST_F(SafeSearchUtilTest, AddGoogleSafeSearchParams) { + const std::string kSafeParameter = chrome::kSafeSearchSafeParameter; + const std::string kSsuiParameter = chrome::kSafeSearchSsuiParameter; + const std::string kBothParameters = kSafeParameter + "&" + kSsuiParameter; + + // Test the home page. + CheckAddedParameters("http://google.com/", kBothParameters); + + // Test the search home page. + CheckAddedParameters("http://google.com/webhp", + kBothParameters); + + // Test different valid search pages with parameters. + CheckAddedParameters("http://google.com/search?q=google", + "q=google&" + kBothParameters); + + CheckAddedParameters("http://google.com/?q=google", + "q=google&" + kBothParameters); + + CheckAddedParameters("http://google.com/webhp?q=google", + "q=google&" + kBothParameters); + + // Test the valid pages with safe set to off. + CheckAddedParameters("http://google.com/search?q=google&safe=off", + "q=google&" + kBothParameters); + + CheckAddedParameters("http://google.com/?q=google&safe=off", + "q=google&" + kBothParameters); + + CheckAddedParameters("http://google.com/webhp?q=google&safe=off", + "q=google&" + kBothParameters); + + CheckAddedParameters("http://google.com/webhp?q=google&%73afe=off", + "q=google&%73afe=off&" + kBothParameters); + + // Test the home page, different TLDs. + CheckAddedParameters("http://google.de/", kBothParameters); + CheckAddedParameters("http://google.ro/", kBothParameters); + CheckAddedParameters("http://google.nl/", kBothParameters); + + // Test the search home page, different TLD. + CheckAddedParameters("http://google.de/webhp", kBothParameters); + + // Test the search page with parameters, different TLD. + CheckAddedParameters("http://google.de/search?q=google", + "q=google&" + kBothParameters); + + // Test the home page with parameters, different TLD. + CheckAddedParameters("http://google.de/?q=google", + "q=google&" + kBothParameters); + + // Test the search page with the parameters set. + CheckAddedParameters("http://google.de/?q=google&" + kBothParameters, + "q=google&" + kBothParameters); + + // Test some possibly tricky combinations. + CheckAddedParameters("http://google.com/?q=goog&" + kSafeParameter + + "&ssui=one", + "q=goog&" + kBothParameters); + + CheckAddedParameters("http://google.de/?q=goog&unsafe=active&" + + kSsuiParameter, + "q=goog&unsafe=active&" + kBothParameters); + + CheckAddedParameters("http://google.de/?q=goog&safe=off&ssui=off", + "q=goog&" + kBothParameters); + + // Test various combinations where we should not add anything. + CheckAddedParameters("http://google.com/?q=goog&" + kSsuiParameter + "&" + + kSafeParameter, + "q=goog&" + kBothParameters); + + CheckAddedParameters("http://google.com/?" + kSsuiParameter + "&q=goog&" + + kSafeParameter, + "q=goog&" + kBothParameters); + + CheckAddedParameters("http://google.com/?" + kSsuiParameter + "&" + + kSafeParameter + "&q=goog", + "q=goog&" + kBothParameters); + + // Test that another website is not affected, without parameters. + CheckAddedParameters("http://google.com/finance", std::string()); + + // Test that another website is not affected, with parameters. + CheckAddedParameters("http://google.com/finance?q=goog", "q=goog"); + + // Test with percent-encoded data (%26 is &) + CheckAddedParameters("http://google.com/?q=%26%26%26&" + kSsuiParameter + + "&" + kSafeParameter + "¶m=%26%26%26", + "q=%26%26%26¶m=%26%26%26&" + kBothParameters); +} TEST_F(SafeSearchUtilTest, SetYoutubeHeader) { scoped_ptr<net::URLRequest> request = CreateYoutubeRequest();
diff --git a/chrome/browser/net/ssl_config_service_manager_pref.cc b/chrome/browser/net/ssl_config_service_manager_pref.cc index 2ce8e9a..decd895 100644 --- a/chrome/browser/net/ssl_config_service_manager_pref.cc +++ b/chrome/browser/net/ssl_config_service_manager_pref.cc
@@ -20,6 +20,7 @@ #include "components/content_settings/core/browser/content_settings_utils.h" #include "components/content_settings/core/common/content_settings.h" #include "content/public/browser/browser_thread.h" +#include "net/socket/ssl_client_socket.h" #include "net/ssl/ssl_cipher_suite_names.h" #include "net/ssl/ssl_config_service.h" @@ -261,7 +262,7 @@ std::string version_max_str = ssl_version_max_.GetValue(); std::string version_fallback_min_str = ssl_version_fallback_min_.GetValue(); config->version_min = net::kDefaultSSLVersionMin; - config->version_max = net::kDefaultSSLVersionMax; + config->version_max = net::SSLClientSocket::GetMaxSupportedSSLVersion(); config->version_fallback_min = net::kDefaultSSLVersionFallbackMin; uint16 version_min = SSLProtocolVersionFromString(version_min_str); uint16 version_max = SSLProtocolVersionFromString(version_max_str); @@ -276,8 +277,6 @@ } } if (version_max) { - // TODO(wtc): get the maximum SSL protocol version supported by the - // SSLClientSocket class. uint16 supported_version_max = config->version_max; config->version_max = std::min(supported_version_max, version_max); }
diff --git a/chrome/browser/net/ssl_config_service_manager_pref_unittest.cc b/chrome/browser/net/ssl_config_service_manager_pref_unittest.cc index 366a5293..f0a413c 100644 --- a/chrome/browser/net/ssl_config_service_manager_pref_unittest.cc +++ b/chrome/browser/net/ssl_config_service_manager_pref_unittest.cc
@@ -18,6 +18,7 @@ #include "components/content_settings/core/browser/host_content_settings_map.h" #include "components/content_settings/core/common/content_settings.h" #include "content/public/test/test_browser_thread.h" +#include "net/socket/ssl_client_socket.h" #include "net/ssl/ssl_config_service.h" #include "testing/gtest/include/gtest/gtest.h" @@ -127,7 +128,7 @@ } // Test that without command-line settings for minimum and maximum SSL versions, -// TLS 1.0 ~ kDefaultSSLVersionMax are enabled. +// TLS versions from 1.0 up to 1.1 or 1.2 are enabled. TEST_F(SSLConfigServiceManagerPrefTest, NoCommandLinePrefs) { scoped_refptr<TestingPrefStore> local_state_store(new TestingPrefStore()); @@ -146,10 +147,12 @@ SSLConfig ssl_config; config_service->GetSSLConfig(&ssl_config); - // The default value in the absence of command-line options is that - // SSL 3.0 ~ kDefaultSSLVersionMax are enabled. + // In the absence of command-line options, TLS versions from 1.0 up to 1.1 or + // 1.2 (depending on the underlying library and cryptographic implementation) + // are enabled. EXPECT_EQ(net::SSL_PROTOCOL_VERSION_TLS1, ssl_config.version_min); - EXPECT_EQ(net::kDefaultSSLVersionMax, ssl_config.version_max); + EXPECT_EQ(net::SSLClientSocket::GetMaxSupportedSSLVersion(), + ssl_config.version_max); // The settings should not be added to the local_state. EXPECT_FALSE(local_state->HasPrefPath(prefs::kSSLVersionMin));
diff --git a/chrome/browser/notifications/notification_ui_manager_android.cc b/chrome/browser/notifications/notification_ui_manager_android.cc index 8a8aae9..a3a339c1 100644 --- a/chrome/browser/notifications/notification_ui_manager_android.cc +++ b/chrome/browser/notifications/notification_ui_manager_android.cc
@@ -121,7 +121,7 @@ const GURL origin_url = notification.origin_url(); DCHECK(origin_url.is_valid()); - for (auto iterator : profile_notifications_) { + for (const auto& iterator : profile_notifications_) { ProfileNotification* profile_notification = iterator.second; if (profile_notification->notification().replace_id() != replace_id || profile_notification->notification().origin_url() != origin_url ||
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc index 016be9d6..0ad9df4 100644 --- a/chrome/browser/password_manager/chrome_password_manager_client.cc +++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -26,15 +26,16 @@ #include "components/autofill/content/common/autofill_messages.h" #include "components/autofill/core/browser/password_generator.h" #include "components/autofill/core/common/password_form.h" +#include "components/password_manager/content/browser/content_password_manager_driver.h" #include "components/password_manager/content/browser/password_manager_internals_service_factory.h" #include "components/password_manager/content/common/credential_manager_messages.h" #include "components/password_manager/content/common/credential_manager_types.h" #include "components/password_manager/core/browser/browser_save_password_progress_logger.h" #include "components/password_manager/core/browser/log_receiver.h" #include "components/password_manager/core/browser/password_form_manager.h" -#include "components/password_manager/core/browser/password_manager.h" #include "components/password_manager/core/browser/password_manager_internals_service.h" #include "components/password_manager/core/browser/password_manager_metrics_util.h" +#include "components/password_manager/core/browser/password_manager_url_collection_experiment.h" #include "components/password_manager/core/common/password_manager_switches.h" #include "content/public/browser/navigation_entry.h" #include "content/public/browser/render_view_host.h" @@ -47,6 +48,7 @@ #include "chrome/browser/password_manager/generated_password_saved_infobar_delegate_android.h" #endif +using password_manager::ContentPasswordManagerDriverFactory; using password_manager::PasswordManagerInternalsService; using password_manager::PasswordManagerInternalsServiceFactory; @@ -73,12 +75,18 @@ autofill::AutofillClient* autofill_client) : content::WebContentsObserver(web_contents), profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())), - driver_(web_contents, this, autofill_client), + password_manager_(this), + driver_factory_(nullptr), credential_manager_dispatcher_(web_contents, this), - observer_(NULL), + observer_(nullptr), can_use_log_router_(false), autofill_sync_state_(ALLOW_SYNC_CREDENTIALS), sync_credential_was_filtered_(false) { + ContentPasswordManagerDriverFactory::CreateForWebContents(web_contents, this, + autofill_client); + driver_factory_ = + ContentPasswordManagerDriverFactory::FromWebContents(web_contents); + PasswordManagerInternalsService* service = PasswordManagerInternalsServiceFactory::GetForBrowserContext(profile_); if (service) @@ -123,6 +131,11 @@ return entry->GetURL().host() != chrome::kChromeUIChromeSigninHost; } +bool ChromePasswordManagerClient::ShouldAskUserToSubmitURL() { + return password_manager::urls_collection_experiment::ShouldShowBubble( + GetPrefs()); +} + bool ChromePasswordManagerClient::ShouldFilterAutofillResult( const autofill::PasswordForm& form) { if (!IsSyncAccountCredential(base::UTF16ToUTF8(form.username_value), @@ -153,6 +166,12 @@ profile_, username, origin); } +void ChromePasswordManagerClient::AskUserAndMaybeReportURL( + const std::string& url) const { + // TODO(melandory) Show bubble which asks user if he wants to report the URL + // and report URL if needed. +} + void ChromePasswordManagerClient::AutofillResultsComputed() { UMA_HISTOGRAM_BOOLEAN("PasswordManager.SyncCredentialFiltered", sync_credential_was_filtered_); @@ -243,11 +262,6 @@ .get(); } -password_manager::PasswordManagerDriver* -ChromePasswordManagerClient::GetDriver() { - return &driver_; -} - base::FieldTrial::Probability ChromePasswordManagerClient::GetProbabilityForExperiment( const std::string& experiment_name) { @@ -331,26 +345,22 @@ return false; } -// static -password_manager::PasswordGenerationManager* -ChromePasswordManagerClient::GetGenerationManagerFromWebContents( - content::WebContents* contents) { - ChromePasswordManagerClient* client = - ChromePasswordManagerClient::FromWebContents(contents); - if (!client) - return NULL; - return client->GetDriver()->GetPasswordGenerationManager(); +bool ChromePasswordManagerClient::DidLastPageLoadEncounterSSLErrors() { + content::NavigationEntry* entry = + web_contents()->GetController().GetLastCommittedEntry(); + if (!entry) + return false; + + return net::IsCertStatusError(entry->GetSSL().cert_status); } -// static +bool ChromePasswordManagerClient::IsOffTheRecord() { + return web_contents()->GetBrowserContext()->IsOffTheRecord(); +} + password_manager::PasswordManager* -ChromePasswordManagerClient::GetManagerFromWebContents( - content::WebContents* contents) { - ChromePasswordManagerClient* client = - ChromePasswordManagerClient::FromWebContents(contents); - if (!client) - return NULL; - return client->GetDriver()->GetPasswordManager(); +ChromePasswordManagerClient::GetPasswordManager() { + return &password_manager_; } void ChromePasswordManagerClient::SetTestObserver( @@ -359,22 +369,27 @@ } bool ChromePasswordManagerClient::OnMessageReceived( - const IPC::Message& message) { + const IPC::Message& message, + content::RenderFrameHost* render_frame_host) { bool handled = true; - IPC_BEGIN_MESSAGE_MAP(ChromePasswordManagerClient, message) + IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(ChromePasswordManagerClient, message, + render_frame_host) // Autofill messages: IPC_MESSAGE_HANDLER(AutofillHostMsg_ShowPasswordGenerationPopup, ShowPasswordGenerationPopup) IPC_MESSAGE_HANDLER(AutofillHostMsg_ShowPasswordEditingPopup, ShowPasswordEditingPopup) + IPC_END_MESSAGE_MAP() + + IPC_BEGIN_MESSAGE_MAP(ChromePasswordManagerClient, message) IPC_MESSAGE_HANDLER(AutofillHostMsg_HidePasswordGenerationPopup, HidePasswordGenerationPopup) IPC_MESSAGE_HANDLER(AutofillHostMsg_PasswordAutofillAgentConstructed, NotifyRendererOfLoggingAvailability) - // Default: IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() + return handled; } @@ -385,6 +400,7 @@ } void ChromePasswordManagerClient::ShowPasswordGenerationPopup( + content::RenderFrameHost* render_frame_host, const gfx::RectF& bounds, int max_length, const autofill::PasswordForm& form) { @@ -394,31 +410,25 @@ popup_controller_ = autofill::PasswordGenerationPopupControllerImpl::GetOrCreate( - popup_controller_, - element_bounds_in_screen_space, - form, - max_length, - driver_.GetPasswordManager(), - observer_, - web_contents(), - web_contents()->GetNativeView()); + popup_controller_, element_bounds_in_screen_space, form, max_length, + &password_manager_, + driver_factory_->GetDriverForFrame(render_frame_host), observer_, + web_contents(), web_contents()->GetNativeView()); popup_controller_->Show(true /* display_password */); } void ChromePasswordManagerClient::ShowPasswordEditingPopup( + content::RenderFrameHost* render_frame_host, const gfx::RectF& bounds, const autofill::PasswordForm& form) { gfx::RectF element_bounds_in_screen_space = GetBoundsInScreenSpace(bounds); popup_controller_ = autofill::PasswordGenerationPopupControllerImpl::GetOrCreate( - popup_controller_, - element_bounds_in_screen_space, - form, + popup_controller_, element_bounds_in_screen_space, form, 0, // Unspecified max length. - driver_.GetPasswordManager(), - observer_, - web_contents(), - web_contents()->GetNativeView()); + &password_manager_, + driver_factory_->GetDriverForFrame(render_frame_host), observer_, + web_contents(), web_contents()->GetNativeView()); popup_controller_->Show(false /* display_password */); }
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.h b/chrome/browser/password_manager/chrome_password_manager_client.h index 529047f..634d8e19 100644 --- a/chrome/browser/password_manager/chrome_password_manager_client.h +++ b/chrome/browser/password_manager/chrome_password_manager_client.h
@@ -8,7 +8,8 @@ #include "base/basictypes.h" #include "base/compiler_specific.h" #include "components/password_manager/content/browser/content_credential_manager_dispatcher.h" -#include "components/password_manager/content/browser/content_password_manager_driver.h" +#include "components/password_manager/content/browser/content_password_manager_driver_factory.h" +#include "components/password_manager/core/browser/password_manager.h" #include "components/password_manager/core/browser/password_manager_client.h" #include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_user_data.h" @@ -28,7 +29,7 @@ namespace password_manager { struct CredentialInfo; class PasswordGenerationManager; -class PasswordManager; +class PasswordManagerDriver; } // ChromePasswordManagerClient implements the PasswordManagerClient interface. @@ -42,10 +43,12 @@ // PasswordManagerClient implementation. bool IsAutomaticPasswordSavingEnabled() const override; bool IsPasswordManagerEnabledForCurrentPage() const override; + bool ShouldAskUserToSubmitURL() override; bool ShouldFilterAutofillResult(const autofill::PasswordForm& form) override; std::string GetSyncUsername() const override; bool IsSyncAccountCredential(const std::string& username, const std::string& origin) const override; + void AskUserAndMaybeReportURL(const std::string& url) const override; void AutofillResultsComputed() override; bool PromptUserToSavePassword( scoped_ptr<password_manager::PasswordFormManager> form_to_save) override; @@ -61,7 +64,6 @@ const autofill::PasswordFormMap& best_matches) const override; PrefService* GetPrefs() override; password_manager::PasswordStore* GetPasswordStore() override; - password_manager::PasswordManagerDriver* GetDriver() override; base::FieldTrial::Probability GetProbabilityForExperiment( const std::string& experiment_name) override; bool IsPasswordSyncEnabled( @@ -70,6 +72,9 @@ void LogSavePasswordProgress(const std::string& text) const override; bool IsLoggingActive() const override; bool WasLastNavigationHTTPError() const override; + bool DidLastPageLoadEncounterSSLErrors() override; + bool IsOffTheRecord() override; + password_manager::PasswordManager* GetPasswordManager() override; // Hides any visible generation UI. void HidePasswordGenerationPopup(); @@ -78,16 +83,6 @@ content::WebContents* contents, autofill::AutofillClient* autofill_client); - // Convenience method to allow //chrome code easy access to a PasswordManager - // from a WebContents instance. - static password_manager::PasswordManager* GetManagerFromWebContents( - content::WebContents* contents); - - // Convenience method to allow //chrome code easy access to a - // PasswordGenerationManager from a WebContents instance. - static password_manager::PasswordGenerationManager* - GetGenerationManagerFromWebContents(content::WebContents* contents); - // Observer for PasswordGenerationPopup events. Used for testing. void SetTestObserver(autofill::PasswordGenerationPopupObserver* observer); @@ -113,7 +108,8 @@ friend class content::WebContentsUserData<ChromePasswordManagerClient>; // content::WebContentsObserver overrides. - bool OnMessageReceived(const IPC::Message& message) override; + bool OnMessageReceived(const IPC::Message& message, + content::RenderFrameHost* render_frame_host) override; // Given |bounds| in the renderers coordinate system, return the same bounds // in the screens coordinate system. @@ -122,13 +118,15 @@ // Causes the password generation UI to be shown for the specified form. // The popup will be anchored at |element_bounds|. The generated password // will be no longer than |max_length|. - void ShowPasswordGenerationPopup(const gfx::RectF& bounds, + void ShowPasswordGenerationPopup(content::RenderFrameHost* render_frame_host, + const gfx::RectF& bounds, int max_length, const autofill::PasswordForm& form); // Causes the password editing UI to be shown anchored at |element_bounds|. - void ShowPasswordEditingPopup( - const gfx::RectF& bounds, const autofill::PasswordForm& form); + void ShowPasswordEditingPopup(content::RenderFrameHost* render_frame_host, + const gfx::RectF& bounds, + const autofill::PasswordForm& form); // Sends a message to the renderer with the current value of // |can_use_log_router_|. @@ -147,7 +145,9 @@ Profile* const profile_; - password_manager::ContentPasswordManagerDriver driver_; + password_manager::PasswordManager password_manager_; + + password_manager::ContentPasswordManagerDriverFactory* driver_factory_; password_manager::ContentCredentialManagerDispatcher credential_manager_dispatcher_;
diff --git a/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc b/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc index a8b47c0..fb35ebb2b 100644 --- a/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc +++ b/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
@@ -172,7 +172,8 @@ // Ping the client for logging activity update. AutofillHostMsg_PasswordAutofillAgentConstructed msg(0); - static_cast<IPC::Listener*>(GetClient())->OnMessageReceived(msg); + static_cast<content::WebContentsObserver*>(GetClient())->OnMessageReceived( + msg, web_contents()->GetMainFrame()); bool logging_active = false; EXPECT_TRUE(WasLoggingActivationMessageSent(&logging_active)); @@ -187,7 +188,8 @@ // Ping the client for logging activity update. AutofillHostMsg_PasswordAutofillAgentConstructed msg(0); - static_cast<IPC::Listener*>(GetClient())->OnMessageReceived(msg); + static_cast<content::WebContentsObserver*>(GetClient())->OnMessageReceived( + msg, web_contents()->GetMainFrame()); bool logging_active = true; EXPECT_TRUE(WasLoggingActivationMessageSent(&logging_active)); @@ -221,6 +223,14 @@ EXPECT_FALSE(client->IsLoggingActive()); } +TEST_F(ChromePasswordManagerClientTest, + ShouldAskUserToSubmitURLDefaultBehaviour) { + ChromePasswordManagerClient* client = GetClient(); + // TODO(melandory) Since "Ask user to submit URL" functionality is currently + // in development, so the user should not be asked to submit a URL. + EXPECT_FALSE(client->ShouldAskUserToSubmitURL()); +} + TEST_F(ChromePasswordManagerClientTest, ShouldFilterAutofillResult_Reauth) { // Make client disallow only reauth requests. CommandLine* command_line = CommandLine::ForCurrentProcess();
diff --git a/chrome/browser/policy/OWNERS b/chrome/browser/policy/OWNERS index 32e8aae..78c3a59 100644 --- a/chrome/browser/policy/OWNERS +++ b/chrome/browser/policy/OWNERS
@@ -1,6 +1,4 @@ mnissler@chromium.org -pastarmovj@chromium.org -joaodasilva@chromium.org bartfab@chromium.org atwilson@chromium.org pneubeck@chromium.org
diff --git a/chrome/browser/policy/chrome_browser_policy_connector.h b/chrome/browser/policy/chrome_browser_policy_connector.h index ecca2f6f..2d0fdde 100644 --- a/chrome/browser/policy/chrome_browser_policy_connector.h +++ b/chrome/browser/policy/chrome_browser_policy_connector.h
@@ -44,7 +44,7 @@ // enable-web-based-signin policy is enabled. // TODO(guohui): Needs to move this to a more proper place and also to handle // dynamic refresh. - void AppendExtraFlagPerPolicy(); + void AppendExtraFlagPerPolicy(); DISALLOW_COPY_AND_ASSIGN(ChromeBrowserPolicyConnector); };
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc b/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc index 8f8627d..c5e7f2ba 100644 --- a/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc +++ b/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc
@@ -97,7 +97,7 @@ UserCloudPolicyManager* BuildCloudPolicyManager( content::BrowserContext* context) { - MockUserCloudPolicyStore *store = new MockUserCloudPolicyStore(); + MockUserCloudPolicyStore* store = new MockUserCloudPolicyStore(); EXPECT_CALL(*store, Load()).Times(AnyNumber()); return new UserCloudPolicyManager(
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc index d6e4a3f..ba7269a 100644 --- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc +++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -97,6 +97,12 @@ { key::kForceSafeSearch, prefs::kForceSafeSearch, base::Value::TYPE_BOOLEAN }, + { key::kForceGoogleSafeSearch, + prefs::kForceGoogleSafeSearch, + base::Value::TYPE_BOOLEAN }, + { key::kForceYouTubeSafetyMode, + prefs::kForceYouTubeSafetyMode, + base::Value::TYPE_BOOLEAN }, { key::kPasswordManagerEnabled, password_manager::prefs::kPasswordManagerSavingEnabled, base::Value::TYPE_BOOLEAN }, @@ -532,7 +538,7 @@ ScopedVector<StringMappingListPolicyHandler::MappingEntry>* result) { // Maps feature tags as specified in policy to the corresponding switch to // re-enable them. - // TODO: Remove after 2015-04-30 per http://crbug.com/374782. + // TODO(atwilson): Remove after 2015-04-30 per http://crbug.com/374782. result->push_back(new StringMappingListPolicyHandler::MappingEntry( "ShowModalDialog_EffectiveUntil20150430", scoped_ptr<base::Value>(new base::StringValue(
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc index 939d360..5e9dd5e 100644 --- a/chrome/browser/policy/policy_browsertest.cc +++ b/chrome/browser/policy/policy_browsertest.cc
@@ -69,6 +69,8 @@ #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/browser_tabstrip.h" #include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/extensions/app_launch_params.h" +#include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/browser/ui/host_desktop.h" #include "chrome/browser/ui/location_bar/location_bar.h" #include "chrome/browser/ui/omnibox/omnibox_edit_model.h" @@ -1459,7 +1461,7 @@ EXPECT_TRUE(chrome::ExecuteCommand(browser(), IDC_DEV_TOOLS)); content::WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents(); - DevToolsWindow *devtools_window = + DevToolsWindow* devtools_window = DevToolsWindow::GetInstanceForInspectedWebContents(contents); EXPECT_TRUE(devtools_window); @@ -2435,10 +2437,9 @@ // Launch an app that tries to open a fullscreen window. TestAddAppWindowObserver add_window_observer( extensions::AppWindowRegistry::Get(browser()->profile())); - OpenApplication(AppLaunchParams(browser()->profile(), - extension, - extensions::LAUNCH_CONTAINER_NONE, - NEW_WINDOW)); + OpenApplication(AppLaunchParams(browser()->profile(), extension, + extensions::LAUNCH_CONTAINER_NONE, NEW_WINDOW, + extensions::SOURCE_UNTRACKED)); extensions::AppWindow* window = add_window_observer.WaitForAppWindow(); ASSERT_TRUE(window);
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc index 2225281..a19a01e 100644 --- a/chrome/browser/prefs/browser_prefs.cc +++ b/chrome/browser/prefs/browser_prefs.cc
@@ -125,7 +125,7 @@ #include "extensions/browser/extension_prefs.h" #endif -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) #include "chrome/browser/supervised_user/supervised_user_service.h" #include "chrome/browser/supervised_user/supervised_user_shared_settings_service.h" #include "chrome/browser/supervised_user/supervised_user_sync_service.h" @@ -446,7 +446,7 @@ printing::StickySettings::RegisterProfilePrefs(registry); #endif -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) SupervisedUserService::RegisterProfilePrefs(registry); SupervisedUserSharedSettingsService::RegisterProfilePrefs(registry); SupervisedUserSyncService::RegisterProfilePrefs(registry);
diff --git a/chrome/browser/prefs/browser_ui_prefs_migrator.cc b/chrome/browser/prefs/browser_ui_prefs_migrator.cc deleted file mode 100644 index 6a9fba3..0000000 --- a/chrome/browser/prefs/browser_ui_prefs_migrator.cc +++ /dev/null
@@ -1,73 +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. - -#include "chrome/browser/prefs/browser_ui_prefs_migrator.h" - -#include <set> - -#include "base/memory/scoped_ptr.h" -#include "base/strings/string_util.h" -#include "base/values.h" -#include "chrome/common/pref_names.h" - -BrowserUIPrefsMigrator::BrowserUIPrefsMigrator(WriteablePrefStore* pref_store) - : pref_store_(pref_store) { -} - -BrowserUIPrefsMigrator::~BrowserUIPrefsMigrator() { -} - -void BrowserUIPrefsMigrator::OnInitializationCompleted( - bool succeeded) { - pref_store_->RemoveObserver(this); - scoped_ptr<BrowserUIPrefsMigrator> self_deleter(this); - if (!succeeded) - return; - - base::Value* browser_value = NULL; - if (!pref_store_->GetMutableValue("browser", &browser_value)) - return; - - base::DictionaryValue* browser_dict = NULL; - if (!browser_value->GetAsDictionary(&browser_dict)) - return; - - // Don't bother scanning "browser" if the migration already occurred. - if (browser_dict->HasKey("app_window_placement")) - return; - - // Get a set of keys in the dictionary. This must be done separately from the - // migration because the migration modifies the dictionary being iterated. - std::set<std::string> keys_to_check; - for (base::DictionaryValue::Iterator it(*browser_dict); !it.IsAtEnd(); - it.Advance()) { - keys_to_check.insert(it.key()); - } - - scoped_ptr<base::DictionaryValue> app_window_placement; - // Apps used to have their window placement preferences registered as - // "browser.window_placement_$APPNAME". - const std::string search_for = - std::string(prefs::kBrowserWindowPlacement) + "_"; - for (std::set<std::string>::const_iterator it = keys_to_check.begin(); - it != keys_to_check.end(); - ++it) { - std::string full_key("browser." + *it); - if (StartsWithASCII(full_key, search_for, true /* case_sensitive */)) { - if (full_key == prefs::kBrowserWindowPlacementPopup) - continue; - scoped_ptr<base::Value> single_app_placement_dict; - bool found = browser_dict->Remove(*it, &single_app_placement_dict); - DCHECK(found); - std::string new_key(full_key.substr(search_for.length())); - if (!app_window_placement) - app_window_placement.reset(new base::DictionaryValue); - app_window_placement->Set(new_key, single_app_placement_dict.release()); - } - } - if (app_window_placement) { - pref_store_->SetValue(prefs::kAppWindowPlacement, - app_window_placement.release()); - } -}
diff --git a/chrome/browser/prefs/browser_ui_prefs_migrator.h b/chrome/browser/prefs/browser_ui_prefs_migrator.h deleted file mode 100644 index 7094aca..0000000 --- a/chrome/browser/prefs/browser_ui_prefs_migrator.h +++ /dev/null
@@ -1,40 +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. - -#ifndef CHROME_BROWSER_PREFS_BROWSER_UI_PREFS_MIGRATOR_H_ -#define CHROME_BROWSER_PREFS_BROWSER_UI_PREFS_MIGRATOR_H_ - -#include "base/memory/scoped_ptr.h" -#include "base/prefs/pref_store.h" -#include "base/prefs/writeable_pref_store.h" - -// When prefs are loaded from disk this class migrates some previously -// dynamically registered preferences to their new home in a statically -// registered dictionary. It can't follow the usual migration pattern because -// it is migrating preferences that aren't registered at migration time and has -// to iterate over a raw DictionaryValue looking for keys to migrate. -// -// Objects of this class delete themselves after the migration. -// -// TODO(dgrogan): Delete this for m41. See http://crbug.com/167256. - -class BrowserUIPrefsMigrator : public PrefStore::Observer { - public: - explicit BrowserUIPrefsMigrator(WriteablePrefStore* pref_store); - - // Overrides from PrefStore::Observer. - void OnPrefValueChanged(const std::string& key) override {} - void OnInitializationCompleted(bool succeeded) override; - - private: - friend struct base::DefaultDeleter<BrowserUIPrefsMigrator>; - - ~BrowserUIPrefsMigrator() override; - - WriteablePrefStore* pref_store_; - - DISALLOW_COPY_AND_ASSIGN(BrowserUIPrefsMigrator); -}; - -#endif // CHROME_BROWSER_PREFS_BROWSER_UI_PREFS_MIGRATOR_H_
diff --git a/chrome/browser/prefs/browser_ui_prefs_migrator_unittest.cc b/chrome/browser/prefs/browser_ui_prefs_migrator_unittest.cc deleted file mode 100644 index 575fcea3..0000000 --- a/chrome/browser/prefs/browser_ui_prefs_migrator_unittest.cc +++ /dev/null
@@ -1,139 +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. - -#include "base/observer_list.h" -#include "base/prefs/writeable_pref_store.h" -#include "base/values.h" -#include "chrome/browser/devtools/devtools_window.h" -#include "chrome/browser/prefs/browser_ui_prefs_migrator.h" -#include "chrome/common/pref_names.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -class DictionaryPrefStore : public WriteablePrefStore { - public: - DictionaryPrefStore() : WriteablePrefStore() {} - - // Overrides from PrefStore. - void AddObserver(Observer* observer) override { - observers_.AddObserver(observer); - } - - void RemoveObserver(Observer* observer) override { - observers_.RemoveObserver(observer); - } - - bool GetValue(const std::string& key, - const base::Value** result) const override { - return prefs_.Get(key, result); - } - - // Overrides from WriteablePrefStore. - void SetValue(const std::string& key, base::Value* value) override { - DCHECK(value); - prefs_.Set(key, value); - ReportValueChanged(key); - } - - void RemoveValue(const std::string& key) override { - if (prefs_.RemovePath(key, NULL)) - ReportValueChanged(key); - } - - bool GetMutableValue(const std::string& key, base::Value** result) override { - return prefs_.Get(key, result); - } - - void ReportValueChanged(const std::string& key) override {} - - void SetValueSilently(const std::string& key, base::Value* value) override { - NOTIMPLEMENTED(); - } - - void SignalObservers() { - FOR_EACH_OBSERVER( - PrefStore::Observer, observers_, OnInitializationCompleted(true)); - } - - private: - ~DictionaryPrefStore() override {} - - base::DictionaryValue prefs_; - ObserverList<PrefStore::Observer, true> observers_; - - DISALLOW_COPY_AND_ASSIGN(DictionaryPrefStore); -}; - -} // namespace - -TEST(UIPrefsMigratorTest, MigrateTest) { - scoped_refptr<DictionaryPrefStore> pref_store(new DictionaryPrefStore); - scoped_ptr<base::DictionaryValue> browser_window_placement( - new base::DictionaryValue); - browser_window_placement->SetInteger("bottom", 1000); - pref_store->SetValue(prefs::kBrowserWindowPlacement, - browser_window_placement.release()); - - scoped_ptr<base::DictionaryValue> browser_window_placement_popup( - new base::DictionaryValue); - browser_window_placement_popup->SetInteger("top", 50); - pref_store->SetValue(prefs::kBrowserWindowPlacementPopup, - browser_window_placement_popup.release()); - - scoped_ptr<base::DictionaryValue> single_app_placement_dict( - new base::DictionaryValue); - single_app_placement_dict->SetInteger("right", 986); - const char* kAppName("localhost_/some_app.html"); - const std::string kOldPathToOneAppDictionary = - prefs::kBrowserWindowPlacement + std::string("_") + kAppName; - pref_store->SetValue(kOldPathToOneAppDictionary, - single_app_placement_dict.release()); - EXPECT_TRUE(pref_store->GetValue(kOldPathToOneAppDictionary, NULL)); - - scoped_ptr<base::DictionaryValue> devtools_placement_dict( - new base::DictionaryValue); - devtools_placement_dict->SetInteger("left", 700); - const std::string kOldPathToDevToolsDictionary = - prefs::kBrowserWindowPlacement + std::string("_") + - DevToolsWindow::kDevToolsApp; - pref_store->SetValue(kOldPathToDevToolsDictionary, - devtools_placement_dict.release()); - EXPECT_TRUE(pref_store->GetValue(kOldPathToDevToolsDictionary, NULL)); - - pref_store->AddObserver(new BrowserUIPrefsMigrator(pref_store.get())); - pref_store->SignalObservers(); - - EXPECT_FALSE(pref_store->GetValue(kOldPathToOneAppDictionary, NULL)); - EXPECT_FALSE(pref_store->GetValue(kOldPathToDevToolsDictionary, NULL)); - - const base::Value* value = NULL; - const base::DictionaryValue* dictionary = NULL; - int out_value; - - ASSERT_TRUE(pref_store->GetValue(prefs::kBrowserWindowPlacement, &value)); - ASSERT_TRUE(value->GetAsDictionary(&dictionary)); - EXPECT_TRUE(dictionary->GetInteger("bottom", &out_value)); - EXPECT_EQ(1000, out_value); - - ASSERT_TRUE( - pref_store->GetValue(prefs::kBrowserWindowPlacementPopup, &value)); - ASSERT_TRUE(value->GetAsDictionary(&dictionary)); - EXPECT_TRUE(dictionary->GetInteger("top", &out_value)); - EXPECT_EQ(50, out_value); - - ASSERT_TRUE(pref_store->GetValue( - prefs::kAppWindowPlacement + std::string(".") + kAppName, &value)); - ASSERT_TRUE(value->GetAsDictionary(&dictionary)); - EXPECT_TRUE(dictionary->GetInteger("right", &out_value)); - EXPECT_EQ(986, out_value); - - ASSERT_TRUE(pref_store->GetValue(prefs::kAppWindowPlacement + - std::string(".") + - DevToolsWindow::kDevToolsApp, - &value)); - ASSERT_TRUE(value->GetAsDictionary(&dictionary)); - EXPECT_TRUE(dictionary->GetInteger("left", &out_value)); - EXPECT_EQ(700, out_value); -}
diff --git a/chrome/browser/prefs/chrome_pref_service_factory.cc b/chrome/browser/prefs/chrome_pref_service_factory.cc index 4f66ad2..93c151c 100644 --- a/chrome/browser/prefs/chrome_pref_service_factory.cc +++ b/chrome/browser/prefs/chrome_pref_service_factory.cc
@@ -25,7 +25,6 @@ #include "base/threading/sequenced_worker_pool.h" #include "base/time/time.h" #include "chrome/browser/browser_process.h" -#include "chrome/browser/prefs/browser_ui_prefs_migrator.h" #include "chrome/browser/prefs/command_line_pref_store.h" #include "chrome/browser/prefs/pref_model_associator.h" #include "chrome/browser/prefs/pref_service_syncable.h" @@ -62,7 +61,7 @@ #include "extensions/browser/pref_names.h" #endif -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) #include "chrome/browser/supervised_user/supervised_user_pref_store.h" #endif @@ -198,6 +197,13 @@ PrefHashFilter::TRACKING_STRATEGY_ATOMIC }, #endif + { + 21, prefs::kGoogleServicesUsername, + PrefHashFilter::ENFORCE_ON_LOAD, + PrefHashFilter::TRACKING_STRATEGY_ATOMIC + }, + // See note at top, new items added here also need to be added to + // histograms.xml's TrackedPreference enum. }; // One more than the last tracked preferences ID above. @@ -386,7 +392,7 @@ policy::POLICY_LEVEL_RECOMMENDED))); #endif // ENABLE_CONFIGURATION_POLICY -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) if (supervised_user_settings) { factory->set_supervised_user_prefs( make_scoped_refptr( @@ -466,9 +472,6 @@ ->CreateProfilePrefStore(pref_io_task_runner, start_sync_flare_for_prefs, validation_delegate)); - // BrowserUIPrefsMigrator unregisters and deletes itself after it is done. - user_pref_store->AddObserver( - new BrowserUIPrefsMigrator(user_pref_store.get())); PrepareFactory(&factory, policy_service, supervised_user_settings,
diff --git a/chrome/browser/prerender/prerender_tab_helper.cc b/chrome/browser/prerender/prerender_tab_helper.cc index 6a7bf04..33017f7a 100644 --- a/chrome/browser/prerender/prerender_tab_helper.cc +++ b/chrome/browser/prerender/prerender_tab_helper.cc
@@ -7,6 +7,7 @@ #include "base/bind.h" #include "base/metrics/histogram.h" #include "base/time/time.h" +#include "chrome/browser/password_manager/chrome_password_manager_client.h" #include "chrome/browser/prerender/prerender_histograms.h" #include "chrome/browser/prerender/prerender_local_predictor.h" #include "chrome/browser/prerender/prerender_manager.h" @@ -43,30 +44,18 @@ } // namespace -// static -void PrerenderTabHelper::CreateForWebContentsWithPasswordManager( - content::WebContents* web_contents, - password_manager::PasswordManager* password_manager) { - if (!FromWebContents(web_contents)) { - web_contents->SetUserData(UserDataKey(), - new PrerenderTabHelper(web_contents, - password_manager)); - } -} - -PrerenderTabHelper::PrerenderTabHelper( - content::WebContents* web_contents, - password_manager::PasswordManager* password_manager) +PrerenderTabHelper::PrerenderTabHelper(content::WebContents* web_contents) : content::WebContentsObserver(web_contents), origin_(ORIGIN_NONE), next_load_is_control_prerender_(false), next_load_origin_(ORIGIN_NONE), weak_factory_(this) { - if (password_manager) { - // May be NULL in testing. - password_manager->AddSubmissionCallback( - base::Bind(&PrerenderTabHelper::PasswordSubmitted, - weak_factory_.GetWeakPtr())); + ChromePasswordManagerClient* client = + ChromePasswordManagerClient::FromWebContents(web_contents); + // May be NULL during testing. + if (client) { + client->GetPasswordManager()->AddSubmissionCallback(base::Bind( + &PrerenderTabHelper::PasswordSubmitted, weak_factory_.GetWeakPtr())); } // Determine if this is a prerender.
diff --git a/chrome/browser/prerender/prerender_tab_helper.h b/chrome/browser/prerender/prerender_tab_helper.h index 035939b..4008071 100644 --- a/chrome/browser/prerender/prerender_tab_helper.h +++ b/chrome/browser/prerender/prerender_tab_helper.h
@@ -44,10 +44,6 @@ EVENT_MAX_VALUE }; - static void CreateForWebContentsWithPasswordManager( - content::WebContents* web_contents, - password_manager::PasswordManager* password_manager); - ~PrerenderTabHelper() override; // content::WebContentsObserver implementation. @@ -79,8 +75,7 @@ void WouldHavePrerenderedNextLoad(Origin origin); private: - PrerenderTabHelper(content::WebContents* web_contents, - password_manager::PasswordManager* password_manager); + explicit PrerenderTabHelper(content::WebContents* web_contents); friend class content::WebContentsUserData<PrerenderTabHelper>; void RecordEvent(Event event) const;
diff --git a/chrome/browser/profiles/OWNERS b/chrome/browser/profiles/OWNERS index 449e119..f27486c 100644 --- a/chrome/browser/profiles/OWNERS +++ b/chrome/browser/profiles/OWNERS
@@ -13,6 +13,8 @@ willchan@chromium.org per-file incognito_mode_policy_handler*=dconnelly@chromium.org -per-file incognito_mode_policy_handler*=joaodasilva@chromium.org +per-file incognito_mode_policy_handler*=mnissler@chromium.org per-file profile_metrics*=mlerman@chromium.org + +per-file host_zoom_map_browsertest.cc=wjmaclean@chromium.org
diff --git a/chrome/browser/profiles/avatar_menu.cc b/chrome/browser/profiles/avatar_menu.cc index 992a2aa..fce3790 100644 --- a/chrome/browser/profiles/avatar_menu.cc +++ b/chrome/browser/profiles/avatar_menu.cc
@@ -33,7 +33,7 @@ #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) #include "chrome/browser/supervised_user/supervised_user_service.h" #include "chrome/browser/supervised_user/supervised_user_service_factory.h" #endif @@ -53,7 +53,7 @@ Browser* browser) : profile_list_(ProfileList::Create(profile_cache)), menu_actions_(AvatarMenuActions::Create()), -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) supervised_user_observer_(this), #endif profile_info_(profile_cache), @@ -68,7 +68,7 @@ registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED, content::NotificationService::AllSources()); -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) // Register this as an observer of the SupervisedUserService to be notified // of changes to the custodian info. if (browser_) { @@ -203,7 +203,7 @@ base::string16 AvatarMenu::GetSupervisedUserInformation() const { // |browser_| can be NULL in unit_tests. if (browser_ && browser_->profile()->IsSupervised()) { -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) SupervisedUserService* service = SupervisedUserServiceFactory::GetForProfile(browser_->profile()); base::string16 custodian = @@ -247,7 +247,7 @@ observer_->OnAvatarMenuChanged(this); } -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) void AvatarMenu::OnCustodianInfoChanged() { RebuildMenu(); if (observer_)
diff --git a/chrome/browser/profiles/avatar_menu.h b/chrome/browser/profiles/avatar_menu.h index 487f0c4..5b08acf 100644 --- a/chrome/browser/profiles/avatar_menu.h +++ b/chrome/browser/profiles/avatar_menu.h
@@ -20,7 +20,7 @@ #include "content/public/browser/web_contents_observer.h" #include "ui/gfx/image/image.h" -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) #include "chrome/browser/supervised_user/supervised_user_service_observer.h" #endif @@ -38,7 +38,7 @@ // data changes, and the view for this model should forward actions // back to it in response to user events. class AvatarMenu : -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) public SupervisedUserServiceObserver, #endif public content::NotificationObserver { @@ -92,6 +92,13 @@ // True if avatar menu should be displayed. static bool ShouldShowAvatarMenu(); + // Sets |image| to the avatar corresponding to the profile at |profile_path| + // and sets |is_rectangle| to true unless |image| is a built-in profile + // avatar. For built-in profile avatars, returns the non-high res version. + static void GetImageForMenuButton(const base::FilePath& profile_path, + gfx::Image* image, + bool* is_rectangle); + // Compare items by name. static bool CompareItems(const Item* item1, const Item* item2); @@ -146,7 +153,7 @@ const content::NotificationDetails& details) override; private: -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) // SupervisedUserServiceObserver: void OnCustodianInfoChanged() override; #endif @@ -157,7 +164,7 @@ // The controller for avatar menu actions. scoped_ptr<AvatarMenuActions> menu_actions_; -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) // Observes changes to a supervised user's custodian info. ScopedObserver<SupervisedUserService, SupervisedUserServiceObserver> supervised_user_observer_;
diff --git a/chrome/browser/profiles/avatar_menu_desktop.cc b/chrome/browser/profiles/avatar_menu_desktop.cc new file mode 100644 index 0000000..2f5fcba --- /dev/null +++ b/chrome/browser/profiles/avatar_menu_desktop.cc
@@ -0,0 +1,42 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/profiles/avatar_menu.h" + +#include "chrome/browser/browser_process.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/profiles/profile_avatar_icon_util.h" +#include "chrome/browser/profiles/profile_info_cache.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "ui/base/resource/resource_bundle.h" + +// static +void AvatarMenu::GetImageForMenuButton(const base::FilePath& profile_path, + gfx::Image* image, + bool* is_rectangle) { + ProfileInfoCache& cache = + g_browser_process->profile_manager()->GetProfileInfoCache(); + size_t index = cache.GetIndexOfProfileWithPath(profile_path); + if (index == std::string::npos) { + NOTREACHED(); + return; + } + + // If there is a Gaia image available, try to use that. + if (cache.IsUsingGAIAPictureOfProfileAtIndex(index)) { + const gfx::Image* gaia_image = cache.GetGAIAPictureOfProfileAtIndex(index); + if (gaia_image) { + *image = *gaia_image; + *is_rectangle = true; + return; + } + } + + // Otherwise, use the default resource, not the downloaded high-res one. + const size_t icon_index = cache.GetAvatarIconIndexOfProfileAtIndex(index); + const int resource_id = + profiles::GetDefaultAvatarIconResourceIDAtIndex(icon_index); + *image = ResourceBundle::GetSharedInstance().GetNativeImageNamed(resource_id); + *is_rectangle = false; +}
diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc index e97554f2..9ffdfda 100644 --- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc +++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -87,7 +87,7 @@ #endif #endif -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) #include "chrome/browser/supervised_user/supervised_user_service_factory.h" #include "chrome/browser/supervised_user/supervised_user_sync_service_factory.h" #if defined(OS_CHROMEOS) @@ -203,7 +203,7 @@ #if defined(ENABLE_SERVICE_DISCOVERY) local_discovery::PrivetNotificationServiceFactory::GetInstance(); #endif -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) #if defined(OS_CHROMEOS) chromeos::SupervisedUserPasswordServiceFactory::GetInstance(); chromeos::ManagerPasswordServiceFactory::GetInstance();
diff --git a/chrome/browser/profiles/host_zoom_map_browsertest.cc b/chrome/browser/profiles/host_zoom_map_browsertest.cc index 8517d72..e73524e 100644 --- a/chrome/browser/profiles/host_zoom_map_browsertest.cc +++ b/chrome/browser/profiles/host_zoom_map_browsertest.cc
@@ -44,9 +44,9 @@ class ZoomLevelChangeObserver { public: - explicit ZoomLevelChangeObserver(Profile* profile) + explicit ZoomLevelChangeObserver(content::BrowserContext* context) : message_loop_runner_(new content::MessageLoopRunner) { - subscription_ = ZoomEventManager::GetForBrowserContext(profile) + subscription_ = ZoomEventManager::GetForBrowserContext(context) ->AddZoomLevelChangedCallback(base::Bind( &ZoomLevelChangeObserver::OnZoomLevelChanged, base::Unretained(this))); @@ -212,11 +212,35 @@ DISALLOW_COPY_AND_ASSIGN(HostZoomMapSanitizationBrowserTest); }; +// Regression test for crbug.com/437392 +IN_PROC_BROWSER_TEST_F(HostZoomMapBrowserTest, ZoomEventsWorkForOffTheRecord) { + GURL test_url(url::kAboutBlankURL); + std::string test_host(test_url.host()); + std::string test_scheme(test_url.scheme()); + Browser* incognito_browser = + ui_test_utils::OpenURLOffTheRecord(browser()->profile(), test_url); + + content::WebContents* web_contents = + incognito_browser->tab_strip_model()->GetActiveWebContents(); + + content::BrowserContext* context = web_contents->GetBrowserContext(); + EXPECT_TRUE(context->IsOffTheRecord()); + ZoomLevelChangeObserver observer(context); + HostZoomMap* host_zoom_map = HostZoomMap::GetForWebContents(web_contents); + + double new_zoom_level = + host_zoom_map->GetZoomLevelForHostAndScheme(test_scheme, test_host) + 0.5; + host_zoom_map->SetZoomLevelForHostAndScheme(test_scheme, test_host, + new_zoom_level); + observer.BlockUntilZoomLevelForHostHasChanged(test_host); + EXPECT_EQ(new_zoom_level, host_zoom_map->GetZoomLevelForHostAndScheme( + test_scheme, test_host)); +} + // Regression test for crbug.com/435017. IN_PROC_BROWSER_TEST_F(HostZoomMapBrowserTest, EventsForNonDefaultStoragePartition) { ZoomLevelChangeObserver observer(browser()->profile()); - // TODO(wjmaclean): Make this test more general by implementing a way to // force a generic URL to be loaded in a non-default storage partition. This // test currently relies on the signin page being loaded into a non-default
diff --git a/chrome/browser/profiles/off_the_record_profile_impl.cc b/chrome/browser/profiles/off_the_record_profile_impl.cc index fd0a7f9b..1c49110d4 100644 --- a/chrome/browser/profiles/off_the_record_profile_impl.cc +++ b/chrome/browser/profiles/off_the_record_profile_impl.cc
@@ -32,6 +32,8 @@ #include "chrome/browser/ssl/chrome_ssl_host_state_delegate_factory.h" #include "chrome/browser/themes/theme_service.h" #include "chrome/browser/ui/webui/extensions/extension_icon_source.h" +#include "chrome/browser/ui/zoom/chrome_zoom_level_otr_delegate.h" +#include "chrome/browser/ui/zoom/zoom_event_manager.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_switches.h" @@ -235,7 +237,8 @@ scoped_ptr<content::ZoomLevelDelegate> OffTheRecordProfileImpl::CreateZoomLevelDelegate( const base::FilePath& partition_path) { - return nullptr; + return make_scoped_ptr(new chrome::ChromeZoomLevelOTRDelegate( + ZoomEventManager::GetForBrowserContext(this)->GetWeakPtr())); } scoped_refptr<base::SequencedTaskRunner>
diff --git a/chrome/browser/profiles/profile.cc b/chrome/browser/profiles/profile.cc index ebe8fbbb9..61537ee6 100644 --- a/chrome/browser/profiles/profile.cc +++ b/chrome/browser/profiles/profile.cc
@@ -30,10 +30,6 @@ #include "chromeos/chromeos_switches.h" #endif -#if defined(OS_ANDROID) && defined(FULL_SAFE_BROWSING) -#include "chrome/browser/safe_browsing/safe_browsing_service.h" -#endif - #if defined(ENABLE_EXTENSIONS) #include "extensions/browser/pref_names.h" #endif @@ -94,21 +90,10 @@ prefs::kSessionExitType, std::string(), user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); -#if defined(OS_ANDROID) && defined(FULL_SAFE_BROWSING) - // During Finch trail, safe browsing should be turned off - // by default, and not sync'ed with desktop. - // If we want to enable safe browsing on Android, we will - // need to remove this Android-specific code. - registry->RegisterBooleanPref( - prefs::kSafeBrowsingEnabled, - SafeBrowsingService::IsEnabledByFieldTrial(), - user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); -#else registry->RegisterBooleanPref( prefs::kSafeBrowsingEnabled, true, user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); -#endif registry->RegisterBooleanPref( prefs::kSafeBrowsingExtendedReportingEnabled, false,
diff --git a/chrome/browser/profiles/profile_avatar_icon_util.cc b/chrome/browser/profiles/profile_avatar_icon_util.cc index 6c9ea0b..7c77462 100644 --- a/chrome/browser/profiles/profile_avatar_icon_util.cc +++ b/chrome/browser/profiles/profile_avatar_icon_util.cc
@@ -291,35 +291,6 @@ return square_bitmap; } -void GetTransparentBackgroundProfileAvatar(const base::FilePath& profile_path, - gfx::Image* image, - bool* is_rectangle) { - const ProfileInfoCache& cache = - g_browser_process->profile_manager()->GetProfileInfoCache(); - size_t index = cache.GetIndexOfProfileWithPath(profile_path); - if (index == std::string::npos) { - NOTREACHED(); - return; - } - - // If there is a Gaia image available, try to use that. - if (cache.IsUsingGAIAPictureOfProfileAtIndex(index)) { - const gfx::Image* gaia_image = cache.GetGAIAPictureOfProfileAtIndex(index); - if (gaia_image) { - *image = *gaia_image; - *is_rectangle = true; - return; - } - } - - // Otherwise, use the default resource, not the downloaded high-res one. - const size_t icon_index = cache.GetAvatarIconIndexOfProfileAtIndex(index); - const int resource_id = - profiles::GetDefaultAvatarIconResourceIDAtIndex(icon_index); - *image = ResourceBundle::GetSharedInstance().GetNativeImageNamed(resource_id); - *is_rectangle = false; -} - // Helper methods for accessing, transforming and drawing avatar icons. size_t GetDefaultAvatarIconCount() { return kDefaultAvatarIconsCount;
diff --git a/chrome/browser/profiles/profile_avatar_icon_util.h b/chrome/browser/profiles/profile_avatar_icon_util.h index 7215598..6896f5a 100644 --- a/chrome/browser/profiles/profile_avatar_icon_util.h +++ b/chrome/browser/profiles/profile_avatar_icon_util.h
@@ -60,13 +60,6 @@ // so that when resized to a square aspect ratio it looks pretty. SkBitmap GetAvatarIconAsSquare(const SkBitmap& source_bitmap, int scale_factor); -// Sets |image| to the avatar corresponding to the profile at |profile_path| and -// sets |is_rectangle| to true unless |image| is a built-in profile avatar. For -// built-in profile avatars, always return the non-high res version. -void GetTransparentBackgroundProfileAvatar(const base::FilePath& profile_path, - gfx::Image* image, - bool* is_rectangle); - // Gets the number of default avatar icons that exist. size_t GetDefaultAvatarIconCount();
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc index a2295e5..07347c51 100644 --- a/chrome/browser/profiles/profile_impl.cc +++ b/chrome/browser/profiles/profile_impl.cc
@@ -148,7 +148,7 @@ #include "extensions/browser/guest_view/guest_view_manager.h" #endif -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) #include "chrome/browser/supervised_user/supervised_user_settings_service.h" #include "chrome/browser/supervised_user/supervised_user_settings_service_factory.h" #endif @@ -327,6 +327,14 @@ false, user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); registry->RegisterBooleanPref( + prefs::kForceGoogleSafeSearch, + false, + user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); + registry->RegisterBooleanPref( + prefs::kForceYouTubeSafetyMode, + false, + user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); + registry->RegisterBooleanPref( prefs::kRecordHistory, false, user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); @@ -468,7 +476,7 @@ RegisterProfilePrefsForServices(this, pref_registry_.get()); SupervisedUserSettingsService* supervised_user_settings = NULL; -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) supervised_user_settings = SupervisedUserSettingsServiceFactory::GetForProfile(this); supervised_user_settings->Init(
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc index 0868b90..0043a71 100644 --- a/chrome/browser/profiles/profile_io_data.cc +++ b/chrome/browser/profiles/profile_io_data.cc
@@ -20,6 +20,7 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" +#include "base/thread_task_runner_handle.h" #include "base/threading/sequenced_worker_pool.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chrome_notification_types.h" @@ -102,7 +103,7 @@ #include "extensions/common/constants.h" #endif -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) #include "chrome/browser/supervised_user/supervised_user_service.h" #include "chrome/browser/supervised_user/supervised_user_service_factory.h" #include "chrome/browser/supervised_user/supervised_user_url_filter.h" @@ -127,9 +128,9 @@ #include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/chromeos/settings/cros_settings.h" #include "chrome/browser/net/nss_context.h" -#include "chromeos/dbus/cryptohome_client.h" #include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/settings/cros_settings_names.h" +#include "chromeos/tpm_token_info_getter.h" #include "components/user_manager/user.h" #include "components/user_manager/user_manager.h" #include "crypto/nss_util.h" @@ -260,28 +261,28 @@ // v---------------------------------------/ // GetTPMInfoForUserOnUIThread // | -// CryptohomeClient::Pkcs11GetTpmTokenInfoForUser +// chromeos::TPMTokenInfoGetter::Start // | // DidGetTPMInfoForUserOnUIThread // \---------------------------------------v // crypto::InitializeTPMForChromeOSUser -void DidGetTPMInfoForUserOnUIThread(const std::string& username_hash, - chromeos::DBusMethodCallStatus call_status, - const std::string& label, - const std::string& user_pin, - int slot_id) { +void DidGetTPMInfoForUserOnUIThread( + scoped_ptr<chromeos::TPMTokenInfoGetter> getter, + const std::string& username_hash, + const chromeos::TPMTokenInfo& info) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - if (call_status == chromeos::DBUS_METHOD_CALL_FAILURE) { - NOTREACHED() << "dbus error getting TPM info for " << username_hash; - return; + if (info.tpm_is_enabled && info.token_slot_id != -1) { + DVLOG(1) << "Got TPM slot for " << username_hash << ": " + << info.token_slot_id; + BrowserThread::PostTask( + BrowserThread::IO, + FROM_HERE, + base::Bind(&crypto::InitializeTPMForChromeOSUser, + username_hash, info.token_slot_id)); + } else { + NOTREACHED() << "TPMTokenInfoGetter reported invalid token."; } - DVLOG(1) << "Got TPM slot for " << username_hash << ": " << slot_id; - BrowserThread::PostTask( - BrowserThread::IO, - FROM_HERE, - base::Bind( - &crypto::InitializeTPMForChromeOSUser, username_hash, slot_id)); } void GetTPMInfoForUserOnUIThread(const std::string& username, @@ -289,11 +290,22 @@ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); DVLOG(1) << "Getting TPM info from cryptohome for " << " " << username << " " << username_hash; - chromeos::DBusThreadManager::Get() - ->GetCryptohomeClient() - ->Pkcs11GetTpmTokenInfoForUser( - username, - base::Bind(&DidGetTPMInfoForUserOnUIThread, username_hash)); + scoped_ptr<chromeos::TPMTokenInfoGetter> scoped_token_info_getter = + chromeos::TPMTokenInfoGetter::CreateForUserToken( + username, + chromeos::DBusThreadManager::Get()->GetCryptohomeClient(), + base::ThreadTaskRunnerHandle::Get()); + chromeos::TPMTokenInfoGetter* token_info_getter = + scoped_token_info_getter.get(); + + // Bind |token_info_getter| to the callback to ensure it does not go away + // before TPM token info is fetched. + // TODO(tbarzic, pneubeck): Handle this in a nicer way when this logic is + // moved to a separate profile service. + token_info_getter->Start( + base::Bind(&DidGetTPMInfoForUserOnUIThread, + base::Passed(&scoped_token_info_getter), + username_hash)); } void StartTPMSlotInitializationOnIOThread(const std::string& username, @@ -398,7 +410,7 @@ params->proxy_config_service .reset(ProxyServiceFactory::CreateProxyConfigService( profile->GetProxyConfigTracker())); -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) SupervisedUserService* supervised_user_service = SupervisedUserServiceFactory::GetForProfile(profile); params->supervised_user_url_filter = @@ -443,6 +455,8 @@ &enable_referrers_, &enable_do_not_track_, &force_safesearch_, + &force_google_safesearch_, + &force_youtube_safety_mode_, pref_service); scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy = @@ -1028,7 +1042,9 @@ network_delegate->set_profile_path(profile_params_->path); network_delegate->set_cookie_settings(profile_params_->cookie_settings.get()); network_delegate->set_enable_do_not_track(&enable_do_not_track_); - network_delegate->set_force_google_safe_search(&force_safesearch_); + network_delegate->set_force_safe_search(&force_safesearch_); + network_delegate->set_force_google_safe_search(&force_google_safesearch_); + network_delegate->set_force_youtube_safety_mode(&force_youtube_safety_mode_); network_delegate->set_prerender_tracker(profile_params_->prerender_tracker); network_delegate_.reset(network_delegate); @@ -1069,7 +1085,7 @@ profile_params_->resource_prefetch_predictor_observer_.release()); } -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) supervised_user_url_filter_ = profile_params_->supervised_user_url_filter; #endif @@ -1209,6 +1225,8 @@ enable_referrers_.Destroy(); enable_do_not_track_.Destroy(); force_safesearch_.Destroy(); + force_google_safesearch_.Destroy(); + force_youtube_safety_mode_.Destroy(); #if !defined(OS_CHROMEOS) enable_metrics_.Destroy(); #endif
diff --git a/chrome/browser/profiles/profile_io_data.h b/chrome/browser/profiles/profile_io_data.h index 48a59e7..4517252 100644 --- a/chrome/browser/profiles/profile_io_data.h +++ b/chrome/browser/profiles/profile_io_data.h
@@ -239,7 +239,7 @@ } #endif -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) const SupervisedUserURLFilter* supervised_user_url_filter() const { return supervised_user_url_filter_.get(); } @@ -328,7 +328,7 @@ // and needs to be on the main thread. scoped_ptr<net::ProxyConfigService> proxy_config_service; -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) scoped_refptr<const SupervisedUserURLFilter> supervised_user_url_filter; #endif @@ -620,6 +620,8 @@ mutable BooleanPrefMember enable_referrers_; mutable BooleanPrefMember enable_do_not_track_; mutable BooleanPrefMember force_safesearch_; + mutable BooleanPrefMember force_google_safesearch_; + mutable BooleanPrefMember force_youtube_safety_mode_; mutable BooleanPrefMember safe_browsing_enabled_; mutable BooleanPrefMember printing_enabled_; mutable BooleanPrefMember sync_disabled_; @@ -708,7 +710,7 @@ mutable scoped_ptr<ChromeHttpUserAgentSettings> chrome_http_user_agent_settings_; -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) mutable scoped_refptr<const SupervisedUserURLFilter> supervised_user_url_filter_; #endif
diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc index 2def7686..b4af151 100644 --- a/chrome/browser/profiles/profile_manager.cc +++ b/chrome/browser/profiles/profile_manager.cc
@@ -71,7 +71,7 @@ #include "extensions/common/manifest.h" #endif -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) #include "chrome/browser/supervised_user/supervised_user_service.h" #include "chrome/browser/supervised_user/supervised_user_service_factory.h" #endif @@ -1013,7 +1013,7 @@ } #endif -#if defined(ENABLE_MANAGED_USERS) && !defined(OS_ANDROID) +#if defined(ENABLE_SUPERVISED_USERS) && !defined(OS_ANDROID) // Initialization needs to happen after extension system initialization (for // extension::ManagementPolicy) and InitProfileUserPrefs (for setting the // initializing the supervised flag if necessary).
diff --git a/chrome/browser/recovery/recovery_install_global_error.cc b/chrome/browser/recovery/recovery_install_global_error.cc new file mode 100644 index 0000000..739f6adb0 --- /dev/null +++ b/chrome/browser/recovery/recovery_install_global_error.cc
@@ -0,0 +1,143 @@ +// 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. + +#include "chrome/browser/recovery/recovery_install_global_error.h" + +#include "base/prefs/pref_service.h" +#include "chrome/app/chrome_command_ids.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/component_updater/recovery_component_installer.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/global_error/global_error_service.h" +#include "chrome/browser/ui/global_error/global_error_service_factory.h" +#include "chrome/browser/upgrade_detector.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/pref_names.h" +#include "grit/chromium_strings.h" +#include "grit/theme_resources.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" + +RecoveryInstallGlobalError::RecoveryInstallGlobalError(Profile* profile) + : elevation_needed_(false), + profile_(profile), + has_shown_bubble_view_(false) { + GlobalErrorServiceFactory::GetForProfile(profile_)->AddGlobalError(this); + + PrefService* pref = g_browser_process->local_state(); + if (pref->FindPreference(prefs::kRecoveryComponentNeedsElevation)) { + elevation_needed_ = + pref->GetBoolean(prefs::kRecoveryComponentNeedsElevation); + } + if (elevation_needed_) { + GlobalErrorServiceFactory::GetForProfile(profile_)->NotifyErrorsChanged( + this); + } + + pref_registrar_.Init(pref); + pref_registrar_.Add( + prefs::kRecoveryComponentNeedsElevation, + base::Bind(&RecoveryInstallGlobalError::OnElevationRequirementChanged, + base::Unretained(this))); +} + +RecoveryInstallGlobalError::~RecoveryInstallGlobalError() { +} + +void RecoveryInstallGlobalError::Shutdown() { + GlobalErrorServiceFactory::GetForProfile(profile_)->RemoveGlobalError(this); +} + +GlobalError::Severity RecoveryInstallGlobalError::GetSeverity() { + return GlobalError::SEVERITY_HIGH; +} + +bool RecoveryInstallGlobalError::HasMenuItem() { + return HasElevationNotification(); +} + +int RecoveryInstallGlobalError::MenuItemCommandID() { + return IDC_ELEVATED_RECOVERY_DIALOG; +} + +base::string16 RecoveryInstallGlobalError::MenuItemLabel() { + return l10n_util::GetStringUTF16(IDS_UPDATE_NOW); +} + +int RecoveryInstallGlobalError::MenuItemIconResourceID() { + return IDR_UPDATE_MENU_SEVERITY_HIGH; +} + +void RecoveryInstallGlobalError::ExecuteMenuItem(Browser* browser) { + ShowBubbleView(browser); +} + +bool RecoveryInstallGlobalError::HasBubbleView() { + return HasElevationNotification(); +} + +bool RecoveryInstallGlobalError::HasShownBubbleView() { + return has_shown_bubble_view_; +} + +void RecoveryInstallGlobalError::ShowBubbleView(Browser* browser) { + GlobalErrorWithStandardBubble::ShowBubbleView(browser); + has_shown_bubble_view_ = true; +} + +gfx::Image RecoveryInstallGlobalError::GetBubbleViewIcon() { + return ResourceBundle::GetSharedInstance().GetNativeImageNamed( + IDR_UPDATE_MENU_SEVERITY_HIGH); +} + +base::string16 RecoveryInstallGlobalError::GetBubbleViewTitle() { + return l10n_util::GetStringUTF16(IDS_RECOVERY_BUBBLE_TITLE); +} + +std::vector<base::string16> +RecoveryInstallGlobalError::GetBubbleViewMessages() { + return std::vector<base::string16>(1, + l10n_util::GetStringUTF16(IDS_RECOVERY_BUBBLE_TEXT)); +} + +base::string16 RecoveryInstallGlobalError::GetBubbleViewAcceptButtonLabel() { + return l10n_util::GetStringUTF16(IDS_RUN_RECOVERY); +} + +bool RecoveryInstallGlobalError::ShouldAddElevationIconToAcceptButton() { + return true; +} + +base::string16 RecoveryInstallGlobalError::GetBubbleViewCancelButtonLabel() { + return l10n_util::GetStringUTF16(IDS_DECLINE_RECOVERY); +} + +void RecoveryInstallGlobalError::OnBubbleViewDidClose(Browser* browser) { +} + +void RecoveryInstallGlobalError::BubbleViewAcceptButtonPressed(Browser* ) { + component_updater::AcceptedElevatedRecoveryInstall(pref_registrar_.prefs()); +} + +void RecoveryInstallGlobalError::BubbleViewCancelButtonPressed(Browser* ) { + component_updater::DeclinedElevatedRecoveryInstall(pref_registrar_.prefs()); +} + +bool RecoveryInstallGlobalError::HasElevationNotification() const { + // Do not show this bubble if we already have an upgrade notice. + return elevation_needed_ && !UpgradeDetector::GetInstance()->notify_upgrade(); +} + +void RecoveryInstallGlobalError::OnElevationRequirementChanged() { + PrefService* pref = pref_registrar_.prefs(); + DCHECK(pref->FindPreference(prefs::kRecoveryComponentNeedsElevation)); + elevation_needed_ = pref->GetBoolean(prefs::kRecoveryComponentNeedsElevation); + + // Got a new elevation request, resets |has_shown_bubble_view_| so the + // bubble has a higher priority to show. + if (elevation_needed_) + has_shown_bubble_view_ = false; + + GlobalErrorServiceFactory::GetForProfile(profile_)->NotifyErrorsChanged(this); +}
diff --git a/chrome/browser/recovery/recovery_install_global_error.h b/chrome/browser/recovery/recovery_install_global_error.h new file mode 100644 index 0000000..82c1883 --- /dev/null +++ b/chrome/browser/recovery/recovery_install_global_error.h
@@ -0,0 +1,62 @@ +// 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. + +#ifndef CHROME_BROWSER_RECOVERY_RECOVERY_INSTALL_GLOBAL_ERROR_H_ +#define CHROME_BROWSER_RECOVERY_RECOVERY_INSTALL_GLOBAL_ERROR_H_ + +#include "base/prefs/pref_change_registrar.h" +#include "chrome/browser/ui/global_error/global_error.h" +#include "components/keyed_service/core/keyed_service.h" + +class Profile; + +// Shows elevation needed for recovery component install on the wrench menu +// using a bubble view and a menu item. +class RecoveryInstallGlobalError : public GlobalErrorWithStandardBubble, + public KeyedService { + public: + explicit RecoveryInstallGlobalError(Profile* profile); + virtual ~RecoveryInstallGlobalError(); + + private: + // KeyedService: + virtual void Shutdown() override; + + // GlobalErrorWithStandardBubble: + virtual Severity GetSeverity() override; + virtual bool HasMenuItem() override; + virtual int MenuItemCommandID() override; + virtual base::string16 MenuItemLabel() override; + virtual int MenuItemIconResourceID() override; + virtual void ExecuteMenuItem(Browser* browser) override; + virtual bool HasBubbleView() override; + virtual bool HasShownBubbleView() override; + virtual void ShowBubbleView(Browser* browser) override; + virtual gfx::Image GetBubbleViewIcon() override; + virtual base::string16 GetBubbleViewTitle() override; + virtual std::vector<base::string16> GetBubbleViewMessages() override; + virtual base::string16 GetBubbleViewAcceptButtonLabel() override; + virtual bool ShouldAddElevationIconToAcceptButton() override; + virtual base::string16 GetBubbleViewCancelButtonLabel() override; + virtual void OnBubbleViewDidClose(Browser* browser) override; + virtual void BubbleViewAcceptButtonPressed(Browser* browser) override; + virtual void BubbleViewCancelButtonPressed(Browser* browser) override; + + bool HasElevationNotification() const; + void OnElevationRequirementChanged(); + + bool elevation_needed_; + + // The Profile this service belongs to. + Profile* profile_; + + // Monitors registry change for recovery component install. + PrefChangeRegistrar pref_registrar_; + + bool has_shown_bubble_view_; + + DISALLOW_COPY_AND_ASSIGN(RecoveryInstallGlobalError); +}; + +#endif // CHROME_BROWSER_RECOVERY_RECOVERY_INSTALL_GLOBAL_ERROR_H_
diff --git a/chrome/browser/recovery/recovery_install_global_error_factory.cc b/chrome/browser/recovery/recovery_install_global_error_factory.cc new file mode 100644 index 0000000..a44477c1 --- /dev/null +++ b/chrome/browser/recovery/recovery_install_global_error_factory.cc
@@ -0,0 +1,42 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/recovery/recovery_install_global_error_factory.h" + +#include "chrome/browser/browser_process.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/recovery/recovery_install_global_error.h" +#include "chrome/browser/ui/global_error/global_error_service_factory.h" +#include "components/keyed_service/content/browser_context_dependency_manager.h" + +RecoveryInstallGlobalErrorFactory::RecoveryInstallGlobalErrorFactory() + : BrowserContextKeyedServiceFactory( + "RecoveryInstallGlobalError", + BrowserContextDependencyManager::GetInstance()) { + DependsOn(GlobalErrorServiceFactory::GetInstance()); +} + +RecoveryInstallGlobalErrorFactory::~RecoveryInstallGlobalErrorFactory() {} + +// static +RecoveryInstallGlobalError* +RecoveryInstallGlobalErrorFactory::GetForProfile(Profile* profile) { + return static_cast<RecoveryInstallGlobalError*>( + GetInstance()->GetServiceForBrowserContext(profile, true)); +} + +// static +RecoveryInstallGlobalErrorFactory* +RecoveryInstallGlobalErrorFactory::GetInstance() { + return Singleton<RecoveryInstallGlobalErrorFactory>::get(); +} + +KeyedService* RecoveryInstallGlobalErrorFactory::BuildServiceInstanceFor( + content::BrowserContext* context) const { +#if defined(OS_WIN) || defined(OS_MACOSX) + return new RecoveryInstallGlobalError(static_cast<Profile*>(context)); +#else + return NULL; +#endif +}
diff --git a/chrome/browser/recovery/recovery_install_global_error_factory.h b/chrome/browser/recovery/recovery_install_global_error_factory.h new file mode 100644 index 0000000..d9ed43c --- /dev/null +++ b/chrome/browser/recovery/recovery_install_global_error_factory.h
@@ -0,0 +1,40 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_RECOVERY_RECOVERY_INSTALL_GLOBAL_ERROR_FACTORY_H_ +#define CHROME_BROWSER_RECOVERY_RECOVERY_INSTALL_GLOBAL_ERROR_FACTORY_H_ + +#include "base/memory/singleton.h" +#include "components/keyed_service/content/browser_context_keyed_service_factory.h" + +class Profile; +class RecoveryInstallGlobalError; + +// Singleton that owns all RecoveryInstallGlobalError and associates them with +// Profiles. Listens for the Profile's destruction notification and cleans up +// the associated RecoveryInstallGlobalError. +class RecoveryInstallGlobalErrorFactory + : public BrowserContextKeyedServiceFactory { + public: + // Returns the instance of RecoveryInstallGlobalError associated with this + // profile, creating one if none exists. + static RecoveryInstallGlobalError* GetForProfile(Profile* profile); + + // Returns an instance of the RecoveryInstallGlobalErrorFactory singleton. + static RecoveryInstallGlobalErrorFactory* GetInstance(); + + private: + friend struct DefaultSingletonTraits<RecoveryInstallGlobalErrorFactory>; + + RecoveryInstallGlobalErrorFactory(); + virtual ~RecoveryInstallGlobalErrorFactory(); + + // BrowserContextKeyedServiceFactory: + virtual KeyedService* BuildServiceInstanceFor( + content::BrowserContext* profile) const override; + + DISALLOW_COPY_AND_ASSIGN(RecoveryInstallGlobalErrorFactory); +}; + +#endif // CHROME_BROWSER_RECOVERY_RECOVERY_INSTALL_GLOBAL_ERROR_FACTORY_H_
diff --git a/chrome/browser/renderer_context_menu/context_menu_content_type_extension_popup.cc b/chrome/browser/renderer_context_menu/context_menu_content_type_extension_popup.cc index 46e61b3..9d331405 100644 --- a/chrome/browser/renderer_context_menu/context_menu_content_type_extension_popup.cc +++ b/chrome/browser/renderer_context_menu/context_menu_content_type_extension_popup.cc
@@ -15,6 +15,8 @@ bool ContextMenuContentTypeExtensionPopup::SupportsGroup(int group) { switch (group) { + case ITEM_GROUP_LINK: + case ITEM_GROUP_MEDIA_IMAGE: case ITEM_GROUP_EDITABLE: case ITEM_GROUP_COPY: case ITEM_GROUP_SEARCH_PROVIDER:
diff --git a/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc b/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc index ab032da..854f3a4 100644 --- a/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc +++ b/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc
@@ -73,7 +73,7 @@ #include "extensions/common/user_script.h" #endif -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) #include "chrome/browser/supervised_user/supervised_user_resource_throttle.h" #endif @@ -523,7 +523,7 @@ } #endif -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) bool is_subresource_request = resource_type != content::RESOURCE_TYPE_MAIN_FRAME; throttles->push_back(new SupervisedUserResourceThrottle(
diff --git a/chrome/browser/resources/chromeos/chromevox/common/chrome_extension_externs.js b/chrome/browser/resources/chromeos/chromevox/common/chrome_extension_externs.js index d4366b7f..fa859fe 100644 --- a/chrome/browser/resources/chromeos/chromevox/common/chrome_extension_externs.js +++ b/chrome/browser/resources/chromeos/chromevox/common/chrome_extension_externs.js
@@ -1427,13 +1427,11 @@ disclosureTriangle: 'disclosureTriangle', div: 'div', document: 'document', - editableText: 'editableText', embeddedObject: 'embeddedObject', footer: 'footer', form: 'form', grid: 'grid', group: 'group', - growArea: 'growArea', heading: 'heading', horizontalRule: 'horizontalRule', iframe: 'iframe', @@ -1441,7 +1439,6 @@ imageMapLink: 'imageMapLink', imageMap: 'imageMap', image: 'image', - incrementor: 'incrementor', inlineTextBox: 'inlineTextBox', labelText: 'labelText', legend: 'legend', @@ -1487,7 +1484,6 @@ sliderThumb: 'sliderThumb', spinButtonPart: 'spinButtonPart', spinButton: 'spinButton', - splitGroup: 'splitGroup', splitter: 'splitter', staticText: 'staticText', status: 'status',
diff --git a/chrome/browser/resources/hotword/state_manager.js b/chrome/browser/resources/hotword/state_manager.js index 8c10f065..ed0b9c2b 100644 --- a/chrome/browser/resources/hotword/state_manager.js +++ b/chrome/browser/resources/hotword/state_manager.js
@@ -259,10 +259,16 @@ // Start the detector if there's a session and the user is unlocked, and // stops it otherwise. - if (this.sessions_.length && !this.isLocked_) + if (!this.hotwordStatus_.userIsActive) { + // If the user is no longer the active user, we need to shut down the + // detector so that we're no longer using the microphone. As a result, + // the microphone indicator in the task bar is not shown. + this.shutdownDetector_(); + } else if (this.sessions_.length && !this.isLocked_) { this.startDetector_(); - else + } else { this.stopDetector_(); + } if (!chrome.idle.onStateChanged.hasListener( this.idleStateChangedListener_)) {
diff --git a/chrome/browser/resources/local_ntp/local_ntp.css b/chrome/browser/resources/local_ntp/local_ntp.css index 2411901..419eb229 100644 --- a/chrome/browser/resources/local_ntp/local_ntp.css +++ b/chrome/browser/resources/local_ntp/local_ntp.css
@@ -36,7 +36,7 @@ } #logo { - background-image: url(images/google_logo.png@2x); + background-image: url('images/google_logo.png@2x'); background-repeat: no-repeat; background-size: 269px 95px; height: 95px; @@ -46,7 +46,7 @@ } body.alternate-logo #logo { - -webkit-mask-image: url(images/google_logo.png@2x); + -webkit-mask-image: url('images/google_logo.png@2x'); -webkit-mask-repeat: no-repeat; -webkit-mask-size: 100%; background: #eee; @@ -76,7 +76,7 @@ border-top-color: rgb(144, 144, 144); } -.classical #fakebox { +.des-cla #fakebox { box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); } @@ -96,34 +96,39 @@ width: 100%; } -body[dir=rtl] #fakebox > input { +html[dir=rtl] #fakebox > input { padding-left: 0; padding-right: 8px; right: 0; } #fakebox-text { + bottom: 0; color: #bbb; font-family: arial, sans-serif; font-size: 16px; - height: 100%; left: 9px; margin-top: 1px; overflow: hidden; position: absolute; + right: 9px; text-align: initial; text-overflow: ellipsis; + top: 0; vertical-align: middle; visibility: inherit; white-space: nowrap; - width: calc(100% - 2 * 9px); } -body[dir=rtl] #fakebox-text { +html[dir=rtl] #fakebox-text { left: auto; right: 9px; } +.des-cla #fakebox-text { + visibility: hidden; +} + #cursor { background: #333; bottom: 5px; @@ -134,7 +139,7 @@ width: 1px; } -body[dir=rtl] #cursor { +html[dir=rtl] #cursor { left: auto; right: 9px; } @@ -168,11 +173,11 @@ } /* For Google page, add space from Fakebox. */ -.classical #most-visited { +.des-cla #most-visited { margin-top: 51px; } -.md #most-visited { +.des-mat #most-visited { margin-top: 64px; } @@ -187,16 +192,16 @@ text-align: left; } -body[dir=rtl] #mv-tiles { +html[dir=rtl] #mv-tiles { text-align: right; } -.classical #mv-tiles { +.des-cla #mv-tiles { height: calc(2 * 138px); line-height: 138px; } -.md #mv-tiles { +.des-mat #mv-tiles { height: calc(2 * 146px); line-height: 146px; } @@ -212,7 +217,7 @@ outline: none; } -.classical .mv-tile { +.des-cla .mv-tile { background: linear-gradient(#f2f2f2, #e8e8e8); border-radius: 3px; box-shadow: inset 0 2px 3px rgba(0, 0, 0, .09); @@ -222,26 +227,26 @@ width: 140px; } -.classical .mv-page-ready { +.des-cla .mv-page-ready { -webkit-transition-duration: 200ms; -webkit-transition-property: -webkit-transform, margin, opacity, width; } -.md .mv-tile { +.des-mat .mv-tile { background: rgb(242,242,242); - border-radius: 1px; + border-radius: 2px; height: 130px; margin-left: 8px; margin-right: 8px; width: 156px; } -.md .mv-page-ready { +.des-mat .mv-page-ready { -webkit-transition-duration: 200ms; -webkit-transition-property: -webkit-transform, margin, opacity, width; } -.md.dark .mv-tile { +.des-mat.dark .mv-tile { background: rgb(51,51,51); } @@ -258,11 +263,11 @@ opacity: 0; } -.classical .mv-tile.mv-blacklist { +.des-cla .mv-tile.mv-blacklist { -webkit-transform: scale(0.5); } -.md .mv-tile.mv-blacklist { +.des-mat .mv-tile.mv-blacklist { -webkit-transform: scale(0, 0); -webkit-transform-origin: 0 41px; margin-left: 0; @@ -281,11 +286,11 @@ position: absolute; } -.classical .mv-mask { +.des-cla .mv-mask { box-shadow: inset 0 2px 3px rgba(0, 0, 0, 0.09); } -.md .mv-mask { +.des-mat .mv-mask { border-color: transparent; border-radius: 2px; height: calc(130px - 2px); @@ -293,55 +298,55 @@ } /* Styling border. */ -.classical .mv-page-ready .mv-mask { +.des-cla .mv-page-ready .mv-mask { border-style: solid; } -.default-theme.classical .mv-page-ready .mv-mask { +.default-theme.des-cla .mv-page-ready .mv-mask { border-color: #c0c0c0; } -.default-theme.classical .mv-page-ready:hover .mv-mask, -.default-theme.classical .mv-page-ready .mv-focused ~ .mv-mask { +.default-theme.des-cla .mv-page-ready:hover .mv-mask, +.default-theme.des-cla .mv-page-ready .mv-focused ~ .mv-mask { border-color: #7f7f7f; } -.default-theme.md.old-hover .mv-page-ready:hover .mv-mask, -.default-theme.md.old-hover .mv-page-ready .mv-focused ~ .mv-mask { +.default-theme.des-mat.old-hover .mv-page-ready:hover .mv-mask, +.default-theme.des-mat.old-hover .mv-page-ready .mv-focused ~ .mv-mask { border-color: #999; } -.default-theme.md.dark .mv-page-ready:hover .mv-mask, -.default-theme.md.dark .mv-page-ready .mv-focused ~ .mv-mask, -.default-theme.md.old-hover.dark .mv-page-ready:hover .mv-mask, -.default-theme.md.old-hover.dark .mv-page-ready .mv-focused ~ .mv-mask { +.default-theme.des-mat.dark .mv-page-ready:hover .mv-mask, +.default-theme.des-mat.dark .mv-page-ready .mv-focused ~ .mv-mask, +.default-theme.des-mat.old-hover.dark .mv-page-ready:hover .mv-mask, +.default-theme.des-mat.old-hover.dark .mv-page-ready .mv-focused ~ .mv-mask { border-color: #888; } /* Styling shadow. */ -.default-theme.md .mv-page-ready .mv-mask { +.default-theme.des-mat .mv-page-ready .mv-mask { -webkit-transition: box-shadow 200ms, border 200ms; } -.default-theme.md .mv-page-ready:hover .mv-mask, -.default-theme.md .mv-page-ready .mv-focused ~ .mv-mask { +.default-theme.des-mat .mv-page-ready:hover .mv-mask, +.default-theme.des-mat .mv-page-ready .mv-focused ~ .mv-mask { box-shadow: 0 1px 2px 0 rgba(0,0,0,0.1), 0 4px 8px 0 rgba(0,0,0,0.2); } -.default-theme.md.dark .mv-page-ready:hover .mv-mask, -.default-theme.md.old-hover .mv-page-ready:hover .mv-mask { +.default-theme.des-mat.dark .mv-page-ready:hover .mv-mask, +.default-theme.des-mat.old-hover .mv-page-ready:hover .mv-mask { box-shadow: none; } /* Styling background. */ -.classical .mv-page .mv-focused ~ .mv-mask { +.des-cla .mv-page .mv-focused ~ .mv-mask { -webkit-transition: background-color 100ms ease-in-out; background: linear-gradient(rgba(255, 255, 255, 0), rgba(255, 255, 255, 0) 80%, rgba(255, 255, 255, 0.9)); background-color: rgba(0, 0, 0, 0.35); } -.md .mv-page .mv-focused ~ .mv-mask { +.des-mat .mv-page .mv-focused ~ .mv-mask { -webkit-transition: box-shadow 200ms, border 200ms, background-color 100ms ease-in-out; background: rgba(0, 0, 0, 0.3); @@ -353,14 +358,14 @@ position: absolute; } -.classical .mv-title { +.des-cla .mv-title { bottom: -27px; height: 18px; left: 0; width: 140px; } -.md .mv-title { +.des-mat .mv-title { bottom: auto; height: 15px; left: 32px; @@ -369,12 +374,12 @@ } @media (-webkit-min-device-pixel-ratio: 2) { - .md .mv-title { + .des-mat .mv-title { top: 8px; } } -body[dir=rtl] .md .mv-title { +html[dir=rtl] .des-mat .mv-title { left: auto; right: 32px; } @@ -385,26 +390,26 @@ position: absolute; } -.classical .mv-thumb, -.classical .mv-mask { +.des-cla .mv-thumb, +.des-cla .mv-mask { height: 83px; width: 138px; } -.classical .mv-thumb { +.des-cla .mv-thumb { border-radius: 2px; left: 1px; top: 1px; } -.classical .mv-mask { +.des-cla .mv-mask { border-radius: 3px; left: 0; top: 0; } -.md .mv-thumb, -.md .mv-thumb-fallback { +.des-mat .mv-thumb, +.des-mat .mv-thumb-fallback { border-radius: 0; height: 94px; left: 4px; @@ -412,22 +417,22 @@ width: 148px; } -body[dir=rtl] .md .mv-thumb, -body[dir=rtl] .md .mv-thumb-fallback { +html[dir=rtl] .des-mat .mv-thumb, +html[dir=rtl] .des-mat .mv-thumb-fallback { left: auto; right: 4px; } -.md .mv-thumb-fallback { +.des-mat .mv-thumb-fallback { background-color: #fff; position: absolute; } -.md.dark .mv-thumb-fallback { +.des-mat.dark .mv-thumb-fallback { background-color: #555; } -.md .mv-thumb-fallback .dot { +.des-mat .mv-thumb-fallback .dot { background-color: #f2f2f2; border-radius: 8px; display: block; @@ -440,7 +445,7 @@ width: 16px; } -.md.dark .mv-thumb-fallback .dot { +.des-mat.dark .mv-thumb-fallback .dot { background-color: #333; } @@ -461,28 +466,28 @@ position: absolute; } -.classical .mv-x { - background-image: url(images/close_2.png); +.des-cla .mv-x { + background-image: url('images/close_2.png'); height: 16px; width: 16px; } -.classical .mv-x:hover, -.classical #mv-notice-x:focus { - background-image: url(images/close_2_hover.png); +.des-cla .mv-x:hover, +.des-cla #mv-notice-x:focus { + background-image: url('images/close_2_hover.png'); } -.classical .mv-x:active, -.classical #mv-notice-x:active { - background-image: url(images/close_2_active.png); +.des-cla .mv-x:active, +.des-cla #mv-notice-x:active { + background-image: url('images/close_2_active.png'); } -.classical .mv-page .mv-x { +.des-cla .mv-page .mv-x { right: 2px; top: 2px; } -body[dir=rtl] .classical .mv-page .mv-x { +html[dir=rtl] .des-cla .mv-page .mv-x { left: 2px; right: auto; } @@ -492,19 +497,20 @@ position: relative; } -.md #mv-notice-x { +.des-mat #mv-notice-x { -webkit-transform: translate(0,-8px); } -.md .mv-x { +.des-mat .mv-x { + border-radius: 2px; height: 32px; width: 32px; } -.md .mv-x .mv-x-inner { +.des-mat .mv-x .mv-x-inner { -webkit-mask-image: -webkit-image-set( - url(images/close_3_mask.png) 1x, - url(images/close_3_mask.png@2x) 2x); + url('images/close_3_mask.png') 1x, + url('images/close_3_mask.png@2x') 2x); -webkit-mask-repeat: no-repeat; -webkit-mask-size: 10px 10px; background-color: rgba(90,90,90,0.7); @@ -517,51 +523,51 @@ width: 10px; } -.md.dark .mv-x .mv-x-inner { +.des-mat.dark .mv-x .mv-x-inner { background-color: rgba(255,255,255,0.7); } -.md .mv-x:hover .mv-x-inner, -.md #mv-notice-x:focus .mv-x-inner { +.des-mat .mv-x:hover .mv-x-inner, +.des-mat #mv-notice-x:focus .mv-x-inner { background-color: rgb(90,90,90); } -.md.dark .mv-x:hover .mv-x-inner, -.md.dark #mv-notice-x:focus .mv-x-inner { +.des-mat.dark .mv-x:hover .mv-x-inner, +.des-mat.dark #mv-notice-x:focus .mv-x-inner { background-color: rgb(255,255,255); } -.md .mv-x:active .mv-x-inner, -.md #mv-notice-x:active .mv-x-inner { +.des-mat .mv-x:active .mv-x-inner, +.des-mat #mv-notice-x:active .mv-x-inner { background-color: rgb(66,133,244); } -.md.dark .mv-x:active .mv-x-inner, -.md.dark #mv-notice-x:active .mv-x-inner { +.des-mat.dark .mv-x:active .mv-x-inner, +.des-mat.dark #mv-notice-x:active .mv-x-inner { background-color: rgba(255,255,255,0.5); } -.md .mv-page .mv-x { - /* background color needs to match .md .mv-tile */ +.des-mat .mv-page .mv-x { + /* background color needs to match .des-mat .mv-tile */ background: linear-gradient(to right, transparent, rgb(242,242,242) 10%); right: 0; top: 0; } -body[dir=rtl] .md .mv-page .mv-x { - /* background color needs to match .md .mv-tile */ +html[dir=rtl] .des-mat .mv-page .mv-x { + /* background color needs to match .des-mat .mv-tile */ background: linear-gradient(to left, transparent, rgb(242,242,242) 10%); left: 0; right: auto; } -.md.dark .mv-page .mv-x { - /* background color needs to match .md.dark .mv-tile */ +.des-mat.dark .mv-page .mv-x { + /* background color needs to match .des-mat.dark .mv-tile */ background: linear-gradient(to right, transparent, rgba(51,51,51,0.9) 30%); } -body[dir=rtl] .md.dark .mv-page .mv-x { - /* background color needs to match .md.dark .mv-tile */ +html[dir=rtl] .des-mat.dark .mv-page .mv-x { + /* background color needs to match .des-mat.dark .mv-tile */ background: linear-gradient(to left, transparent, rgba(51,51,51,0.9) 30%); } @@ -582,26 +588,26 @@ width: 16px; } -.classical .mv-favicon { +.des-cla .mv-favicon { bottom: -7px; left: 62px; } -.md .mv-favicon { +.des-mat .mv-favicon { left: 8px; top: 8px; } -body[dir=rtl] .md .mv-favicon { +html[dir=rtl] .des-mat .mv-favicon { left: auto; right: 8px; top: 8px; } -.md .mv-favicon-fallback { +.des-mat .mv-favicon-fallback { background-image: -webkit-image-set( - url(images/ntp_default_favicon.png) 1x, - url(images/ntp_default_favicon.png@2x) 2x); + url('images/ntp_default_favicon.png') 1x, + url('images/ntp_default_favicon.png@2x') 2x); background-repeat: no-repeat; background-size: 16px 16px; } @@ -674,7 +680,7 @@ z-index: -1; } -body[dir=rtl] #attribution { +html[dir=rtl] #attribution { text-align: right; } @@ -693,7 +699,7 @@ right: 8px; } -body[dir=rtl] #attribution,body[dir=rtl] #recent-tabs { +html[dir=rtl] #attribution,html[dir=rtl] #recent-tabs { left: 8px; right: auto; }
diff --git a/chrome/browser/resources/local_ntp/local_ntp.js b/chrome/browser/resources/local_ntp/local_ntp.js index 3db2d43..d4ec801d 100644 --- a/chrome/browser/resources/local_ntp/local_ntp.js +++ b/chrome/browser/resources/local_ntp/local_ntp.js
@@ -176,8 +176,7 @@ /** * True if a page has been blacklisted and we're waiting on the - * onmostvisitedchange callback. See onMostVisitedChange() for how this - * is used. + * onmostvisitedchange callback. See renderAllTiles() for how this is used. * @type {boolean} */ var isBlacklisting = false; @@ -193,7 +192,7 @@ /** * A flag to indicate Most Visited changed caused by user action. If true, then - * in onMostVisitedChange() tiles remain visible so no flickering occurs. + * in renderAllTiles() tiles remain visible so no flickering occurs. * @type {boolean} */ var userInitiatedMostVisitedChange = false; @@ -338,8 +337,7 @@ var fakeboxText = $(IDS.FAKEBOX_TEXT); if (fakeboxText) { fakeboxText.innerHTML = ''; - if (NTP_DESIGN.showFakeboxHint && - configData.translatedStrings.searchboxPlaceholder) { + if (configData.translatedStrings.searchboxPlaceholder) { fakeboxText.textContent = configData.translatedStrings.searchboxPlaceholder; } @@ -380,7 +378,7 @@ function onThemeChange() { renderTheme(); tilesContainer.innerHTML = ''; - renderAndShowTiles(); + renderAllTiles(); } @@ -495,9 +493,17 @@ /** - * Handles a new set of Most Visited page data. + * Called when page data change. */ function onMostVisitedChange() { + renderAllTiles(); +} + + +/** + * Rerenders all tiles based on Most Visited page data. + */ +function renderAllTiles() { if (isBlacklisting) { // Trigger the blacklist animation, which then triggers reloadAllTiles(). var lastBlacklistedTileElem = lastBlacklistedTile.elem; @@ -521,8 +527,8 @@ lastBlacklistedTile.elem.removeEventListener( 'webkitTransitionEnd', blacklistAnimationDone); // Need to call explicitly to re-render the tiles, since the initial - // onmostvisitedchange issued by the blacklist function only triggered - // the animation. + // renderAllTiles() issued by the blacklist function only triggered the + // animation. reloadAllTiles(); } @@ -543,7 +549,7 @@ /** - * Binds onload events for a tile's internal <iframe> elements. + * Binds onload events for a tile's internal iframe elements. * @param {Tile} tile The main tile to bind events to. * @param {Barrier} tileVisibilityBarrier A barrier to make all tiles visible * the moment all tiles are loaded. @@ -577,7 +583,7 @@ var numDesired = Math.min(tiles.length, numColumnsShown * NUM_ROWS); // If we need to render new tiles, manage the visibility to hide intermediate - // load states of the <iframe>s. + // load states of the iframes. if (numExisting < numDesired) { var showAll = function() { for (var i = 0; i < numDesired; ++i) { @@ -662,7 +668,7 @@ /** * Creates a Tile with the specified page data. If no data is provided, a * filler Tile is created. - * @param {Object} page The page data. + * @param {?Object} page The page data. * @param {number} position The position of the tile. * @return {Tile} The new Tile. */ @@ -670,93 +676,95 @@ var tileElem = document.createElement('div'); tileElem.classList.add(CLASSES.TILE); // Prevent tile from being selected (and highlighted) when areas outside the - // <iframe>s are clicked. + // iframes are clicked. tileElem.addEventListener('mousedown', function(e) { e.preventDefault(); }); - var innerElem = createAndAppendElement(tileElem, 'div', CLASSES.TILE_INNER); - if (page) { - var rid = page.rid; - tileElem.classList.add(CLASSES.PAGE); - - var navigateFunction = function(e) { - e.preventDefault(); - ntpApiHandle.navigateContentWindow(rid, getDispositionFromEvent(e)); - }; - - // The click handler for navigating to the page identified by the RID. - tileElem.addEventListener('click', navigateFunction); - - // The iframe which renders the page title. - var titleElem = document.createElement('iframe'); - // Enable tab navigation on the iframe, which will move the selection to the - // link element (which also has a tabindex). - titleElem.tabIndex = '0'; - - // Why iframes have IDs: - // - // On navigating back to the NTP we see several onmostvisitedchange() events - // in series with incrementing RIDs. After the first event, a set of iframes - // begins loading RIDs n, n+1, ..., n+k-1; after the second event, these get - // destroyed and a new set begins loading RIDs n+k, n+k+1, ..., n+2k-1. - // Now due to crbug.com/68841, Chrome incorrectly loads the content for the - // first set of iframes into the most recent set of iframes. - // - // Giving iframes distinct ids seems to cause some invalidation and prevent - // associating the incorrect data. - // - // TODO(jered): Find and fix the root (probably Blink) bug. - - // Keep this ID here. See comment above. - titleElem.id = 'title-' + rid; - titleElem.className = CLASSES.TITLE; - titleElem.src = getMostVisitedTitleIframeUrl(rid, position); - innerElem.appendChild(titleElem); - - // A fallback element for missing thumbnails. - if (NTP_DESIGN.thumbnailFallback) { - var fallbackElem = createAndAppendElement( - innerElem, 'div', CLASSES.THUMBNAIL_FALLBACK); - if (NTP_DESIGN.thumbnailFallback === THUMBNAIL_FALLBACK.DOT) - createAndAppendElement(fallbackElem, 'div', CLASSES.DOT); - } - - // The iframe which renders either a thumbnail or domain element. - var thumbnailElem = document.createElement('iframe'); - thumbnailElem.tabIndex = '-1'; - thumbnailElem.setAttribute('aria-hidden', 'true'); - // Keep this ID here. See comment above. - thumbnailElem.id = 'thumb-' + rid; - thumbnailElem.className = CLASSES.THUMBNAIL; - thumbnailElem.src = getMostVisitedThumbnailIframeUrl(rid, position); - innerElem.appendChild(thumbnailElem); - - // The button used to blacklist this page. - var blacklistButton = createAndAppendElement( - innerElem, 'div', CLASSES.BLACKLIST_BUTTON); - createAndAppendElement( - blacklistButton, 'div', CLASSES.BLACKLIST_BUTTON_INNER); - var blacklistFunction = generateBlacklistFunction(rid); - blacklistButton.addEventListener('click', blacklistFunction); - blacklistButton.title = configData.translatedStrings.removeThumbnailTooltip; - - // A helper mask on top of the tile that is used to create hover border - // and/or to darken the thumbnail on focus. - var maskElement = createAndAppendElement( - innerElem, 'div', CLASSES.THUMBNAIL_MASK); - - // The page favicon, or a fallback. - var favicon = createAndAppendElement(innerElem, 'div', CLASSES.FAVICON); - if (page.faviconUrl) { - favicon.style.backgroundImage = 'url(' + page.faviconUrl + ')'; - } else { - favicon.classList.add(CLASSES.FAVICON_FALLBACK); - } - return new Tile(tileElem, innerElem, titleElem, thumbnailElem, rid); - } else { + if (!page) { return new Tile(tileElem); } + + var rid = page.rid; + tileElem.classList.add(CLASSES.PAGE); + + var navigateFunction = function(e) { + e.preventDefault(); + ntpApiHandle.navigateContentWindow(rid, getDispositionFromEvent(e)); + }; + + // The click handler for navigating to the page identified by the RID. + tileElem.addEventListener('click', navigateFunction); + + // Container of tile contents. + var innerElem = createAndAppendElement(tileElem, 'div', CLASSES.TILE_INNER); + + // The iframe which renders the page title. + var titleElem = document.createElement('iframe'); + // Enable tab navigation on the iframe, which will move the selection to the + // link element (which also has a tabindex). + titleElem.tabIndex = '0'; + + // Why iframes have IDs: + // + // On navigating back to the NTP we see several onmostvisitedchange() events + // in series with incrementing RIDs. After the first event, a set of iframes + // begins loading RIDs n, n+1, ..., n+k-1; after the second event, these get + // destroyed and a new set begins loading RIDs n+k, n+k+1, ..., n+2k-1. + // Now due to crbug.com/68841, Chrome incorrectly loads the content for the + // first set of iframes into the most recent set of iframes. + // + // Giving iframes distinct ids seems to cause some invalidation and prevent + // associating the incorrect data. + // + // TODO(jered): Find and fix the root (probably Blink) bug. + + // Keep this ID here. See comment above. + titleElem.id = 'title-' + rid; + titleElem.className = CLASSES.TITLE; + titleElem.src = getMostVisitedTitleIframeUrl(rid, position); + innerElem.appendChild(titleElem); + + // A fallback element for missing thumbnails. + if (NTP_DESIGN.thumbnailFallback) { + var fallbackElem = createAndAppendElement( + innerElem, 'div', CLASSES.THUMBNAIL_FALLBACK); + if (NTP_DESIGN.thumbnailFallback === THUMBNAIL_FALLBACK.DOT) + createAndAppendElement(fallbackElem, 'div', CLASSES.DOT); + } + + // The iframe which renders either a thumbnail or domain element. + var thumbnailElem = document.createElement('iframe'); + thumbnailElem.tabIndex = '-1'; + thumbnailElem.setAttribute('aria-hidden', 'true'); + // Keep this ID here. See comment above. + thumbnailElem.id = 'thumb-' + rid; + thumbnailElem.className = CLASSES.THUMBNAIL; + thumbnailElem.src = getMostVisitedThumbnailIframeUrl(rid, position); + innerElem.appendChild(thumbnailElem); + + // The button used to blacklist this page. + var blacklistButton = createAndAppendElement( + innerElem, 'div', CLASSES.BLACKLIST_BUTTON); + createAndAppendElement( + blacklistButton, 'div', CLASSES.BLACKLIST_BUTTON_INNER); + var blacklistFunction = generateBlacklistFunction(rid); + blacklistButton.addEventListener('click', blacklistFunction); + blacklistButton.title = configData.translatedStrings.removeThumbnailTooltip; + + // A helper mask on top of the tile that is used to create hover border + // and/or to darken the thumbnail on focus. + var maskElement = createAndAppendElement( + innerElem, 'div', CLASSES.THUMBNAIL_MASK); + + // The page favicon, or a fallback. + var favicon = createAndAppendElement(innerElem, 'div', CLASSES.FAVICON); + if (page.faviconUrl) { + favicon.style.backgroundImage = 'url(' + page.faviconUrl + ')'; + } else { + favicon.classList.add(CLASSES.FAVICON_FALLBACK); + } + return new Tile(tileElem, innerElem, titleElem, thumbnailElem, rid); } @@ -1135,7 +1143,7 @@ onInputStart(); renderTheme(); - onMostVisitedChange(); + renderAllTiles(); searchboxApiHandle = topLevelHandle.searchBox; @@ -1180,9 +1188,10 @@ if (searchboxApiHandle.rtl) { $(IDS.NOTIFICATION).dir = 'rtl'; - document.body.setAttribute('dir', 'rtl'); + // Grabbing the root HTML element. + document.documentElement.setAttribute('dir', 'rtl'); // Add class for setting alignments based on language directionality. - document.body.classList.add(CLASSES.RTL); + document.documentElement.classList.add(CLASSES.RTL); $(IDS.TILES).dir = 'rtl'; }
diff --git a/chrome/browser/resources/local_ntp/local_ntp_design.js b/chrome/browser/resources/local_ntp/local_ntp_design.js index 7434209..e2c46944 100644 --- a/chrome/browser/resources/local_ntp/local_ntp_design.js +++ b/chrome/browser/resources/local_ntp/local_ntp_design.js
@@ -14,9 +14,8 @@ /** * Specifications for an NTP design (not comprehensive). * - * name: A unique identifier for the style. - * fontFamily: Font family to use for title and thumbnail <iframe>s. - * fontSize: Font size to use for the <iframe>s, in px. + * fontFamily: Font family to use for title and thumbnail iframes. + * fontSize: Font size to use for the iframes, in px. * tileWidth: The width of each suggestion tile, in px. * tileMargin: Spacing between successive tiles, in px. * titleColor: The RRGGBBAA color of title text. @@ -25,15 +24,13 @@ * default value is 'center'. * titleTextFade: (Optional) The number of pixels beyond which title * text begins to fade. This overrides the default ellipsis style. - * thumbnailTextColor: The RRGGBBAA color that thumbnail <iframe> may use to + * thumbnailTextColor: The RRGGBBAA color that thumbnail iframe may use to * display text message in place of missing thumbnail. * thumbnailFallback: (Optional) A value in THUMBNAIL_FALLBACK to specify the * thumbnail fallback strategy. If unassigned, then the thumbnail.html - * <iframe> would handle the fallback. - * showFakeboxHint: Whether to display text in the fakebox. + * iframe would handle the fallback. * * @typedef {{ - * name: string, * fontFamily: string, * fontSize: number, * tileWidth: number, @@ -41,10 +38,9 @@ * titleColor: string, * titleColorAgainstDark: string, * titleTextAlign: string|null|undefined, - * titleTextFade: string|null|undefined, + * titleTextFade: number|null|undefined, * thumbnailTextColor: string, * thumbnailFallback: string|null|undefined - * showFakeboxHint: string|null|undefined * }} */ var NtpDesign; @@ -58,9 +54,8 @@ function getNtpDesign(opt_name) { var ntpDesign = null; - if (opt_name === 'md') { + if (opt_name === 'des-mat') { ntpDesign = { - name: opt_name, fontFamily: 'arial, sans-serif', fontSize: 12, tileWidth: 156, @@ -70,12 +65,10 @@ titleTextAlign: 'inherit', titleTextFade: 122 - 36, // 112px wide title with 32 pixel fade at end. thumbnailTextColor: '323232ff', // Unused. - thumbnailFallback: THUMBNAIL_FALLBACK.DOT, - showFakeboxHint: true + thumbnailFallback: THUMBNAIL_FALLBACK.DOT }; } else { ntpDesign = { - name: 'classical', fontFamily: 'arial, sans-serif', fontSize: 11, tileWidth: 140, @@ -85,8 +78,7 @@ titleTextAlign: 'center', titleTextFade: null, // Default to ellipsis. thumbnailTextColor: '777777ff', - thumbnailFallback: null, // Default to false. - showFakeboxHint: false + thumbnailFallback: null // Default to false. }; } return ntpDesign;
diff --git a/chrome/browser/resources/options/chromeos/onc_data.js b/chrome/browser/resources/options/chromeos/onc_data.js index 4dd3067..38a758c 100644 --- a/chrome/browser/resources/options/chromeos/onc_data.js +++ b/chrome/browser/resources/options/chromeos/onc_data.js
@@ -47,7 +47,7 @@ * Sets the value of a property. Currently only supports unmanaged * properties. * @param {string} key The property key. - * @param {Object} value The property value to set. + * @param {?} value The property value to set. */ setProperty: function(key, value) { var data = this.data_;
diff --git a/chrome/browser/resources/options/handler_options_list.js b/chrome/browser/resources/options/handler_options_list.js index a3e4fa1..733492d4 100644 --- a/chrome/browser/resources/options/handler_options_list.js +++ b/chrome/browser/resources/options/handler_options_list.js
@@ -188,7 +188,7 @@ this.appendChild(indicator); } - if (data.registered_by_user) { + if (data.is_default_handler_set_by_user) { // Remove link. var removeElement = document.createElement('div'); removeElement.textContent =
diff --git a/chrome/browser/resources/options/inline_editable_list.js b/chrome/browser/resources/options/inline_editable_list.js index 204ada7a..0e37c57 100644 --- a/chrome/browser/resources/options/inline_editable_list.js +++ b/chrome/browser/resources/options/inline_editable_list.js
@@ -138,9 +138,18 @@ cr.dispatchSimpleEvent(this, 'edit', true); + var isMouseClick = this.editClickTarget_; var focusElement = this.getEditFocusElement_(); - if (focusElement) - this.focusAndMaybeSelect_(focusElement); + if (focusElement) { + if (isMouseClick) { + // Delay focus to fix http://crbug.com/436789 + setTimeout(function() { + this.focusAndMaybeSelect_(focusElement); + }.bind(this), 0); + } else { + this.focusAndMaybeSelect_(focusElement); + } + } } else { if (!this.editCancelled_ && this.hasBeenEdited && this.currentInputIsValid) {
diff --git a/chrome/browser/resources/pdf/pdf.js b/chrome/browser/resources/pdf/pdf.js index 18317eb..57b80c3 100644 --- a/chrome/browser/resources/pdf/pdf.js +++ b/chrome/browser/resources/pdf/pdf.js
@@ -55,12 +55,18 @@ this.beforeZoom_.bind(this), this.afterZoom_.bind(this), getScrollbarWidth()); - + var isPrintPreview = + this.streamDetails.originalUrl.indexOf('chrome://print') == 0; // Create the plugin object dynamically so we can set its src. The plugin // element is sized to fill the entire window and is set to be fixed // positioning, acting as a viewport. The plugin renders into this viewport // according to the scroll position of the window. - this.plugin_ = document.createElement('embed'); + // + // TODO(sammc): Remove special casing for print preview. This is currently + // necessary because setting the src for an embed element triggers origin + // checking and the PDF extension is not allowed to embed URLs with a scheme + // of "chrome", which is used by print preview. + this.plugin_ = document.createElement(isPrintPreview ? 'object' : 'embed'); // NOTE: The plugin's 'id' field must be set to 'plugin' since // chrome/renderer/printing/print_web_view_helper.cc actually references it. this.plugin_.id = 'plugin';
diff --git a/chrome/browser/resources/plugin_metadata/plugins_chromeos.json b/chrome/browser/resources/plugin_metadata/plugins_chromeos.json index 6268175..57e36857 100644 --- a/chrome/browser/resources/plugin_metadata/plugins_chromeos.json +++ b/chrome/browser/resources/plugin_metadata/plugins_chromeos.json
@@ -1,5 +1,5 @@ { - "x-version": 1, + "x-version": 2, "google-talk": { "mime_types": [ ],
diff --git a/chrome/browser/resources/plugin_metadata/plugins_linux.json b/chrome/browser/resources/plugin_metadata/plugins_linux.json index 7855c7c9..7ddd998 100644 --- a/chrome/browser/resources/plugin_metadata/plugins_linux.json +++ b/chrome/browser/resources/plugin_metadata/plugins_linux.json
@@ -1,5 +1,5 @@ { - "x-version": 4, + "x-version": 5, "google-talk": { "mime_types": [ ],
diff --git a/chrome/browser/resources/plugin_metadata/plugins_mac.json b/chrome/browser/resources/plugin_metadata/plugins_mac.json index 28a2c91..cb424a9 100644 --- a/chrome/browser/resources/plugin_metadata/plugins_mac.json +++ b/chrome/browser/resources/plugin_metadata/plugins_mac.json
@@ -1,5 +1,5 @@ { - "x-version": 5, + "x-version": 6, "google-talk": { "mime_types": [ ],
diff --git a/chrome/browser/resources/plugin_metadata/plugins_win.json b/chrome/browser/resources/plugin_metadata/plugins_win.json index 5ddd6088..5d2229c 100644 --- a/chrome/browser/resources/plugin_metadata/plugins_win.json +++ b/chrome/browser/resources/plugin_metadata/plugins_win.json
@@ -1,5 +1,5 @@ { - "x-version": 14, + "x-version": 15, "google-talk": { "mime_types": [ ],
diff --git a/chrome/browser/resources/user_manager/user_manager_tutorial.html b/chrome/browser/resources/user_manager/user_manager_tutorial.html index c1da41d..16b9a06 100644 --- a/chrome/browser/resources/user_manager/user_manager_tutorial.html +++ b/chrome/browser/resources/user_manager/user_manager_tutorial.html
@@ -49,6 +49,7 @@ <div id="dismiss-bubble-button"></div> <div class="slide-buttons"> <div class="slide-text" i18n-content="slideCompleteUserNotFound"></div> + <br> <a is="action-link" id="slide-add-user" i18n-content="slideCompleteAddUser"></a> </div>
diff --git a/chrome/browser/safe_browsing/safe_browsing_service.cc b/chrome/browser/safe_browsing/safe_browsing_service.cc index 059a3d7..7cd72e3 100644 --- a/chrome/browser/safe_browsing/safe_browsing_service.cc +++ b/chrome/browser/safe_browsing/safe_browsing_service.cc
@@ -27,10 +27,6 @@ #include "chrome/browser/safe_browsing/client_side_detection_service.h" #include "chrome/browser/safe_browsing/database_manager.h" #include "chrome/browser/safe_browsing/download_protection_service.h" -#include "chrome/browser/safe_browsing/incident_reporting/binary_integrity_analyzer.h" -#include "chrome/browser/safe_browsing/incident_reporting/blacklist_load_analyzer.h" -#include "chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.h" -#include "chrome/browser/safe_browsing/incident_reporting/off_domain_inclusion_detector.h" #include "chrome/browser/safe_browsing/malware_details.h" #include "chrome/browser/safe_browsing/ping_manager.h" #include "chrome/browser/safe_browsing/protocol_manager.h" @@ -55,9 +51,11 @@ #include "chrome/installer/util/browser_distribution.h" #endif -#if defined(OS_ANDROID) -#include <string> -#include "base/metrics/field_trial.h" +#if defined(FULL_SAFE_BROWSING) +#include "chrome/browser/safe_browsing/incident_reporting/binary_integrity_analyzer.h" +#include "chrome/browser/safe_browsing/incident_reporting/blacklist_load_analyzer.h" +#include "chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.h" +#include "chrome/browser/safe_browsing/incident_reporting/off_domain_inclusion_detector.h" #endif using content::BrowserThread; @@ -188,14 +186,6 @@ return factory_->CreateSafeBrowsingService(); } -#if defined(OS_ANDROID) && defined(FULL_SAFE_BROWSING) -// static -bool SafeBrowsingService::IsEnabledByFieldTrial() { - const std::string experiment_name = - base::FieldTrialList::FindFullName("SafeBrowsingAndroid"); - return experiment_name == "Enabled"; -} -#endif SafeBrowsingService::SafeBrowsingService() : protocol_manager_(NULL), @@ -285,8 +275,11 @@ // on it. csd_service_.reset(); +#if defined(FULL_SAFE_BROWSING) off_domain_inclusion_detector_.reset(); incident_service_.reset(); +#endif + download_service_.reset(); url_request_context_getter_ = NULL; @@ -345,13 +338,13 @@ return scoped_ptr<TrackedPreferenceValidationDelegate>(); } +#if defined(FULL_SAFE_BROWSING) void SafeBrowsingService::RegisterDelayedAnalysisCallback( const safe_browsing::DelayedAnalysisCallback& callback) { -#if defined(FULL_SAFE_BROWSING) if (incident_service_) incident_service_->RegisterDelayedAnalysisCallback(callback); -#endif } +#endif void SafeBrowsingService::AddDownloadManager( content::DownloadManager* download_manager) {
diff --git a/chrome/browser/safe_browsing/safe_browsing_service.h b/chrome/browser/safe_browsing/safe_browsing_service.h index d69f585..6230e7ac 100644 --- a/chrome/browser/safe_browsing/safe_browsing_service.h +++ b/chrome/browser/safe_browsing/safe_browsing_service.h
@@ -17,12 +17,15 @@ #include "base/memory/scoped_ptr.h" #include "base/observer_list.h" #include "base/sequenced_task_runner_helpers.h" -#include "chrome/browser/safe_browsing/incident_reporting/delayed_analysis_callback.h" #include "chrome/browser/safe_browsing/safe_browsing_util.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" +#if defined(FULL_SAFE_BROWSING) +#include "chrome/browser/safe_browsing/incident_reporting/delayed_analysis_callback.h" +#endif + class PrefChangeRegistrar; class PrefService; class Profile; @@ -52,8 +55,11 @@ namespace safe_browsing { class ClientSideDetectionService; class DownloadProtectionService; + +#if defined(FULL_SAFE_BROWSING) class IncidentReportingService; class OffDomainInclusionDetector; +#endif } // Construction needs to happen on the main thread. @@ -80,12 +86,6 @@ // Create an instance of the safe browsing service. static SafeBrowsingService* CreateSafeBrowsingService(); -#if defined(OS_ANDROID) && defined(FULL_SAFE_BROWSING) - // Return whether the user is in mobile safe browsing - // field trial enabled group. - static bool IsEnabledByFieldTrial(); -#endif - // Called on the UI thread to initialize the service. void Initialize(); @@ -131,11 +131,13 @@ scoped_ptr<TrackedPreferenceValidationDelegate> CreatePreferenceValidationDelegate(Profile* profile) const; +#if defined(FULL_SAFE_BROWSING) // Registers |callback| to be run after some delay following process launch. // |callback| will be dropped if the service is not applicable for the // process. void RegisterDelayedAnalysisCallback( const safe_browsing::DelayedAnalysisCallback& callback); +#endif // Adds |download_manager| to the set monitored by safe browsing. void AddDownloadManager(content::DownloadManager* download_manager); @@ -250,7 +252,9 @@ // Accessed on UI thread. scoped_ptr<safe_browsing::DownloadProtectionService> download_service_; +#if defined(FULL_SAFE_BROWSING) scoped_ptr<safe_browsing::IncidentReportingService> incident_service_; +#endif // The UI manager handles showing interstitials. Accessed on both UI and IO // thread. @@ -260,8 +264,10 @@ // both UI and IO thread. scoped_refptr<SafeBrowsingDatabaseManager> database_manager_; +#if defined(FULL_SAFE_BROWSING) scoped_ptr<safe_browsing::OffDomainInclusionDetector> off_domain_inclusion_detector_; +#endif DISALLOW_COPY_AND_ASSIGN(SafeBrowsingService); };
diff --git a/chrome/browser/search/hotword_service.cc b/chrome/browser/search/hotword_service.cc index 3bbbb57..94ba90e 100644 --- a/chrome/browser/search/hotword_service.cc +++ b/chrome/browser/search/hotword_service.cc
@@ -8,6 +8,7 @@ #include "base/command_line.h" #include "base/i18n/case_conversion.h" +#include "base/message_loop/message_loop.h" #include "base/metrics/field_trial.h" #include "base/metrics/histogram.h" #include "base/path_service.h" @@ -19,25 +20,34 @@ #include "chrome/browser/extensions/pending_extension_manager.h" #include "chrome/browser/extensions/updater/extension_updater.h" #include "chrome/browser/extensions/webstore_startup_installer.h" +#include "chrome/browser/notifications/notification.h" +#include "chrome/browser/notifications/notification_ui_manager.h" #include "chrome/browser/plugins/plugin_prefs.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/search/hotword_audio_history_handler.h" #include "chrome/browser/search/hotword_service_factory.h" +#include "chrome/browser/ui/extensions/app_launch_params.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/extensions/extension_constants.h" #include "chrome/common/pref_names.h" #include "chrome/grit/generated_resources.h" +#include "components/user_manager/user.h" +#include "components/user_manager/user_manager.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/plugin_service.h" #include "content/public/common/webplugininfo.h" #include "extensions/browser/extension_system.h" #include "extensions/browser/uninstall_reason.h" +#include "extensions/common/constants.h" #include "extensions/common/extension.h" #include "extensions/common/one_shot_event.h" +#include "grit/theme_resources.h" #include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" using extensions::BrowserContextKeyedAPIFactory; using extensions::HotwordPrivateEventService; @@ -52,6 +62,14 @@ "ru" }; +// Maximum number of retries for installing the hotword shared module from the +// web store. +static const int kMaxInstallRetries = 2; + +// Delay between retries for installing the hotword shared module from the web +// store. +static const int kInstallRetryDelaySeconds = 5; + // Enum describing the state of the hotword preference. // This is used for UMA stats -- do not reorder or delete items; only add to // the end. @@ -185,8 +203,55 @@ const char kHotwordUnusablePrefName[] = "hotword.search_enabled"; // String passed to indicate the training state has changed. const char kHotwordTrainingEnabled[] = "hotword_training_enabled"; +// Id of the hotword notification. +const char kHotwordNotificationId[] = "hotword"; +// Notifier id for the hotword notification. +const char kHotwordNotifierId[] = "hotword.notification"; } // namespace hotword_internal +// Delegate for the hotword notification. +class HotwordNotificationDelegate : public NotificationDelegate { + public: + explicit HotwordNotificationDelegate(Profile* profile) + : profile_(profile) { + } + + // Overridden from NotificationDelegate: + void ButtonClick(int button_index) override { + DCHECK_EQ(0, button_index); + + // Launch the hotword audio verification app in the right mode. + HotwordService::LaunchMode launch_mode = + HotwordService::HOTWORD_AND_AUDIO_HISTORY; + if (profile_->GetPrefs()->GetBoolean( + prefs::kHotwordAudioHistoryEnabled)) { + // TODO(rlp): Make sure the Chrome Audio History pref is synced + // to the account-level Audio History setting from footprints. + launch_mode = HotwordService::HOTWORD_ONLY; + } + + HotwordService* hotword_service = + HotwordServiceFactory::GetForProfile(profile_); + + if (!hotword_service) + return; + + hotword_service->LaunchHotwordAudioVerificationApp(launch_mode); + } + + // Overridden from NotificationDelegate: + std::string id() const override { + return hotword_internal::kHotwordNotificationId; + } + + private: + ~HotwordNotificationDelegate() override {} + + Profile* profile_; + + DISALLOW_COPY_AND_ASSIGN(HotwordNotificationDelegate); +}; + // static bool HotwordService::DoesHotwordSupportLanguage(Profile* profile) { std::string normalized_locale = @@ -213,6 +278,27 @@ return command_line->HasSwitch(switches::kEnableExperimentalHotwording); } +#if defined(OS_CHROMEOS) +class HotwordService::HotwordUserSessionStateObserver + : public user_manager::UserManager::UserSessionStateObserver { + public: + explicit HotwordUserSessionStateObserver(HotwordService* service) + : service_(service) {} + + // Overridden from UserSessionStateObserver: + void ActiveUserChanged(const user_manager::User* active_user) override { + service_->ActiveUserChanged(); + } + + private: + HotwordService* service_; // Not owned +}; +#else +// Dummy class to please the linker. +class HotwordService::HotwordUserSessionStateObserver { +}; +#endif + HotwordService::HotwordService(Profile* profile) : profile_(profile), extension_registry_observer_(this), @@ -258,9 +344,77 @@ } audio_history_handler_.reset(new HotwordAudioHistoryHandler(profile_)); + + if (HotwordServiceFactory::IsHotwordHardwareAvailable() && + IsHotwordAllowed() && + IsExperimentalHotwordingEnabled()) { + // Show the hotword notification in 5 seconds if the experimental flag is + // on, or in 30 minutes if not. We need to wait at least a few seconds + // for the hotword extension to be installed. + CommandLine* command_line = CommandLine::ForCurrentProcess(); + if (command_line->HasSwitch(switches::kEnableExperimentalHotwordHardware)) { + base::MessageLoop::current()->PostDelayedTask( + FROM_HERE, + base::Bind(&HotwordService::ShowHotwordNotification, + weak_factory_.GetWeakPtr()), + base::TimeDelta::FromSeconds(5)); + } else if (!profile_->GetPrefs()->GetBoolean( + prefs::kHotwordAlwaysOnNotificationSeen)) { + base::MessageLoop::current()->PostDelayedTask( + FROM_HERE, + base::Bind(&HotwordService::ShowHotwordNotification, + weak_factory_.GetWeakPtr()), + base::TimeDelta::FromMinutes(30)); + } + } + +#if defined(OS_CHROMEOS) + if (user_manager::UserManager::IsInitialized()) { + session_observer_.reset(new HotwordUserSessionStateObserver(this)); + user_manager::UserManager::Get()->AddSessionStateObserver( + session_observer_.get()); + } +#endif } HotwordService::~HotwordService() { +#if defined(OS_CHROMEOS) + if (user_manager::UserManager::IsInitialized() && session_observer_) { + user_manager::UserManager::Get()->RemoveSessionStateObserver( + session_observer_.get()); + } +#endif +} + +void HotwordService::ShowHotwordNotification() { + // Check for enabled here in case always-on was enabled during the delay. + if (!IsServiceAvailable() || IsAlwaysOnEnabled()) + return; + + message_center::RichNotificationData data; + const base::string16 label = l10n_util::GetStringUTF16( + IDS_HOTWORD_NOTIFICATION_BUTTON); + data.buttons.push_back(message_center::ButtonInfo(label)); + + Notification notification( + message_center::NOTIFICATION_TYPE_SIMPLE, + GURL(), + l10n_util::GetStringUTF16(IDS_HOTWORD_NOTIFICATION_TITLE), + l10n_util::GetStringUTF16(IDS_HOTWORD_NOTIFICATION_DESCRIPTION), + ui::ResourceBundle::GetSharedInstance().GetImageNamed( + IDR_HOTWORD_NOTIFICATION_ICON), + blink::WebTextDirectionDefault, + message_center::NotifierId( + message_center::NotifierId::SYSTEM_COMPONENT, + hotword_internal::kHotwordNotifierId), + base::string16(), + base::string16(), + data, + new HotwordNotificationDelegate(profile_)); + + g_browser_process->notification_ui_manager()->Add(notification, profile_); + profile_->GetPrefs()->SetBoolean( + prefs::kHotwordAlwaysOnNotificationSeen, true); } void HotwordService::OnExtensionUninstalled( @@ -280,7 +434,7 @@ if (!reinstall_pending_) return; - InstallHotwordExtensionFromWebstore(); + InstallHotwordExtensionFromWebstore(kMaxInstallRetries); SetPreviousLanguagePref(); } @@ -291,12 +445,31 @@ return extension_misc::kHotwordExtensionId; } -void HotwordService::InstallHotwordExtensionFromWebstore() { +void HotwordService::InstalledFromWebstoreCallback( + int num_tries, + bool success, + const std::string& error, + extensions::webstore_install::Result result) { + if (result != extensions::webstore_install::SUCCESS && num_tries) { + // Try again on failure. + content::BrowserThread::PostDelayedTask( + content::BrowserThread::UI, + FROM_HERE, + base::Bind(&HotwordService::InstallHotwordExtensionFromWebstore, + weak_factory_.GetWeakPtr(), + num_tries), + base::TimeDelta::FromSeconds(kInstallRetryDelaySeconds)); + } +} + +void HotwordService::InstallHotwordExtensionFromWebstore(int num_tries) { installer_ = new extensions::WebstoreStartupInstaller( ReinstalledExtensionId(), profile_, false, - extensions::WebstoreStandaloneInstaller::Callback()); + base::Bind(&HotwordService::InstalledFromWebstoreCallback, + weak_factory_.GetWeakPtr(), + num_tries - 1)); installer_->BeginInstall(); } @@ -503,8 +676,9 @@ if (!extension) return; - OpenApplication(AppLaunchParams( - profile_, extension, extensions::LAUNCH_CONTAINER_WINDOW, NEW_WINDOW)); + OpenApplication( + AppLaunchParams(profile_, extension, extensions::LAUNCH_CONTAINER_WINDOW, + NEW_WINDOW, extensions::SOURCE_CHROME_INTERNAL)); } HotwordService::LaunchMode @@ -627,3 +801,23 @@ return locale != previous_locale && HotwordService::DoesHotwordSupportLanguage(profile_); } + +void HotwordService::ActiveUserChanged() { + // Do nothing for old hotwording. + if (!IsExperimentalHotwordingEnabled()) + return; + + // Don't bother notifying the extension if hotwording is completely off. + if (!IsSometimesOnEnabled() && !IsAlwaysOnEnabled()) + return; + + HotwordPrivateEventService* event_service = + BrowserContextKeyedAPIFactory<HotwordPrivateEventService>::Get(profile_); + // "enabled" isn't being changed, but piggy-back off the notification anyway. + if (event_service) + event_service->OnEnabledChanged(prefs::kHotwordSearchEnabled); +} + +bool HotwordService::UserIsActive() { + return profile_ == ProfileManager::GetActiveUserProfile(); +}
diff --git a/chrome/browser/search/hotword_service.h b/chrome/browser/search/hotword_service.h index 738d999..3a99a4b 100644 --- a/chrome/browser/search/hotword_service.h +++ b/chrome/browser/search/hotword_service.h
@@ -11,6 +11,7 @@ #include "base/memory/weak_ptr.h" #include "base/prefs/pref_change_registrar.h" #include "base/scoped_observer.h" +#include "chrome/common/extensions/webstore_install_result.h" #include "components/keyed_service/core/keyed_service.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" @@ -100,7 +101,7 @@ // Helper functions pulled out for testing purposes. // UninstallHotwordExtension returns true if the extension was uninstalled. virtual bool UninstallHotwordExtension(ExtensionService* extension_service); - virtual void InstallHotwordExtensionFromWebstore(); + virtual void InstallHotwordExtensionFromWebstore(int num_tries); // Sets the pref value of the previous language. void SetPreviousLanguagePref(); @@ -135,6 +136,12 @@ // Returns true if speaker training is currently in progress. bool IsTraining(); + // Indicate that the currently active user has changed. + void ActiveUserChanged(); + + // Return true if this profile corresponds to the currently active user. + bool UserIsActive(); + // Returns a pointer to the audio history handler. HotwordAudioHistoryHandler* GetAudioHistoryHandler(); @@ -142,9 +149,21 @@ void SetAudioHistoryHandler(HotwordAudioHistoryHandler* handler); private: + class HotwordUserSessionStateObserver; + + // Callback for webstore extension installer. + void InstalledFromWebstoreCallback( + int num_tries, + bool success, + const std::string& error, + extensions::webstore_install::Result result); + // Returns the ID of the extension that may need to be reinstalled. std::string ReinstalledExtensionId(); + // Creates a notification for always-on hotwording. + void ShowHotwordNotification(); + Profile* profile_; PrefChangeRegistrar pref_registrar_; @@ -165,12 +184,16 @@ bool reinstall_pending_; // Whether we are currently in the process of training the speaker model. bool training_; - - base::WeakPtrFactory<HotwordService> weak_factory_; + scoped_ptr<HotwordUserSessionStateObserver> session_observer_; // Stores the launch mode for the Hotword Audio Verification App. LaunchMode hotword_audio_verification_launch_mode_; + // The WeakPtrFactory should be the last member, so the weak pointer + // gets invalidated before the destructors for other members run, + // to avoid callbacks into a half-destroyed object. + base::WeakPtrFactory<HotwordService> weak_factory_; + DISALLOW_COPY_AND_ASSIGN(HotwordService); };
diff --git a/chrome/browser/search/hotword_service_factory.cc b/chrome/browser/search/hotword_service_factory.cc index 6142b86f..ed2dabc77 100644 --- a/chrome/browser/search/hotword_service_factory.cc +++ b/chrome/browser/search/hotword_service_factory.cc
@@ -125,6 +125,9 @@ prefs->RegisterBooleanPref(prefs::kHotwordAlwaysOnSearchEnabled, false, user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); + prefs->RegisterBooleanPref(prefs::kHotwordAlwaysOnNotificationSeen, + false, + user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); } KeyedService* HotwordServiceFactory::BuildServiceInstanceFor(
diff --git a/chrome/browser/search/hotword_service_unittest.cc b/chrome/browser/search/hotword_service_unittest.cc index db1ce868..bf1c4a5b4 100644 --- a/chrome/browser/search/hotword_service_unittest.cc +++ b/chrome/browser/search/hotword_service_unittest.cc
@@ -37,7 +37,7 @@ return HotwordService::UninstallHotwordExtension(extension_service); } - void InstallHotwordExtensionFromWebstore() override { + void InstallHotwordExtensionFromWebstore(int num_tries) override { scoped_ptr<base::DictionaryValue> manifest = extensions::DictionaryBuilder() .Set("name", "Hotword Test Extension") @@ -251,7 +251,7 @@ SetApplicationLocale(profile(), "test_locale"); - hotword_service->InstallHotwordExtensionFromWebstore(); + hotword_service->InstallHotwordExtensionFromWebstore(1); base::MessageLoop::current()->RunUntilIdle(); EXPECT_EQ("test_locale", @@ -282,8 +282,8 @@ // The previous locale should not be set. No reason to uninstall. EXPECT_FALSE(hotword_service->MaybeReinstallHotwordExtension()); - // Do an initial installation. - hotword_service->InstallHotwordExtensionFromWebstore(); + // Do an initial installation. + hotword_service->InstallHotwordExtensionFromWebstore(1); base::MessageLoop::current()->RunUntilIdle(); EXPECT_EQ("en", profile()->GetPrefs()->GetString(prefs::kHotwordPreviousLanguage)); @@ -298,7 +298,7 @@ EXPECT_TRUE(registry()->disabled_extensions().Contains(extension_id_)); } - // The previous locale should be set but should match the current + // The previous locale should be set but should match the current // locale. No reason to uninstall. EXPECT_FALSE(hotword_service->MaybeReinstallHotwordExtension()); @@ -306,7 +306,7 @@ SetApplicationLocale(profile(), "fr_fr"); EXPECT_TRUE(HotwordServiceFactory::IsHotwordAllowed(profile())); - // Different but valid locale so expect uninstall. + // Different but valid locale so expect uninstall. EXPECT_TRUE(hotword_service->MaybeReinstallHotwordExtension()); EXPECT_EQ(1, hotword_service->uninstall_count()); EXPECT_EQ("fr_fr", @@ -372,7 +372,7 @@ EXPECT_TRUE(hotword_service->IsAlwaysOnEnabled()); // Do an initial installation. - hotword_service->InstallHotwordExtensionFromWebstore(); + hotword_service->InstallHotwordExtensionFromWebstore(1); base::MessageLoop::current()->RunUntilIdle(); // The previous locale should be set but should match the current
diff --git a/chrome/browser/search/local_ntp_source.cc b/chrome/browser/search/local_ntp_source.cc index 2485cc6..929f820aa 100644 --- a/chrome/browser/search/local_ntp_source.cc +++ b/chrome/browser/search/local_ntp_source.cc
@@ -37,8 +37,8 @@ const char kMaterialDesignNTPFieldTrialEnabledPrefix[] = "Enabled"; // Names of NTP designs in local resources, also used in CSS. -const char kClassicalNTPName[] = "classical"; -const char kMaterialDesignNTPName[] = "md"; +const char kClassicalNTPName[] = "des-cla"; +const char kMaterialDesignNTPName[] = "des-mat"; // Signifies a locally constructed resource, i.e. not from grit/. const int kLocalResource = -1;
diff --git a/chrome/browser/search/search.cc b/chrome/browser/search/search.cc index ad4bf66f..925e419 100644 --- a/chrome/browser/search/search.cc +++ b/chrome/browser/search/search.cc
@@ -35,7 +35,7 @@ #include "content/public/browser/render_process_host.h" #include "content/public/browser/web_contents.h" -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) #include "chrome/browser/supervised_user/supervised_user_service.h" #include "chrome/browser/supervised_user/supervised_user_service_factory.h" #include "chrome/browser/supervised_user/supervised_user_url_filter.h" @@ -246,7 +246,7 @@ } bool IsURLAllowedForSupervisedUser(const GURL& url, Profile* profile) { -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) SupervisedUserService* supervised_user_service = SupervisedUserServiceFactory::GetForProfile(profile); SupervisedUserURLFilter* url_filter =
diff --git a/chrome/browser/search/search_unittest.cc b/chrome/browser/search/search_unittest.cc index 7a4187fa..b31ab05 100644 --- a/chrome/browser/search/search_unittest.cc +++ b/chrome/browser/search/search_unittest.cc
@@ -31,7 +31,7 @@ #include "content/public/common/renderer_preferences.h" #include "url/gurl.h" -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) #include "chrome/browser/supervised_user/supervised_user_service.h" #include "chrome/browser/supervised_user/supervised_user_service_factory.h" #include "chrome/browser/supervised_user/supervised_user_url_filter.h" @@ -434,7 +434,7 @@ EXPECT_EQ(GURL(chrome::kChromeSearchLocalNtpUrl), new_tab_url); } -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) TEST_F(SearchTest, UseLocalNTPIfNTPURLIsBlockedForSupervisedUser) { // Block access to foo.com in the URL filter. SupervisedUserService* supervised_user_service =
diff --git a/chrome/browser/search_engines/OWNERS b/chrome/browser/search_engines/OWNERS index 6da8b74..c5d3565 100644 --- a/chrome/browser/search_engines/OWNERS +++ b/chrome/browser/search_engines/OWNERS
@@ -3,5 +3,5 @@ per-file *_android.*=mariakhomenko@chromium.org -per-file default_search_policy_handler*=joaodasilva@chromium.org +per-file default_search_policy_handler*=mnissler@chromium.org per-file default_search_policy_handler*=dconnelly@chromium.org
diff --git a/chrome/browser/services/gcm/OWNERS b/chrome/browser/services/gcm/OWNERS index 0f8cc7a..0eba0b77 100644 --- a/chrome/browser/services/gcm/OWNERS +++ b/chrome/browser/services/gcm/OWNERS
@@ -2,3 +2,7 @@ fgorski@chromium.org jianli@chromium.org zea@chromium.org + +per-file push_messaging_*=johnme@chromium.org +per-file push_messaging_*=mvanouwerkerk@chromium.org +per-file push_messaging_*=peter@chromium.org
diff --git a/chrome/browser/services/gcm/fake_gcm_profile_service.cc b/chrome/browser/services/gcm/fake_gcm_profile_service.cc index 8169ded5..b5bdb17 100644 --- a/chrome/browser/services/gcm/fake_gcm_profile_service.cc +++ b/chrome/browser/services/gcm/fake_gcm_profile_service.cc
@@ -143,6 +143,9 @@ CustomFakeGCMDriver* custom_driver = static_cast<CustomFakeGCMDriver*>(driver()); custom_driver->OnUnregisterFinished(app_id, result); + + if (!unregister_callback_.is_null()) + unregister_callback_.Run(app_id); } void FakeGCMProfileService::SendFinished( @@ -164,4 +167,9 @@ unregister_responses_.push_back(result); } +void FakeGCMProfileService::SetUnregisterCallback( + const UnregisterCallback& callback) { + unregister_callback_ = callback; +} + } // namespace gcm
diff --git a/chrome/browser/services/gcm/fake_gcm_profile_service.h b/chrome/browser/services/gcm/fake_gcm_profile_service.h index 2326b9922..fe2ffd8c 100644 --- a/chrome/browser/services/gcm/fake_gcm_profile_service.h +++ b/chrome/browser/services/gcm/fake_gcm_profile_service.h
@@ -20,6 +20,8 @@ // Acts as a bridge between GCM API and GCMClient layer for testing purposes. class FakeGCMProfileService : public GCMProfileService { public: + typedef base::Callback<void(const std::string&)> UnregisterCallback; + // Helper function to be used with // KeyedService::SetTestingFactory(). static KeyedService* Build(content::BrowserContext* context); @@ -36,6 +38,8 @@ void AddExpectedUnregisterResponse(GCMClient::Result result); + void SetUnregisterCallback(const UnregisterCallback& callback); + const GCMClient::OutgoingMessage& last_sent_message() const { return last_sent_message_; } @@ -65,6 +69,7 @@ std::list<GCMClient::Result> unregister_responses_; GCMClient::OutgoingMessage last_sent_message_; std::string last_receiver_id_; + UnregisterCallback unregister_callback_; DISALLOW_COPY_AND_ASSIGN(FakeGCMProfileService); };
diff --git a/chrome/browser/services/gcm/push_messaging_browsertest.cc b/chrome/browser/services/gcm/push_messaging_browsertest.cc index 9b83d5a..6dfd3b1 100644 --- a/chrome/browser/services/gcm/push_messaging_browsertest.cc +++ b/chrome/browser/services/gcm/push_messaging_browsertest.cc
@@ -18,6 +18,8 @@ #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" +#include "components/content_settings/core/browser/host_content_settings_map.h" +#include "components/content_settings/core/common/content_settings_types.h" #include "components/gcm_driver/gcm_client.h" #include "components/infobars/core/confirm_infobar_delegate.h" #include "components/infobars/core/infobar.h" @@ -72,6 +74,34 @@ bool accept_; bool has_observed_; }; + +// Class to instantiate on the stack that is meant to be used with +// FakeGCMProfileService. The ::Run() method follows the signature of +// FakeGCMProfileService::UnregisterCallback. +class UnregistrationCallback { + public: + UnregistrationCallback() : done_(false) {} + + void Run(const std::string& app_id) { + app_id_ = app_id; + done_ = true; + base::MessageLoop::current()->Quit(); + } + + void WaitUntilSatisfied() { + while (!done_) + content::RunMessageLoop(); + } + + const std::string& app_id() { + return app_id_; + } + + private: + bool done_; + std::string app_id_; +}; + } // namespace class PushMessagingBrowserTest : public InProcessBrowserTest { @@ -237,4 +267,147 @@ EXPECT_EQ("testdata", script_result); } +IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, PushEventNoServiceWorker) { + std::string script_result; + + ASSERT_TRUE(RunScript("registerServiceWorker()", &script_result)); + ASSERT_EQ("ok - service worker registered", script_result); + + InfoBarResponder accepting_responder(browser(), true); + ASSERT_TRUE(RunScript("requestNotificationPermission();", &script_result)); + ASSERT_EQ("permission status - granted", script_result); + + ASSERT_TRUE(RunScript("registerPush()", &script_result)); + EXPECT_EQ(std::string(kPushMessagingEndpoint) + " - 1", script_result); + + PushMessagingApplicationId app_id(https_server()->GetURL(""), 0L); + EXPECT_EQ(app_id.ToString(), gcm_service()->last_registered_app_id()); + EXPECT_EQ("1234567890", gcm_service()->last_registered_sender_ids()[0]); + + ASSERT_TRUE(RunScript("isControlled()", &script_result)); + ASSERT_EQ("false - is not controlled", script_result); + + loadTestPage(); // Reload to become controlled. + + ASSERT_TRUE(RunScript("isControlled()", &script_result)); + ASSERT_EQ("true - is controlled", script_result); + + // Unregister service worker. Sending a message should now fail. + ASSERT_TRUE(RunScript("unregisterServiceWorker()", &script_result)); + ASSERT_EQ("service worker unregistration status: true", script_result); + + // When the push service will receive it next message, given that there is no + // SW available, it should unregister |app_id|. + UnregistrationCallback callback; + gcm_service()->SetUnregisterCallback(base::Bind(&UnregistrationCallback::Run, + base::Unretained(&callback))); + + GCMClient::IncomingMessage message; + GCMClient::MessageData messageData; + messageData.insert(std::pair<std::string, std::string>("data", "testdata")); + message.data = messageData; + push_service()->OnMessage(app_id.ToString(), message); + + callback.WaitUntilSatisfied(); + EXPECT_EQ(app_id.ToString(), callback.app_id()); + + // No push data should have been received. + ASSERT_TRUE(RunScript("pushData.getImmediately()", &script_result)); + EXPECT_EQ("null", script_result); +} + +IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, PushEventNoPermission) { + std::string script_result; + + ASSERT_TRUE(RunScript("registerServiceWorker()", &script_result)); + ASSERT_EQ("ok - service worker registered", script_result); + + InfoBarResponder accepting_responder(browser(), true); + ASSERT_TRUE(RunScript("requestNotificationPermission();", &script_result)); + ASSERT_EQ("permission status - granted", script_result); + + ASSERT_TRUE(RunScript("registerPush()", &script_result)); + EXPECT_EQ(std::string(kPushMessagingEndpoint) + " - 1", script_result); + + PushMessagingApplicationId app_id(https_server()->GetURL(""), 0L); + EXPECT_EQ(app_id.ToString(), gcm_service()->last_registered_app_id()); + EXPECT_EQ("1234567890", gcm_service()->last_registered_sender_ids()[0]); + + ASSERT_TRUE(RunScript("isControlled()", &script_result)); + ASSERT_EQ("false - is not controlled", script_result); + + loadTestPage(); // Reload to become controlled. + + ASSERT_TRUE(RunScript("isControlled()", &script_result)); + ASSERT_EQ("true - is controlled", script_result); + + // Revoke Push permission. + browser()->profile()->GetHostContentSettingsMap()-> + ClearSettingsForOneType(CONTENT_SETTINGS_TYPE_PUSH_MESSAGING); + + // When the push service will receive its next message, given that there is no + // SW available, it should unregister |app_id|. + UnregistrationCallback callback; + gcm_service()->SetUnregisterCallback(base::Bind(&UnregistrationCallback::Run, + base::Unretained(&callback))); + + GCMClient::IncomingMessage message; + GCMClient::MessageData messageData; + messageData.insert(std::pair<std::string, std::string>("data", "testdata")); + message.data = messageData; + push_service()->OnMessage(app_id.ToString(), message); + + callback.WaitUntilSatisfied(); + EXPECT_EQ(app_id.ToString(), callback.app_id()); + + // No push data should have been received. + ASSERT_TRUE(RunScript("pushData.getImmediately()", &script_result)); + EXPECT_EQ("null", script_result); +} + +IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, HasPermissionSaysDefault) { + std::string script_result; + + ASSERT_TRUE(RunScript("registerServiceWorker()", &script_result)); + ASSERT_EQ("ok - service worker registered", script_result); + + ASSERT_TRUE(RunScript("hasPermission()", &script_result)); + ASSERT_EQ("permission status - default", script_result); +} + +IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, HasPermissionSaysGranted) { + std::string script_result; + + ASSERT_TRUE(RunScript("registerServiceWorker()", &script_result)); + ASSERT_EQ("ok - service worker registered", script_result); + + InfoBarResponder accepting_responder(browser(), true); + ASSERT_TRUE(RunScript("requestNotificationPermission();", &script_result)); + EXPECT_EQ("permission status - granted", script_result); + + ASSERT_TRUE(RunScript("registerPush()", &script_result)); + EXPECT_EQ(std::string(kPushMessagingEndpoint) + " - 1", script_result); + + ASSERT_TRUE(RunScript("hasPermission()", &script_result)); + EXPECT_EQ("permission status - granted", script_result); +} + +IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, HasPermissionSaysDenied) { + std::string script_result; + + ASSERT_TRUE(RunScript("registerServiceWorker()", &script_result)); + ASSERT_EQ("ok - service worker registered", script_result); + + InfoBarResponder cancelling_responder(browser(), false); + ASSERT_TRUE(RunScript("requestNotificationPermission();", &script_result)); + EXPECT_EQ("permission status - denied", script_result); + + ASSERT_TRUE(RunScript("registerPush()", &script_result)); + EXPECT_EQ("AbortError - Registration failed - permission denied", + script_result); + + ASSERT_TRUE(RunScript("hasPermission()", &script_result)); + EXPECT_EQ("permission status - denied", script_result); +} + } // namespace gcm
diff --git a/chrome/browser/services/gcm/push_messaging_permission_context.cc b/chrome/browser/services/gcm/push_messaging_permission_context.cc index 1fba719..418b1742 100644 --- a/chrome/browser/services/gcm/push_messaging_permission_context.cc +++ b/chrome/browser/services/gcm/push_messaging_permission_context.cc
@@ -27,6 +27,9 @@ ContentSetting PushMessagingPermissionContext::GetPermissionStatus( const GURL& requesting_origin, const GURL& embedding_origin) const { + if (requesting_origin != embedding_origin) + return CONTENT_SETTING_BLOCK; + ContentSetting push_content_setting = profile_->GetHostContentSettingsMap()->GetContentSetting( requesting_origin, embedding_origin, kPushSettingType, std::string()); @@ -50,6 +53,7 @@ } // Unlike other permissions, push is decided by the following algorithm +// - You need to request it from a top level domain // - You need to have notification permission granted. // - You need to not have push permission explicitly blocked. // - If those two things are true it is granted without prompting. @@ -61,6 +65,10 @@ const GURL& embedding_origin, bool user_gesture, const BrowserPermissionCallback& callback) { + if (requesting_origin != embedding_origin) { + NotifyPermissionSet(id, requesting_origin, embedding_origin, callback, + false /* persist */, false /* granted */); + } ContentSetting notifications_content_setting = profile_->GetHostContentSettingsMap() ->GetContentSettingAndMaybeUpdateLastUsage(
diff --git a/chrome/browser/services/gcm/push_messaging_permission_context_unittest.cc b/chrome/browser/services/gcm/push_messaging_permission_context_unittest.cc index eeba4941..653d1d4 100644 --- a/chrome/browser/services/gcm/push_messaging_permission_context_unittest.cc +++ b/chrome/browser/services/gcm/push_messaging_permission_context_unittest.cc
@@ -11,7 +11,8 @@ #include "content/public/test/test_browser_thread_bundle.h" #include "testing/gtest/include/gtest/gtest.h" -const char kEmbedder[] = "https://example.org"; +const char kOriginA[] = "https://origina.org"; +const char kOriginB[] = "https://originb.org"; namespace gcm { @@ -70,7 +71,7 @@ protected: void SetContentSetting(ContentSettingsType setting, ContentSetting value) { ContentSettingsPattern pattern = - ContentSettingsPattern::FromString(kEmbedder); + ContentSettingsPattern::FromString(kOriginA); HostContentSettingsMap* host_content_settings_map = profile_.GetHostContentSettingsMap(); host_content_settings_map->SetContentSetting(pattern, pattern, setting, @@ -84,13 +85,13 @@ TEST_F(PushMessagingPermissionContextTest, HasPermissionPrompt) { PushMessagingPermissionContext context(&profile_); EXPECT_EQ(CONTENT_SETTING_ASK, - context.GetPermissionStatus(GURL(kEmbedder), GURL(kEmbedder))); + context.GetPermissionStatus(GURL(kOriginA), GURL(kOriginA))); // Just granting notifications should still prompt SetContentSetting(CONTENT_SETTINGS_TYPE_NOTIFICATIONS, CONTENT_SETTING_ALLOW); EXPECT_EQ(CONTENT_SETTING_ASK, - context.GetPermissionStatus(GURL(kEmbedder), GURL(kEmbedder))); + context.GetPermissionStatus(GURL(kOriginA), GURL(kOriginA))); // Just granting push should still prompt SetContentSetting(CONTENT_SETTINGS_TYPE_NOTIFICATIONS, CONTENT_SETTING_ASK); @@ -98,28 +99,37 @@ CONTENT_SETTING_ALLOW); EXPECT_EQ(CONTENT_SETTING_ASK, - context.GetPermissionStatus(GURL(kEmbedder), GURL(kEmbedder))); + context.GetPermissionStatus(GURL(kOriginA), GURL(kOriginA))); } -TEST_F(PushMessagingPermissionContextTest, HasPermissionDeny) { +TEST_F(PushMessagingPermissionContextTest, HasPermissionDenySettingsMismatch) { PushMessagingPermissionContext context(&profile_); SetContentSetting(CONTENT_SETTINGS_TYPE_NOTIFICATIONS, CONTENT_SETTING_BLOCK); EXPECT_EQ(CONTENT_SETTING_BLOCK, - context.GetPermissionStatus(GURL(kEmbedder), GURL(kEmbedder))); + context.GetPermissionStatus(GURL(kOriginA), GURL(kOriginA))); SetContentSetting(CONTENT_SETTINGS_TYPE_NOTIFICATIONS, CONTENT_SETTING_ASK); SetContentSetting(CONTENT_SETTINGS_TYPE_PUSH_MESSAGING, CONTENT_SETTING_BLOCK); EXPECT_EQ(CONTENT_SETTING_BLOCK, - context.GetPermissionStatus(GURL(kEmbedder), GURL(kEmbedder))); + context.GetPermissionStatus(GURL(kOriginA), GURL(kOriginA))); SetContentSetting(CONTENT_SETTINGS_TYPE_NOTIFICATIONS, CONTENT_SETTING_ALLOW); EXPECT_EQ(CONTENT_SETTING_BLOCK, - context.GetPermissionStatus(GURL(kEmbedder), GURL(kEmbedder))); + context.GetPermissionStatus(GURL(kOriginA), GURL(kOriginA))); SetContentSetting(CONTENT_SETTINGS_TYPE_NOTIFICATIONS, CONTENT_SETTING_ASK); SetContentSetting(CONTENT_SETTINGS_TYPE_PUSH_MESSAGING, CONTENT_SETTING_BLOCK); EXPECT_EQ(CONTENT_SETTING_BLOCK, - context.GetPermissionStatus(GURL(kEmbedder), GURL(kEmbedder))); + context.GetPermissionStatus(GURL(kOriginA), GURL(kOriginA))); +} + +TEST_F(PushMessagingPermissionContextTest, HasPermissionDenyDifferentOrigins) { + PushMessagingPermissionContext context(&profile_); + SetContentSetting(CONTENT_SETTINGS_TYPE_NOTIFICATIONS, CONTENT_SETTING_ALLOW); + SetContentSetting(CONTENT_SETTINGS_TYPE_PUSH_MESSAGING, CONTENT_SETTING_ASK); + + EXPECT_EQ(CONTENT_SETTING_BLOCK, + context.GetPermissionStatus(GURL(kOriginB), GURL(kOriginA))); } TEST_F(PushMessagingPermissionContextTest, HasPermissionAccept) { @@ -128,36 +138,40 @@ SetContentSetting(CONTENT_SETTINGS_TYPE_PUSH_MESSAGING, CONTENT_SETTING_ALLOW); EXPECT_EQ(CONTENT_SETTING_ALLOW, - context.GetPermissionStatus(GURL(kEmbedder), GURL(kEmbedder))); + context.GetPermissionStatus(GURL(kOriginA), GURL(kOriginA))); } TEST_F(PushMessagingPermissionContextTest, DecidePermission) { TestPushMessagingPermissionContext context(&profile_); - PermissionRequestID request_id(-1, -1, -1, GURL(kEmbedder)); + PermissionRequestID request_id(-1, -1, -1, GURL(kOriginA)); BrowserPermissionCallback callback; - context.DecidePermission(NULL, request_id, GURL(kEmbedder), GURL(kEmbedder), + context.DecidePermission(NULL, request_id, GURL(kOriginA), GURL(kOriginA), true, callback); EXPECT_FALSE(context.was_persisted()); EXPECT_FALSE(context.was_granted()); SetContentSetting(CONTENT_SETTINGS_TYPE_NOTIFICATIONS, CONTENT_SETTING_BLOCK); - context.DecidePermission(NULL, request_id, GURL(kEmbedder), GURL(kEmbedder), + context.DecidePermission(NULL, request_id, GURL(kOriginA), GURL(kOriginA), true, callback); EXPECT_FALSE(context.was_persisted()); EXPECT_FALSE(context.was_granted()); SetContentSetting(CONTENT_SETTINGS_TYPE_NOTIFICATIONS, CONTENT_SETTING_ALLOW); SetContentSetting(CONTENT_SETTINGS_TYPE_PUSH_MESSAGING, CONTENT_SETTING_BLOCK); - context.DecidePermission(NULL, request_id, GURL(kEmbedder), GURL(kEmbedder), + context.DecidePermission(NULL, request_id, GURL(kOriginA), GURL(kOriginA), true, callback); EXPECT_FALSE(context.was_persisted()); EXPECT_FALSE(context.was_granted()); SetContentSetting(CONTENT_SETTINGS_TYPE_PUSH_MESSAGING, CONTENT_SETTING_ASK); - context.DecidePermission(NULL, request_id, GURL(kEmbedder), GURL(kEmbedder), + context.DecidePermission(NULL, request_id, GURL(kOriginA), GURL(kOriginA), true, callback); EXPECT_TRUE(context.was_persisted()); EXPECT_TRUE(context.was_granted()); + context.DecidePermission(NULL, request_id, GURL(kOriginB), GURL(kOriginA), + true, callback); + EXPECT_FALSE(context.was_persisted()); + EXPECT_FALSE(context.was_granted()); } } // namespace gcm
diff --git a/chrome/browser/services/gcm/push_messaging_service_impl.cc b/chrome/browser/services/gcm/push_messaging_service_impl.cc index 15b1b70..a4e0840e 100644 --- a/chrome/browser/services/gcm/push_messaging_service_impl.cc +++ b/chrome/browser/services/gcm/push_messaging_service_impl.cc
@@ -81,7 +81,7 @@ // Create the GCMProfileService, and hence instantiate this class. GCMProfileService* gcm_service = - gcm::GCMProfileServiceFactory::GetForProfile(profile); + GCMProfileServiceFactory::GetForProfile(profile); PushMessagingServiceImpl* push_service = static_cast<PushMessagingServiceImpl*>( gcm_service->push_messaging_service()); @@ -155,6 +155,13 @@ DCHECK(application_id.IsValid()); GCMClient::MessageData::const_iterator it = message.data.find("data"); if (application_id.IsValid() && it != message.data.end()) { + if (!HasPermission(application_id.origin)) { + // The |origin| lost push permission. We need to unregister and drop this + // message. + Unregister(application_id); + return; + } + const std::string& data = it->second; content::BrowserContext::DeliverPushMessage( profile_, @@ -184,6 +191,15 @@ content::PushDeliveryStatus status) { // TODO(mvanouwerkerk): UMA logging. // TODO(mvanouwerkerk): Is there a way to recover from failure? + switch (status) { + case content::PUSH_DELIVERY_STATUS_SUCCESS: + case content::PUSH_DELIVERY_STATUS_SERVICE_WORKER_ERROR: + case content::PUSH_DELIVERY_STATUS_EVENT_WAITUNTIL_REJECTED: + break; + case content::PUSH_DELIVERY_STATUS_NO_SERVICE_WORKER: + Unregister(application_id); + break; + } } void PushMessagingServiceImpl::OnMessagesDeleted(const std::string& app_id) { @@ -203,8 +219,12 @@ NOTREACHED() << "The Push API shouldn't have sent messages upstream"; } -void PushMessagingServiceImpl::Register( - const GURL& origin, +GURL PushMessagingServiceImpl::PushEndpoint() { + return GURL(std::string(kPushMessagingEndpoint)); +} + +void PushMessagingServiceImpl::RegisterFromDocument( + const GURL& requesting_origin, int64 service_worker_registration_id, const std::string& sender_id, int renderer_id, @@ -213,10 +233,11 @@ const content::PushMessagingService::RegisterCallback& callback) { if (!gcm_profile_service_->driver()) { NOTREACHED() << "There is no GCMDriver. Has GCMProfileService shut down?"; + return; } - PushMessagingApplicationId application_id = - PushMessagingApplicationId(origin, service_worker_registration_id); + PushMessagingApplicationId application_id = PushMessagingApplicationId( + requesting_origin, service_worker_registration_id); DCHECK(application_id.IsValid()); if (push_registration_count_ >= kMaxRegistrations) { @@ -226,24 +247,20 @@ return; } + // TODO(johnme): This is probably redundant due to + // https://codereview.chromium.org/756063002, or even if it isn't it'll + // interfere with auto-removing the app handler, so should be removed. // If this is registering for the first time then the driver does not have // this as an app handler and registration would fail. - if (gcm_profile_service_->driver()->GetAppHandler( - kPushMessagingApplicationIdPrefix) != this) - gcm_profile_service_->driver()->AddAppHandler( - kPushMessagingApplicationIdPrefix, this); + AddAppHandlerIfNecessary(); content::RenderFrameHost* render_frame_host = content::RenderFrameHost::FromID(renderer_id, render_frame_id); - - // The frame doesn't exist any more, or we received a bad frame id. if (!render_frame_host) return; content::WebContents* web_contents = content::WebContents::FromRenderFrameHost(render_frame_host); - - // The page doesn't exist any more or we got a bad render frame host. if (!web_contents) return; @@ -254,7 +271,7 @@ const PermissionRequestID id( renderer_id, web_contents->GetRoutingID(), bridge_id, GURL()); - GURL embedder = web_contents->GetLastCommittedURL(); + GURL embedding_origin = web_contents->GetLastCommittedURL().GetOrigin(); gcm::PushMessagingPermissionContext* permission_context = gcm::PushMessagingPermissionContextFactory::GetForProfile(profile_); @@ -266,32 +283,65 @@ } permission_context->RequestPermission( - web_contents, - id, - embedder, - user_gesture, + web_contents, id, embedding_origin, user_gesture, base::Bind(&PushMessagingServiceImpl::DidRequestPermission, - weak_factory_.GetWeakPtr(), - application_id, - sender_id, + weak_factory_.GetWeakPtr(), application_id, sender_id, callback)); } +void PushMessagingServiceImpl::RegisterFromWorker( + const GURL& requesting_origin, + int64 service_worker_registration_id, + const std::string& sender_id, + const content::PushMessagingService::RegisterCallback& register_callback) { + if (!gcm_profile_service_->driver()) { + NOTREACHED() << "There is no GCMDriver. Has GCMProfileService shut down?"; + return; + } + + PushMessagingApplicationId application_id = PushMessagingApplicationId( + requesting_origin, service_worker_registration_id); + DCHECK(application_id.IsValid()); + + if (profile_->GetPrefs()->GetInteger( + prefs::kPushMessagingRegistrationCount) >= kMaxRegistrations) { + RegisterEnd(register_callback, std::string(), + content::PUSH_REGISTRATION_STATUS_LIMIT_REACHED); + return; + } + + // If this is registering for the first time then the driver does not have + // this as an app handler and registration would fail. + AddAppHandlerIfNecessary(); + + GURL embedding_origin = requesting_origin; + blink::WebPushPermissionStatus permission_status = + PushMessagingServiceImpl::GetPermissionStatus(requesting_origin, + embedding_origin); + if (permission_status != blink::WebPushPermissionStatusGranted) { + RegisterEnd(register_callback, std::string(), + content::PUSH_REGISTRATION_STATUS_PERMISSION_DENIED); + return; + } + + std::vector<std::string> sender_ids(1, sender_id); + gcm_profile_service_->driver()->Register( + application_id.ToString(), sender_ids, + base::Bind(&PushMessagingServiceImpl::DidRegister, + weak_factory_.GetWeakPtr(), register_callback)); +} + blink::WebPushPermissionStatus PushMessagingServiceImpl::GetPermissionStatus( const GURL& requesting_origin, int renderer_id, int render_frame_id) { content::RenderFrameHost* render_frame_host = content::RenderFrameHost::FromID(renderer_id, render_frame_id); - - // The frame doesn't exist any more, or we received a bad frame id. if (!render_frame_host) return blink::WebPushPermissionStatusDenied; content::WebContents* web_contents = content::WebContents::FromRenderFrameHost(render_frame_host); - - // The page doesn't exist any more or we got a bad render frame host. if (!web_contents) return blink::WebPushPermissionStatusDenied; @@ -303,12 +353,20 @@ requesting_origin, embedder_origin)); } +blink::WebPushPermissionStatus PushMessagingServiceImpl::GetPermissionStatus( + const GURL& requesting_origin, + const GURL& embedding_origin) { + PushMessagingPermissionContext* permission_context = + PushMessagingPermissionContextFactory::GetForProfile(profile_); + return ToPushPermission(permission_context->GetPermissionStatus( + requesting_origin, embedding_origin)); +} + void PushMessagingServiceImpl::RegisterEnd( const content::PushMessagingService::RegisterCallback& callback, const std::string& registration_id, content::PushRegistrationStatus status) { - GURL endpoint = GURL(std::string(kPushMessagingEndpoint)); - callback.Run(endpoint, registration_id, status); + callback.Run(registration_id, status); if (status == content::PUSH_REGISTRATION_STATUS_SUCCESS) IncreasePushRegistrationCount(1); } @@ -350,6 +408,39 @@ register_callback)); } -// TODO(johnme): Unregister should call DecreasePushRegistrationCount. +void PushMessagingServiceImpl::Unregister( + const PushMessagingApplicationId& application_id) { + DCHECK(gcm_profile_service_->driver()); + + gcm_profile_service_->driver()->Unregister( + application_id.ToString(), + base::Bind(&PushMessagingServiceImpl::DidUnregister, + weak_factory_.GetWeakPtr())); +} + +void PushMessagingServiceImpl::DidUnregister(GCMClient::Result result) { + if (result != GCMClient::SUCCESS) { + DVLOG(1) << "GCM unregistration failed."; + return; + } + + DecreasePushRegistrationCount(1); +} + +bool PushMessagingServiceImpl::HasPermission(const GURL& origin) { + gcm::PushMessagingPermissionContext* permission_context = + gcm::PushMessagingPermissionContextFactory::GetForProfile(profile_); + DCHECK(permission_context); + + return permission_context->GetPermissionStatus(origin, origin) == + CONTENT_SETTING_ALLOW; +} + +void PushMessagingServiceImpl::AddAppHandlerIfNecessary() { + if (gcm_profile_service_->driver()->GetAppHandler( + kPushMessagingApplicationIdPrefix) != this) + gcm_profile_service_->driver()->AddAppHandler( + kPushMessagingApplicationIdPrefix, this); +} } // namespace gcm
diff --git a/chrome/browser/services/gcm/push_messaging_service_impl.h b/chrome/browser/services/gcm/push_messaging_service_impl.h index 6d1b412..6598e99 100644 --- a/chrome/browser/services/gcm/push_messaging_service_impl.h +++ b/chrome/browser/services/gcm/push_messaging_service_impl.h
@@ -50,18 +50,29 @@ bool CanHandle(const std::string& app_id) const override; // content::PushMessagingService implementation: - void Register( - const GURL& origin, + GURL PushEndpoint() override; + void RegisterFromDocument( + const GURL& requesting_origin, int64 service_worker_registration_id, const std::string& sender_id, int renderer_id, int render_frame_id, bool user_gesture, const content::PushMessagingService::RegisterCallback& callback) override; + void RegisterFromWorker( + const GURL& requesting_origin, + int64 service_worker_registration_id, + const std::string& sender_id, + const content::PushMessagingService::RegisterCallback& callback) override; + // TODO(mvanouwerkerk): Delete once the Push API flows through platform. + // https://crbug.com/389194 blink::WebPushPermissionStatus GetPermissionStatus( const GURL& requesting_origin, int renderer_id, int render_frame_id) override; + blink::WebPushPermissionStatus GetPermissionStatus( + const GURL& requesting_origin, + const GURL& embedding_origin) override; void SetProfileForTesting(Profile* profile); @@ -89,6 +100,19 @@ const content::PushMessagingService::RegisterCallback& callback, bool allow); + // TODO(mvanouwerkerk): this will need to be extended and move to the + // PushMessagingService interface later. + void Unregister(const PushMessagingApplicationId& application_id); + + void DidUnregister(GCMClient::Result result); + + // Helper method that checks if a given origin is allowed to use Push. + bool HasPermission(const GURL& origin); + + // Adds this service as an app handler to the GCMDriver if it has not been + // added yet. + void AddAppHandlerIfNecessary(); + GCMProfileService* gcm_profile_service_; // It owns us. Profile* profile_; // It owns our owner.
diff --git a/chrome/browser/sessions/OWNERS b/chrome/browser/sessions/OWNERS index 6aa255e..f889915 100644 --- a/chrome/browser/sessions/OWNERS +++ b/chrome/browser/sessions/OWNERS
@@ -1,7 +1,7 @@ marja@chromium.org sky@chromium.org -per-file restore_on_startup_policy_handler*=joaodasilva@chromium.org +per-file restore_on_startup_policy_handler*=mnissler@chromium.org per-file restore_on_startup_policy_handler*=dconnelly@chromium.org per-file session_restore_android*=dfalcantara@chromium.org
diff --git a/chrome/browser/sessions/session_restore.cc b/chrome/browser/sessions/session_restore.cc index 020185c..c95fab2 100644 --- a/chrome/browser/sessions/session_restore.cc +++ b/chrome/browser/sessions/session_restore.cc
@@ -1073,19 +1073,6 @@ // focused tab will be loaded by Browser, and TabLoader will load the rest. DCHECK(web_contents->GetController().NeedsReload()); - // Set up the file access rights for the selected navigation entry. - const int id = web_contents->GetRenderProcessHost()->GetID(); - const content::PageState& page_state = - content::PageState::CreateFromEncodedData( - tab.navigations.at(selected_index).encoded_page_state()); - const std::vector<base::FilePath>& file_paths = - page_state.GetReferencedFiles(); - for (std::vector<base::FilePath>::const_iterator file = file_paths.begin(); - file != file_paths.end(); ++file) { - content::ChildProcessSecurityPolicy::GetInstance()->GrantReadFile(id, - *file); - } - if (!is_selected_tab) tab_loader_->ScheduleLoad(&web_contents->GetController()); return web_contents;
diff --git a/chrome/browser/signin/chrome_signin_client.cc b/chrome/browser/signin/chrome_signin_client.cc index 05754be..9bcdf6a4 100644 --- a/chrome/browser/signin/chrome_signin_client.cc +++ b/chrome/browser/signin/chrome_signin_client.cc
@@ -25,7 +25,7 @@ #include "net/url_request/url_request_context_getter.h" #include "url/gurl.h" -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) #include "chrome/browser/supervised_user/supervised_user_constants.h" #endif
diff --git a/chrome/browser/signin/easy_unlock_screenlock_state_handler.cc b/chrome/browser/signin/easy_unlock_screenlock_state_handler.cc index 96d53cf..c93613b 100644 --- a/chrome/browser/signin/easy_unlock_screenlock_state_handler.cc +++ b/chrome/browser/signin/easy_unlock_screenlock_state_handler.cc
@@ -251,16 +251,18 @@ icon_options.SetIcon(ScreenlockBridge::USER_POD_CUSTOM_ICON_HARDLOCKED); } + base::string16 device_name = GetDeviceName(); base::string16 tooltip; if (hardlock_state_ == USER_HARDLOCK) { tooltip = l10n_util::GetStringFUTF16( - IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_HARDLOCK_USER, GetDeviceName()); + IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_HARDLOCK_USER, device_name); } else if (hardlock_state_ == PAIRING_CHANGED) { tooltip = l10n_util::GetStringUTF16( IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_HARDLOCK_PAIRING_CHANGED); } else if (hardlock_state_ == PAIRING_ADDED) { - tooltip = l10n_util::GetStringUTF16( - IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_HARDLOCK_PAIRING_ADDED); + tooltip = l10n_util::GetStringFUTF16( + IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_HARDLOCK_PAIRING_ADDED, device_name, + device_name); } else if (hardlock_state_ == LOGIN_FAILED) { tooltip = l10n_util::GetStringUTF16( IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_LOGIN_FAILURE);
diff --git a/chrome/browser/signin/easy_unlock_service_regular.cc b/chrome/browser/signin/easy_unlock_service_regular.cc index 3551309..d9d3779 100644 --- a/chrome/browser/signin/easy_unlock_service_regular.cc +++ b/chrome/browser/signin/easy_unlock_service_regular.cc
@@ -14,6 +14,7 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/signin/easy_unlock_toggle_flow.h" #include "chrome/browser/signin/screenlock_bridge.h" +#include "chrome/browser/ui/extensions/app_launch_params.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/common/extensions/extension_constants.h" #include "chrome/common/pref_names.h" @@ -21,6 +22,7 @@ #include "components/proximity_auth/switches.h" #include "content/public/browser/browser_thread.h" #include "extensions/browser/extension_system.h" +#include "extensions/common/constants.h" #if defined(OS_CHROMEOS) #include "apps/app_lifetime_monitor_factory.h" @@ -135,8 +137,9 @@ const extensions::Extension* extension = service->GetExtensionById(extension_misc::kEasyUnlockAppId, false); - OpenApplication(AppLaunchParams( - profile(), extension, extensions::LAUNCH_CONTAINER_WINDOW, NEW_WINDOW)); + OpenApplication( + AppLaunchParams(profile(), extension, extensions::LAUNCH_CONTAINER_WINDOW, + NEW_WINDOW, extensions::SOURCE_CHROME_INTERNAL)); } const base::DictionaryValue* EasyUnlockServiceRegular::GetPermitAccess() const {
diff --git a/chrome/browser/signin/signin_header_helper.cc b/chrome/browser/signin/signin_header_helper.cc index b3d11f5..f41f1417 100644 --- a/chrome/browser/signin/signin_header_helper.cc +++ b/chrome/browser/signin/signin_header_helper.cc
@@ -241,7 +241,7 @@ // embedded in a webui page, otherwise user may end up with a blank page as // gaia uses the header to decide whether it returns 204 for certain end // points. - if (is_guest && webview_info.embedder_extension_id.empty()) + if (is_guest && webview_info.owner_extension_id.empty()) return false; #endif // !OS_ANDROID && !OS_IOS
diff --git a/chrome/browser/supervised_user/supervised_users.h b/chrome/browser/supervised_user/supervised_users.h index b73e99b..82fcba6 100644 --- a/chrome/browser/supervised_user/supervised_users.h +++ b/chrome/browser/supervised_user/supervised_users.h
@@ -6,8 +6,8 @@ #define CHROME_BROWSER_SUPERVISED_USER_SUPERVISED_USERS_H_ // Compile-time check to make sure that we don't include supervised user source -// files when ENABLE_MANAGED_USERS is not defined. -#if !defined(ENABLE_MANAGED_USERS) +// files when ENABLE_SUPERVISED_USERS is not defined. +#if !defined(ENABLE_SUPERVISED_USERS) #error "Supervised users aren't enabled." #endif
diff --git a/chrome/browser/sync/OWNERS b/chrome/browser/sync/OWNERS index 1254d0d1..e0c8fa8 100644 --- a/chrome/browser/sync/OWNERS +++ b/chrome/browser/sync/OWNERS
@@ -7,4 +7,4 @@ zea@chromium.org per-file sync_policy_handler*=dconnelly@chromium.org -per-file sync_policy_handler*=joaodasilva@chromium.org +per-file sync_policy_handler*=mnissler@chromium.org
diff --git a/chrome/browser/sync/glue/sync_backend_host_impl.cc b/chrome/browser/sync/glue/sync_backend_host_impl.cc index 766b93a6..639fb10 100644 --- a/chrome/browser/sync/glue/sync_backend_host_impl.cc +++ b/chrome/browser/sync/glue/sync_backend_host_impl.cc
@@ -6,6 +6,7 @@ #include "base/command_line.h" #include "base/logging.h" +#include "base/profiler/scoped_tracker.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/profiles/profile.h" @@ -107,6 +108,9 @@ syncer::ReportUnrecoverableErrorFunction report_unrecoverable_error_function, syncer::NetworkResources* network_resources) { + // TODO(pavely): Remove ScopedTracker below once crbug.com/426272 is fixed. + tracked_objects::ScopedTracker tracker1(FROM_HERE_WITH_EXPLICIT_FUNCTION( + "426272 SyncBackendHostImpl::Initialize registrar")); registrar_.reset(new browser_sync::SyncBackendRegistrar(name_, profile_, sync_thread.Pass())); @@ -115,10 +119,16 @@ frontend_ = frontend; DCHECK(frontend); + // TODO(pavely): Remove ScopedTracker below once crbug.com/426272 is fixed. + tracked_objects::ScopedTracker tracker2(FROM_HERE_WITH_EXPLICIT_FUNCTION( + "426272 SyncBackendHostImpl::Initialize locks")); syncer::ModelSafeRoutingInfo routing_info; std::vector<scoped_refptr<syncer::ModelSafeWorker> > workers; registrar_->GetModelSafeRoutingInfo(&routing_info); registrar_->GetWorkers(&workers); + // TODO(pavely): Remove ScopedTracker below once crbug.com/426272 is fixed. + tracked_objects::ScopedTracker tracker3(FROM_HERE_WITH_EXPLICIT_FUNCTION( + "426272 SyncBackendHostImpl::Initialize init")); InternalComponentsFactory::Switches factory_switches = { InternalComponentsFactory::ENCRYPTION_KEYSTORE,
diff --git a/chrome/browser/sync/glue/sync_backend_registrar.cc b/chrome/browser/sync/glue/sync_backend_registrar.cc index 2926e15..97fa4efc 100644 --- a/chrome/browser/sync/glue/sync_backend_registrar.cc +++ b/chrome/browser/sync/glue/sync_backend_registrar.cc
@@ -9,6 +9,7 @@ #include "base/compiler_specific.h" #include "base/logging.h" #include "base/message_loop/message_loop.h" +#include "base/profiler/scoped_tracker.h" #include "chrome/browser/history/history_service_factory.h" #include "chrome/browser/password_manager/password_store_factory.h" #include "chrome/browser/profiles/profile.h" @@ -63,6 +64,9 @@ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); CHECK(profile_); + // TODO(pavely): Remove ScopedTracker below once crbug.com/426272 is fixed. + tracked_objects::ScopedTracker tracker1(FROM_HERE_WITH_EXPLICIT_FUNCTION( + "426272 SyncBackendRegistrar::ctor thread")); sync_thread_ = sync_thread.Pass(); if (!sync_thread_) { sync_thread_.reset(new base::Thread("Chrome_SyncThread")); @@ -87,6 +91,9 @@ new syncer::PassiveModelWorker(sync_thread_->message_loop(), this); workers_[syncer::GROUP_PASSIVE]->RegisterForLoopDestruction(); + // TODO(pavely): Remove ScopedTracker below once crbug.com/426272 is fixed. + tracked_objects::ScopedTracker tracker2(FROM_HERE_WITH_EXPLICIT_FUNCTION( + "426272 SyncBackendRegistrar::ctor history")); HistoryService* history_service = HistoryServiceFactory::GetForProfile(profile, Profile::IMPLICIT_ACCESS); if (history_service) { @@ -96,6 +103,9 @@ } + // TODO(pavely): Remove ScopedTracker below once crbug.com/426272 is fixed. + tracked_objects::ScopedTracker tracker3(FROM_HERE_WITH_EXPLICIT_FUNCTION( + "426272 SyncBackendRegistrar::ctor passwords")); scoped_refptr<password_manager::PasswordStore> password_store = PasswordStoreFactory::GetForProfile(profile, Profile::IMPLICIT_ACCESS); if (password_store.get()) {
diff --git a/chrome/browser/sync/profile_sync_components_factory_impl.cc b/chrome/browser/sync/profile_sync_components_factory_impl.cc index d6a219d4..2c9cd244 100644 --- a/chrome/browser/sync/profile_sync_components_factory_impl.cc +++ b/chrome/browser/sync/profile_sync_components_factory_impl.cc
@@ -83,7 +83,7 @@ #include "chrome/browser/sync/glue/extension_setting_data_type_controller.h" #endif -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) #include "chrome/browser/supervised_user/supervised_user_settings_service.h" #include "chrome/browser/supervised_user/supervised_user_settings_service_factory.h" #include "chrome/browser/supervised_user/supervised_user_shared_settings_service.h" @@ -283,7 +283,7 @@ this)); } -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) pss->RegisterDataTypeController( new SupervisedUserSyncDataTypeController( syncer::SUPERVISED_USER_SETTINGS, @@ -405,7 +405,7 @@ } #endif -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) pss->RegisterDataTypeController( new SupervisedUserSyncDataTypeController( syncer::SUPERVISED_USERS, @@ -528,7 +528,7 @@ return favicons ? favicons->AsWeakPtr() : base::WeakPtr<syncer::SyncableService>(); } -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) case syncer::SUPERVISED_USER_SETTINGS: return SupervisedUserSettingsServiceFactory::GetForProfile(profile_)-> AsWeakPtr();
diff --git a/chrome/browser/sync/sessions/notification_service_sessions_router.cc b/chrome/browser/sync/sessions/notification_service_sessions_router.cc index 574866a..9ae1027f 100644 --- a/chrome/browser/sync/sessions/notification_service_sessions_router.cc +++ b/chrome/browser/sync/sessions/notification_service_sessions_router.cc
@@ -20,7 +20,7 @@ #include "content/public/browser/notification_source.h" #include "content/public/browser/web_contents.h" -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) #include "chrome/browser/supervised_user/supervised_user_service.h" #include "chrome/browser/supervised_user/supervised_user_service_factory.h" #endif @@ -65,7 +65,7 @@ base::Bind(&NotificationServiceSessionsRouter::OnFaviconChanged, base::Unretained(this))); } -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) if (profile_->IsSupervised()) { SupervisedUserService* supervised_user_service = SupervisedUserServiceFactory::GetForProfile(profile_);
diff --git a/chrome/browser/sync/supervised_user_signin_manager_wrapper.cc b/chrome/browser/sync/supervised_user_signin_manager_wrapper.cc index 36c24eff..94d09a9 100644 --- a/chrome/browser/sync/supervised_user_signin_manager_wrapper.cc +++ b/chrome/browser/sync/supervised_user_signin_manager_wrapper.cc
@@ -8,7 +8,7 @@ #include "components/signin/core/browser/signin_manager_base.h" #include "google_apis/gaia/gaia_constants.h" -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) #include "chrome/browser/supervised_user/supervised_user_constants.h" #endif @@ -25,7 +25,7 @@ } std::string SupervisedUserSigninManagerWrapper::GetEffectiveUsername() const { -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) if (!original_->IsAuthenticated() && profile_->IsSupervised()) return supervised_users::kSupervisedUserPseudoEmail; #endif @@ -33,7 +33,7 @@ } std::string SupervisedUserSigninManagerWrapper::GetAccountIdToUse() const { -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) if (!original_->IsAuthenticated() && profile_->IsSupervised()) return supervised_users::kSupervisedUserPseudoEmail; #endif @@ -41,7 +41,7 @@ } std::string SupervisedUserSigninManagerWrapper::GetSyncScopeToUse() const { -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) if (!original_->IsAuthenticated() && profile_->IsSupervised()) return GaiaConstants::kChromeSyncSupervisedOAuth2Scope; #endif
diff --git a/chrome/browser/task_manager/task_manager.cc b/chrome/browser/task_manager/task_manager.cc index 07e1a1d..0bf47085 100644 --- a/chrome/browser/task_manager/task_manager.cc +++ b/chrome/browser/task_manager/task_manager.cc
@@ -242,37 +242,79 @@ listen_requests_(0), update_state_(IDLE), is_updating_byte_count_(false) { - // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed. - tracked_objects::ScopedTracker tracking_profile( + // TODO(vadimt): Remove ScopedTracker below once crbug.com/437890 is fixed. + tracked_objects::ScopedTracker tracking_profile1( FROM_HERE_WITH_EXPLICIT_FUNCTION( - "423948 TaskManagerModel::TaskManagerModel")); + "437890 TaskManagerModel::TaskManagerModel1")); AddResourceProvider( new task_manager::BrowserProcessResourceProvider(task_manager)); + + // TODO(vadimt): Remove ScopedTracker below once crbug.com/437890 is fixed. + tracked_objects::ScopedTracker tracking_profile2( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "437890 TaskManagerModel::TaskManagerModel2")); + AddResourceProvider(new task_manager::WebContentsResourceProvider( task_manager, scoped_ptr<WebContentsInformation>( new task_manager::BackgroundInformation()))); + + // TODO(vadimt): Remove ScopedTracker below once crbug.com/437890 is fixed. + tracked_objects::ScopedTracker tracking_profile3( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "437890 TaskManagerModel::TaskManagerModel3")); + AddResourceProvider(new task_manager::WebContentsResourceProvider( task_manager, scoped_ptr<WebContentsInformation>( new task_manager::TabContentsInformation()))); #if defined(ENABLE_PRINT_PREVIEW) + + // TODO(vadimt): Remove ScopedTracker below once crbug.com/437890 is fixed. + tracked_objects::ScopedTracker tracking_profile4( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "437890 TaskManagerModel::TaskManagerModel4")); + AddResourceProvider(new task_manager::WebContentsResourceProvider( task_manager, scoped_ptr<WebContentsInformation>( new task_manager::PrintingInformation()))); #endif // ENABLE_PRINT_PREVIEW + + // TODO(vadimt): Remove ScopedTracker below once crbug.com/437890 is fixed. + tracked_objects::ScopedTracker tracking_profile5( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "437890 TaskManagerModel::TaskManagerModel5")); + AddResourceProvider(new task_manager::WebContentsResourceProvider( task_manager, scoped_ptr<WebContentsInformation>( new task_manager::PanelInformation()))); + + // TODO(vadimt): Remove ScopedTracker below once crbug.com/437890 is fixed. + tracked_objects::ScopedTracker tracking_profile6( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "437890 TaskManagerModel::TaskManagerModel6")); + AddResourceProvider( new task_manager::ChildProcessResourceProvider(task_manager)); + + // TODO(vadimt): Remove ScopedTracker below once crbug.com/437890 is fixed. + tracked_objects::ScopedTracker tracking_profile7( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "437890 TaskManagerModel::TaskManagerModel7")); + AddResourceProvider(new task_manager::WebContentsResourceProvider( task_manager, scoped_ptr<WebContentsInformation>( new task_manager::ExtensionInformation()))); + + // TODO(vadimt): Remove ScopedTracker below once crbug.com/437890 is fixed. + tracked_objects::ScopedTracker tracking_profile8( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "437890 TaskManagerModel::TaskManagerModel8")); + AddResourceProvider(new task_manager::WebContentsResourceProvider( task_manager, scoped_ptr<WebContentsInformation>(
diff --git a/chrome/browser/task_manager/task_manager_browsertest.cc b/chrome/browser/task_manager/task_manager_browsertest.cc index 2cd34c2..6a17cf0 100644 --- a/chrome/browser/task_manager/task_manager_browsertest.cc +++ b/chrome/browser/task_manager/task_manager_browsertest.cc
@@ -35,8 +35,11 @@ #include "components/infobars/core/confirm_infobar_delegate.h" #include "components/infobars/core/infobar.h" #include "content/public/browser/notification_service.h" +#include "content/public/browser/page_navigator.h" +#include "content/public/browser/render_frame_host.h" #include "content/public/common/content_switches.h" #include "content/public/test/browser_test_utils.h" +#include "content/public/test/content_browser_test_utils.h" #include "extensions/browser/extension_system.h" #include "extensions/common/extension.h" #include "net/dns/mock_host_resolver.h" @@ -49,9 +52,11 @@ using task_manager::browsertest_util::MatchAboutBlankTab; using task_manager::browsertest_util::MatchAnyApp; using task_manager::browsertest_util::MatchAnyExtension; +using task_manager::browsertest_util::MatchAnySubframe; using task_manager::browsertest_util::MatchAnyTab; using task_manager::browsertest_util::MatchApp; using task_manager::browsertest_util::MatchExtension; +using task_manager::browsertest_util::MatchSubframe; using task_manager::browsertest_util::MatchTab; using task_manager::browsertest_util::WaitForTaskManagerRows; @@ -78,6 +83,13 @@ chrome::ShowTaskManager(browser()); } + void HideTaskManager() { + // Hide the task manager, and wait for the model to be depopulated. + chrome::HideTaskManager(); + base::RunLoop().RunUntilIdle(); // OnWindowClosed happens asynchronously. + EXPECT_EQ(0, model()->ResourceCount()); + } + void Refresh() { model()->Refresh(); } @@ -112,6 +124,31 @@ DISALLOW_COPY_AND_ASSIGN(TaskManagerBrowserTest); }; +// Parameterized variant of TaskManagerBrowserTest which runs with/without +// --site-per-process, which enables out of process iframes (OOPIFs). +class TaskManagerOOPIFBrowserTest : public TaskManagerBrowserTest, + public testing::WithParamInterface<bool> { + public: + TaskManagerOOPIFBrowserTest() {} + + protected: + void SetUpCommandLine(CommandLine* command_line) override { + TaskManagerBrowserTest::SetUpCommandLine(command_line); + if (GetParam()) + command_line->AppendSwitch(switches::kSitePerProcess); + } + + bool ShouldExpectSubframes() { + return CommandLine::ForCurrentProcess()->HasSwitch( + switches::kSitePerProcess); + } + + private: + DISALLOW_COPY_AND_ASSIGN(TaskManagerOOPIFBrowserTest); +}; + +INSTANTIATE_TEST_CASE_P(, TaskManagerOOPIFBrowserTest, ::testing::Bool()); + #if defined(OS_MACOSX) || defined(OS_LINUX) #define MAYBE_ShutdownWhileOpen DISABLED_ShutdownWhileOpen #else @@ -765,3 +802,243 @@ ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(3, MatchAnyTab())); DevToolsWindowTesting::CloseDevToolsWindowSync(devtools); } + +IN_PROC_BROWSER_TEST_P(TaskManagerOOPIFBrowserTest, KillSubframe) { + ShowTaskManager(); + + host_resolver()->AddRule("*", "127.0.0.1"); + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); + content::SetupCrossSiteRedirector(embedded_test_server()); + + GURL main_url(embedded_test_server()->GetURL( + "/cross-site/a.com/iframe_cross_site.html")); + browser()->OpenURL(content::OpenURLParams(main_url, content::Referrer(), + CURRENT_TAB, + ui::PAGE_TRANSITION_TYPED, false)); + + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchTab("cross-site iframe test"))); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); + + if (!ShouldExpectSubframes()) { + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe())); + } else { + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchSubframe("http://b.com/"))); + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchSubframe("http://c.com/"))); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(2, MatchAnySubframe())); + int subframe_b = FindResourceIndex(MatchSubframe("http://b.com/")); + ASSERT_NE(-1, subframe_b); + ASSERT_TRUE(model()->GetResourceWebContents(subframe_b) != NULL); + ASSERT_TRUE(model()->CanActivate(subframe_b)); + + TaskManager::GetInstance()->KillProcess(subframe_b); + + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(0, MatchSubframe("http://b.com/"))); + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchSubframe("http://c.com/"))); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnySubframe())); + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchTab("cross-site iframe test"))); + } + + HideTaskManager(); + ShowTaskManager(); + + if (!ShouldExpectSubframes()) { + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe())); + } else { + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(0, MatchSubframe("http://b.com/"))); + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchSubframe("http://c.com/"))); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnySubframe())); + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchTab("cross-site iframe test"))); + } +} + +// Tests what happens when a tab navigates to a site (a.com) that it previously +// has a cross-process subframe into (b.com). +// +// TODO(nick): Disabled because the second navigation hits an ASSERT(frame()) in +// WebLocalFrameImpl::loadRequest under --site-per-process. +IN_PROC_BROWSER_TEST_P(TaskManagerOOPIFBrowserTest, + DISABLED_NavigateToSubframeProcess) { + ShowTaskManager(); + + host_resolver()->AddRule("*", "127.0.0.1"); + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); + content::SetupCrossSiteRedirector(embedded_test_server()); + + // Navigate the tab to a page on a.com with cross-process subframes to + // b.com and c.com. + GURL a_dotcom(embedded_test_server()->GetURL( + "/cross-site/a.com/iframe_cross_site.html")); + browser()->OpenURL(content::OpenURLParams(a_dotcom, content::Referrer(), + CURRENT_TAB, + ui::PAGE_TRANSITION_TYPED, false)); + + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchTab("cross-site iframe test"))); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); + + if (!ShouldExpectSubframes()) { + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe())); + } else { + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchSubframe("http://b.com/"))); + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchSubframe("http://c.com/"))); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(2, MatchAnySubframe())); + } + + // Now navigate to a page on b.com with a simple (same-site) iframe. + // This should not show any subframe resources in the task manager. + GURL b_dotcom( + embedded_test_server()->GetURL("/cross-site/b.com/iframe.html")); + + browser()->OpenURL(content::OpenURLParams(b_dotcom, content::Referrer(), + CURRENT_TAB, + ui::PAGE_TRANSITION_TYPED, false)); + + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchTab("iframe test"))); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe())); + HideTaskManager(); + ShowTaskManager(); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchTab("iframe test"))); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe())); +} + +// TODO(nick): Fails flakily under OOPIF due to a ASSERT_NOT_REACHED in +// WebRemoteFrame, at least under debug OSX. http://crbug.com/437956 +IN_PROC_BROWSER_TEST_P(TaskManagerOOPIFBrowserTest, + DISABLED_NavigateToSiteWithSubframeToOriginalSite) { + ShowTaskManager(); + + host_resolver()->AddRule("*", "127.0.0.1"); + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); + content::SetupCrossSiteRedirector(embedded_test_server()); + + // Navigate to a page on b.com with a simple (same-site) iframe. + // This should not show any subframe resources in the task manager. + GURL b_dotcom( + embedded_test_server()->GetURL("/cross-site/b.com/iframe.html")); + + browser()->OpenURL(content::OpenURLParams(b_dotcom, content::Referrer(), + CURRENT_TAB, + ui::PAGE_TRANSITION_TYPED, false)); + + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchTab("iframe test"))); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe())); + + // Now navigate the tab to a page on a.com with cross-process subframes to + // b.com and c.com. + GURL a_dotcom(embedded_test_server()->GetURL( + "/cross-site/a.com/iframe_cross_site.html")); + browser()->OpenURL(content::OpenURLParams(a_dotcom, content::Referrer(), + CURRENT_TAB, + ui::PAGE_TRANSITION_TYPED, false)); + + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchTab("cross-site iframe test"))); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); + + if (!ShouldExpectSubframes()) { + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe())); + } else { + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchSubframe("http://b.com/"))); + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchSubframe("http://c.com/"))); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(2, MatchAnySubframe())); + } + + HideTaskManager(); + ShowTaskManager(); + + if (!ShouldExpectSubframes()) { + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe())); + } else { + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchSubframe("http://b.com/"))); + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchSubframe("http://c.com/"))); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(2, MatchAnySubframe())); + } +} + +// Tests what happens when a tab navigates a cross-frame iframe (to b.com) +// back to the site of the parent document (a.com). +// +// TODO(nick): Disabled because the second navigation crashes the renderer +// under --site-per-process during blink::Frame::detach(). +IN_PROC_BROWSER_TEST_P(TaskManagerOOPIFBrowserTest, + DISABLED_CrossSiteIframeBecomesSameSite) { + ShowTaskManager(); + + host_resolver()->AddRule("*", "127.0.0.1"); + ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); + content::SetupCrossSiteRedirector(embedded_test_server()); + + // Navigate the tab to a page on a.com with cross-process subframes to + // b.com and c.com. + GURL a_dotcom(embedded_test_server()->GetURL( + "/cross-site/a.com/iframe_cross_site.html")); + browser()->OpenURL(content::OpenURLParams(a_dotcom, content::Referrer(), + CURRENT_TAB, + ui::PAGE_TRANSITION_TYPED, false)); + + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchTab("cross-site iframe test"))); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); + + if (!ShouldExpectSubframes()) { + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe())); + } else { + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchSubframe("http://b.com/"))); + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchSubframe("http://c.com/"))); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(2, MatchAnySubframe())); + } + + // Navigate the b.com frame back to a.com. It is no longer a cross-site iframe + ASSERT_TRUE(content::ExecuteScript( + browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame(), + "document.getElementById('frame1').src='/title1.html';" + "document.title='aac';")); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchTab("aac"))); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); + if (!ShouldExpectSubframes()) { + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe())); + } else { + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(0, MatchSubframe("http://b.com/"))); + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchSubframe("http://c.com/"))); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnySubframe())); + } + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchTab("aac"))); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); + + HideTaskManager(); + ShowTaskManager(); + + if (!ShouldExpectSubframes()) { + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnySubframe())); + } else { + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(0, MatchSubframe("http://b.com/"))); + ASSERT_NO_FATAL_FAILURE( + WaitForTaskManagerRows(1, MatchSubframe("http://c.com/"))); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnySubframe())); + } + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchTab("aac"))); + ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); +}
diff --git a/chrome/browser/task_manager/task_manager_browsertest_util.cc b/chrome/browser/task_manager/task_manager_browsertest_util.cc index 6ece5a4..cc575bc1 100644 --- a/chrome/browser/task_manager/task_manager_browsertest_util.cc +++ b/chrome/browser/task_manager/task_manager_browsertest_util.cc
@@ -184,5 +184,14 @@ base::string16 MatchAnyPrint() { return MatchPrint("*"); } +base::string16 MatchSubframe(const char* title) { + return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_SUBFRAME_PREFIX, + base::ASCIIToUTF16(title)); +} + +base::string16 MatchAnySubframe() { + return MatchSubframe("*"); +} + } // namespace browsertest_util } // namespace task_manager
diff --git a/chrome/browser/task_manager/task_manager_browsertest_util.h b/chrome/browser/task_manager/task_manager_browsertest_util.h index 9b4010e..e66ec37 100644 --- a/chrome/browser/task_manager/task_manager_browsertest_util.h +++ b/chrome/browser/task_manager/task_manager_browsertest_util.h
@@ -35,6 +35,8 @@ base::string16 MatchAnyBackground(); // "Background: *" base::string16 MatchPrint(const char* title); // "Print: " + title base::string16 MatchAnyPrint(); // "Print: *" +base::string16 MatchSubframe(const char* title); // "Subframe: " + title +base::string16 MatchAnySubframe(); // "Subframe: *" } // namespace browsertest_util } // namespace task_manager
diff --git a/chrome/browser/task_manager/web_contents_resource_provider.cc b/chrome/browser/task_manager/web_contents_resource_provider.cc index b3cdf672..dc720db 100644 --- a/chrome/browser/task_manager/web_contents_resource_provider.cc +++ b/chrome/browser/task_manager/web_contents_resource_provider.cc
@@ -27,8 +27,9 @@ #include "ui/base/l10n/l10n_util.h" #include "ui/gfx/image/image_skia.h" -using content::RenderViewHost; using content::RenderFrameHost; +using content::RenderProcessHost; +using content::RenderViewHost; using content::SiteInstance; using content::WebContents; @@ -86,7 +87,8 @@ // Tracks changes to one WebContents, and manages task manager resources for // that WebContents, on behalf of a WebContentsResourceProvider. -class TaskManagerWebContentsEntry : public content::WebContentsObserver { +class TaskManagerWebContentsEntry : public content::WebContentsObserver, + public content::RenderProcessHostObserver { public: typedef std::multimap<SiteInstance*, RendererResource*> ResourceMap; typedef std::pair<ResourceMap::iterator, ResourceMap::iterator> ResourceRange; @@ -97,19 +99,7 @@ provider_(provider), main_frame_site_instance_(NULL) {} - ~TaskManagerWebContentsEntry() override { - for (ResourceMap::iterator j = resources_by_site_instance_.begin(); - j != resources_by_site_instance_.end();) { - RendererResource* resource = j->second; - - // Advance to next non-duplicate entry. - do { - ++j; - } while (j != resources_by_site_instance_.end() && resource == j->second); - - delete resource; - } - } + ~TaskManagerWebContentsEntry() override { ClearAllResources(false); } // content::WebContentsObserver implementation. void RenderFrameDeleted(RenderFrameHost* render_frame_host) override { @@ -124,17 +114,24 @@ } void RenderViewReady() override { - ClearAllResources(); + ClearAllResources(true); CreateAllResources(); } - void RenderProcessGone(base::TerminationStatus status) override { - ClearAllResources(); + void WebContentsDestroyed() override { + ClearAllResources(true); + provider_->DeleteEntry(web_contents(), this); // Deletes |this|. } - void WebContentsDestroyed() override { - ClearAllResources(); - provider_->DeleteEntry(web_contents(), this); // Deletes |this|. + // content::RenderProcessHostObserver implementation. + void RenderProcessExited(RenderProcessHost* process_host, + base::TerminationStatus status, + int exit_code) override { + ClearResourcesForProcess(process_host); + } + + void RenderProcessHostDestroyed(RenderProcessHost* process_host) override { + tracked_process_hosts_.erase(process_host); } // Called by WebContentsResourceProvider. @@ -153,21 +150,27 @@ base::Unretained(this))); } - void ClearAllResources() { - for (ResourceMap::iterator j = resources_by_site_instance_.begin(); - j != resources_by_site_instance_.end();) { - RendererResource* resource = j->second; - - // Advance to next non-duplicate entry. - do { - ++j; - } while (j != resources_by_site_instance_.end() && resource == j->second); - - // Remove the resource from the Task Manager. - task_manager()->RemoveResource(resource); + void ClearAllResources(bool update_task_manager) { + RendererResource* last_resource = NULL; + for (auto& x : resources_by_site_instance_) { + RendererResource* resource = x.second; + if (resource == last_resource) + continue; // Skip multiset duplicates. + if (update_task_manager) + task_manager()->RemoveResource(resource); delete resource; + last_resource = resource; } resources_by_site_instance_.clear(); + + RenderProcessHost* last_process_host = NULL; + for (RenderProcessHost* process_host : tracked_process_hosts_) { + if (last_process_host == process_host) + continue; // Skip multiset duplicates. + process_host->RemoveObserver(this); + last_process_host = process_host; + } + tracked_process_hosts_.clear(); tracked_frame_hosts_.clear(); } @@ -193,16 +196,33 @@ // actually destroy it. task_manager()->RemoveResource(resource); delete resource; + DecrementProcessWatch(site_instance->GetProcess()); if (site_instance == main_frame_site_instance_) { main_frame_site_instance_ = NULL; } } } + void ClearResourcesForProcess(RenderProcessHost* crashed_process) { + std::vector<RenderFrameHost*> frame_hosts_to_delete; + for (RenderFrameHost* frame_host : tracked_frame_hosts_) { + if (frame_host->GetProcess() == crashed_process) { + frame_hosts_to_delete.push_back(frame_host); + } + } + for (RenderFrameHost* frame_host : frame_hosts_to_delete) { + ClearResourceForFrame(frame_host); + } + } + void CreateResourceForFrame(RenderFrameHost* render_frame_host) { SiteInstance* site_instance = render_frame_host->GetSiteInstance(); DCHECK_EQ(0u, tracked_frame_hosts_.count(render_frame_host)); + + if (!site_instance->GetProcess()->HasConnection()) + return; + tracked_frame_hosts_.insert(render_frame_host); ResourceRange existing_resource_range = @@ -235,6 +255,7 @@ } task_manager()->RemoveResource(old_resource); delete old_resource; + DecrementProcessWatch(site_instance->GetProcess()); } } @@ -242,17 +263,56 @@ task_manager()->AddResource(new_resource.get()); resources_by_site_instance_.insert( std::make_pair(site_instance, new_resource.release())); + IncrementProcessWatch(site_instance->GetProcess()); } } + // Add ourself as an observer of |process|, if we aren't already. Must be + // balanced by a call to DecrementProcessWatch(). + // TODO(nick): Move away from RenderProcessHostObserver once + // WebContentsObserver supports per-frame process death notices. + void IncrementProcessWatch(RenderProcessHost* process) { + auto range = tracked_process_hosts_.equal_range(process); + if (range.first == range.second) { + process->AddObserver(this); + } + tracked_process_hosts_.insert(range.first, process); + } + + void DecrementProcessWatch(RenderProcessHost* process) { + auto range = tracked_process_hosts_.equal_range(process); + if (range.first == range.second) { + NOTREACHED(); + return; + } + + auto element = range.first++; + if (range.first == range.second) { + process->RemoveObserver(this); + } + tracked_process_hosts_.erase(element, range.first); + } + private: TaskManager* task_manager() { return provider_->task_manager(); } WebContentsInformation* info() { return provider_->info(); } WebContentsResourceProvider* const provider_; + + // Every RenderFrameHost that we're watching. std::set<RenderFrameHost*> tracked_frame_hosts_; + + // The set of processes we're currently observing. There is one entry here per + // RendererResource we create. A multimap because we may request observation + // more than once, say if two resources happen to share a process. + std::multiset<RenderProcessHost*> tracked_process_hosts_; + + // Maps SiteInstances to the RendererResources. A multimap, this contains one + // entry per tracked RenderFrameHost, so we can tell when we're done reusing. ResourceMap resources_by_site_instance_; + + // The site instance of the main frame. SiteInstance* main_frame_site_instance_; };
diff --git a/chrome/browser/themes/theme_properties.h b/chrome/browser/themes/theme_properties.h index 249a8bc..3a34e8b 100644 --- a/chrome/browser/themes/theme_properties.h +++ b/chrome/browser/themes/theme_properties.h
@@ -88,7 +88,7 @@ COLOR_NTP_SECTION_HEADER_RULE, COLOR_NTP_SECTION_HEADER_RULE_LIGHT, COLOR_NTP_TEXT_LIGHT, -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) COLOR_SUPERVISED_USER_LABEL, COLOR_SUPERVISED_USER_LABEL_BACKGROUND, COLOR_SUPERVISED_USER_LABEL_BORDER,
diff --git a/chrome/browser/themes/theme_service.cc b/chrome/browser/themes/theme_service.cc index 758b5d97..053cfb89 100644 --- a/chrome/browser/themes/theme_service.cc +++ b/chrome/browser/themes/theme_service.cc
@@ -35,7 +35,7 @@ #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/image/image_skia.h" -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) #include "chrome/browser/supervised_user/supervised_user_theme.h" #endif @@ -171,7 +171,7 @@ return IncreaseLightness(GetColor(Properties::COLOR_NTP_TEXT), 0.86); case Properties::COLOR_NTP_TEXT_LIGHT: return IncreaseLightness(GetColor(Properties::COLOR_NTP_TEXT), 0.40); -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) case Properties::COLOR_SUPERVISED_USER_LABEL: return color_utils::GetReadableColor( SK_ColorWHITE, @@ -401,7 +401,7 @@ void ThemeService::UseDefaultTheme() { if (ready_) content::RecordAction(UserMetricsAction("Themes_Reset")); -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) if (IsSupervisedUser()) { SetSupervisedUserTheme(); return; @@ -462,7 +462,7 @@ std::string current_id = GetThemeID(); if (current_id == kDefaultThemeID) { -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) // Supervised users have a different default theme. if (IsSupervisedUser()) { SetSupervisedUserTheme(); @@ -617,7 +617,7 @@ SwapThemeSupplier(pack); } -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) bool ThemeService::IsSupervisedUser() const { return profile_->IsSupervised(); }
diff --git a/chrome/browser/themes/theme_service.h b/chrome/browser/themes/theme_service.h index c6135ab..b70fd74 100644 --- a/chrome/browser/themes/theme_service.h +++ b/chrome/browser/themes/theme_service.h
@@ -207,7 +207,7 @@ // case we don't have a theme pack). void BuildFromExtension(const extensions::Extension* extension); -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) // Returns true if the profile belongs to a supervised user. bool IsSupervisedUser() const;
diff --git a/chrome/browser/themes/theme_service_unittest.cc b/chrome/browser/themes/theme_service_unittest.cc index e8d760a..82cd20d 100644 --- a/chrome/browser/themes/theme_service_unittest.cc +++ b/chrome/browser/themes/theme_service_unittest.cc
@@ -23,7 +23,7 @@ #include "extensions/common/extension.h" #include "testing/gtest/include/gtest/gtest.h" -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) #include "chrome/browser/supervised_user/supervised_user_service.h" #include "chrome/browser/supervised_user/supervised_user_service_factory.h" #endif @@ -237,7 +237,7 @@ ExtensionRegistry::DISABLED)); } -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) class ThemeServiceSupervisedUserTest : public ThemeServiceTest { public: ThemeServiceSupervisedUserTest() {} @@ -275,6 +275,6 @@ CustomThemeSupplier::SUPERVISED_USER_THEME); } #endif // defined(OS_LINUX) && !defined(OS_CHROMEOS) -#endif // defined(ENABLE_MANAGED_USERS) +#endif // defined(ENABLE_SUPERVISED_USERS) }; // namespace theme_service_internal
diff --git a/chrome/browser/ui/app_list/app_list_controller_delegate_impl.cc b/chrome/browser/ui/app_list/app_list_controller_delegate_impl.cc index 98116d21..61b4542 100644 --- a/chrome/browser/ui/app_list/app_list_controller_delegate_impl.cc +++ b/chrome/browser/ui/app_list/app_list_controller_delegate_impl.cc
@@ -11,6 +11,7 @@ #include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/browser_dialogs.h" #include "chrome/browser/ui/browser_navigator.h" +#include "chrome/browser/ui/extensions/app_launch_params.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" #include "extensions/browser/extension_system.h" @@ -111,7 +112,8 @@ int event_flags) { AppListServiceImpl::RecordAppListAppLaunch(); - AppLaunchParams params(profile, extension, NEW_FOREGROUND_TAB); + AppLaunchParams params(profile, extension, NEW_FOREGROUND_TAB, + extensions::SOURCE_APP_LAUNCHER); if (source != LAUNCH_FROM_UNKNOWN && extension->id() == extensions::kWebStoreAppId) { @@ -122,7 +124,6 @@ extension_urls::kWebstoreSourceField, AppListSourceToString(source)); } - params.source = extensions::SOURCE_APP_LAUNCHER; FillLaunchParams(¶ms); OpenApplication(params);
diff --git a/chrome/browser/ui/app_list/app_list_shower_views.cc b/chrome/browser/ui/app_list/app_list_shower_views.cc index 5de2d80..b34e9fc 100644 --- a/chrome/browser/ui/app_list/app_list_shower_views.cc +++ b/chrome/browser/ui/app_list/app_list_shower_views.cc
@@ -115,10 +115,27 @@ } app_list::AppListView* AppListShower::MakeViewForCurrentProfile() { + // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. + tracked_objects::ScopedTracker tracking_profile1( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "431326 AppListShower::MakeViewForCurrentProfile1")); + // The app list view manages its own lifetime. app_list::AppListView* view = new app_list::AppListView(delegate_->GetViewDelegateForCreate()); + + // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. + tracked_objects::ScopedTracker tracking_profile2( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "431326 AppListShower::MakeViewForCurrentProfile2")); + gfx::Point cursor = gfx::Screen::GetNativeScreen()->GetCursorScreenPoint(); + + // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. + tracked_objects::ScopedTracker tracking_profile3( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "431326 AppListShower::MakeViewForCurrentProfile3")); + view->InitAsBubbleAtFixedLocation(NULL, 0, cursor,
diff --git a/chrome/browser/ui/app_list/app_list_view_delegate.cc b/chrome/browser/ui/app_list/app_list_view_delegate.cc index 6c426ceb5..570c13d1 100644 --- a/chrome/browser/ui/app_list/app_list_view_delegate.cc +++ b/chrome/browser/ui/app_list/app_list_view_delegate.cc
@@ -11,6 +11,7 @@ #include "base/command_line.h" #include "base/files/file_path.h" #include "base/metrics/user_metrics.h" +#include "base/profiler/scoped_tracker.h" #include "base/stl_util.h" #include "chrome/browser/apps/scoped_keep_alive.h" #include "chrome/browser/browser_process.h" @@ -158,6 +159,11 @@ profile_(NULL), model_(NULL), scoped_observer_(this) { + // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. + tracked_objects::ScopedTracker tracking_profile( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "431326 AppListViewDelegate::AppListViewDelegate")); + CHECK(controller_); // The SigninManagerFactor and the SigninManagers are observed to keep the // profile switcher menu up to date, with the correct list of profiles and the @@ -206,6 +212,11 @@ } void AppListViewDelegate::SetProfile(Profile* new_profile) { + // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. + tracked_objects::ScopedTracker tracking_profile( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "431326 AppListViewDelegate::SetProfile")); + if (profile_ == new_profile) return;
diff --git a/chrome/browser/ui/app_list/search/search_resource_manager.cc b/chrome/browser/ui/app_list/search/search_resource_manager.cc index 4c6a1c1..f83f15b 100644 --- a/chrome/browser/ui/app_list/search/search_resource_manager.cc +++ b/chrome/browser/ui/app_list/search/search_resource_manager.cc
@@ -15,6 +15,23 @@ namespace app_list { +namespace { + +scoped_ptr<SearchBoxModel::SpeechButtonProperty> CreateNewProperty( + SpeechRecognitionState state) { + if (state == SPEECH_RECOGNITION_OFF) + return nullptr; + + ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); + return make_scoped_ptr(new SearchBoxModel::SpeechButtonProperty( + *bundle.GetImageSkiaNamed(IDR_OMNIBOX_MIC_SEARCH), + l10n_util::GetStringUTF16(IDS_APP_LIST_HOTWORD_LISTENING), + *bundle.GetImageSkiaNamed(IDR_APP_LIST_MIC_HOTWORD_OFF), + l10n_util::GetStringUTF16(IDS_APP_LIST_START_SPEECH_RECOGNITION))); +} + +} // namespace + SearchResourceManager::SearchResourceManager(Profile* profile, SearchBoxModel* search_box, SpeechUIModel* speech_ui) @@ -24,18 +41,6 @@ ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); search_box_->SetIcon(*bundle.GetImageSkiaNamed(IDR_OMNIBOX_SEARCH)); - StartPageService* service = StartPageService::Get(profile); - if (service && service->GetSpeechRecognitionContents()) { - search_box_->SetSpeechRecognitionButton( - scoped_ptr<SearchBoxModel::SpeechButtonProperty>( - new SearchBoxModel::SpeechButtonProperty( - *bundle.GetImageSkiaNamed(IDR_OMNIBOX_MIC_SEARCH), - l10n_util::GetStringUTF16( - IDS_APP_LIST_HOTWORD_LISTENING), - *bundle.GetImageSkiaNamed(IDR_APP_LIST_MIC_HOTWORD_OFF), - l10n_util::GetStringUTF16( - IDS_APP_LIST_START_SPEECH_RECOGNITION)))); - } OnSpeechRecognitionStateChanged(speech_ui_->state()); } @@ -48,6 +53,7 @@ search_box_->SetHintText(l10n_util::GetStringUTF16( (new_state == SPEECH_RECOGNITION_HOTWORD_LISTENING) ? IDS_SEARCH_BOX_HOTWORD_HINT : IDS_SEARCH_BOX_HINT)); + search_box_->SetSpeechRecognitionButton(CreateNewProperty(new_state)); } } // namespace app_list
diff --git a/chrome/browser/ui/app_list/start_page_service.cc b/chrome/browser/ui/app_list/start_page_service.cc index 2f14a4a..b1164a0 100644 --- a/chrome/browser/ui/app_list/start_page_service.cc +++ b/chrome/browser/ui/app_list/start_page_service.cc
@@ -36,6 +36,10 @@ #include "extensions/common/extension.h" #include "ui/app_list/app_list_switches.h" +#if defined(OS_CHROMEOS) +#include "chromeos/audio/cras_audio_handler.h" +#endif + using base::RecordAction; using base::UserMetricsAction; @@ -48,7 +52,7 @@ state == SPEECH_RECOGNITION_IN_SPEECH; } -} +} // namespace class StartPageService::ProfileDestroyObserver : public content::NotificationObserver { @@ -102,6 +106,48 @@ DISALLOW_COPY_AND_ASSIGN(StartPageWebContentsDelegate); }; +#if defined(OS_CHROMEOS) + +class StartPageService::AudioStatus + : public chromeos::CrasAudioHandler::AudioObserver { + public: + explicit AudioStatus(StartPageService* start_page_service) + : start_page_service_(start_page_service) { + chromeos::CrasAudioHandler::Get()->AddAudioObserver(this); + CheckAndUpdate(); + } + + ~AudioStatus() override { + chromeos::CrasAudioHandler::Get()->RemoveAudioObserver(this); + } + + bool CanListen() { + chromeos::CrasAudioHandler* audio_handler = + chromeos::CrasAudioHandler::Get(); + return (audio_handler->GetPrimaryActiveInputNode() != 0) && + !audio_handler->IsInputMuted(); + } + + private: + void CheckAndUpdate() { + // TODO(mukai): If the system can listen, this should also restart the + // hotword recognition. + start_page_service_->OnSpeechRecognitionStateChanged( + CanListen() ? SPEECH_RECOGNITION_READY : SPEECH_RECOGNITION_OFF); + } + + // chromeos::CrasAudioHandler::AudioObserver: + void OnInputMuteChanged() override { CheckAndUpdate(); } + + void OnActiveInputNodeChanged() override { CheckAndUpdate(); } + + StartPageService* start_page_service_; + + DISALLOW_COPY_AND_ASSIGN(AudioStatus); +}; + +#endif // OS_CHROMEOS + // static StartPageService* StartPageService::Get(Profile* profile) { return StartPageServiceFactory::GetForProfile(profile); @@ -119,8 +165,9 @@ // If experimental hotwording is enabled, then we're always "ready". // Transitioning into the "hotword recognizing" state is handled by the // hotword extension. - if (HotwordService::IsExperimentalHotwordingEnabled()) + if (HotwordService::IsExperimentalHotwordingEnabled()) { state_ = app_list::SPEECH_RECOGNITION_READY; + } if (app_list::switches::IsExperimentalAppListEnabled()) LoadContents(); @@ -148,6 +195,10 @@ "appList.startPage.onAppListShown", base::FundamentalValue(HotwordEnabled())); } + +#if defined(OS_CHROMEOS) + audio_status_.reset(new AudioStatus(this)); +#endif } void StartPageService::AppListHidden() { @@ -162,6 +213,10 @@ speech_recognizer_) { speech_recognizer_->Stop(); } + +#if defined(OS_CHROMEOS) + audio_status_.reset(); +#endif } void StartPageService::ToggleSpeechRecognition() { @@ -251,6 +306,14 @@ void StartPageService::OnSpeechRecognitionStateChanged( SpeechRecognitionState new_state) { +#if defined(OS_CHROMEOS) + // Sometimes this can be called even though there are no audio input devices. + if (audio_status_ && !audio_status_->CanListen()) + new_state = SPEECH_RECOGNITION_OFF; +#endif + + if (state_ == new_state) + return; if (HotwordService::IsExperimentalHotwordingEnabled() && new_state == SPEECH_RECOGNITION_READY && @@ -283,6 +346,9 @@ void StartPageService::Shutdown() { UnloadContents(); +#if defined(OS_CHROMEOS) + audio_status_.reset(); +#endif } void StartPageService::WebUILoaded() {
diff --git a/chrome/browser/ui/app_list/start_page_service.h b/chrome/browser/ui/app_list/start_page_service.h index 61e2260..d33bd53 100644 --- a/chrome/browser/ui/app_list/start_page_service.h +++ b/chrome/browser/ui/app_list/start_page_service.h
@@ -88,6 +88,12 @@ // getUserMedia() request from the web contents. class StartPageWebContentsDelegate; +#if defined(OS_CHROMEOS) + // This class observes the change of audio input device availability and + // checks if currently the system has valid audio input. + class AudioStatus; +#endif + void LoadContents(); void UnloadContents(); @@ -109,6 +115,10 @@ scoped_ptr<SpeechRecognizer> speech_recognizer_; +#if defined(OS_CHROMEOS) + scoped_ptr<AudioStatus> audio_status_; +#endif + base::WeakPtrFactory<StartPageService> weak_factory_; DISALLOW_COPY_AND_ASSIGN(StartPageService);
diff --git a/chrome/browser/ui/ash/chrome_new_window_delegate_chromeos.cc b/chrome/browser/ui/ash/chrome_new_window_delegate_chromeos.cc index f616847..56d7d24 100644 --- a/chrome/browser/ui/ash/chrome_new_window_delegate_chromeos.cc +++ b/chrome/browser/ui/ash/chrome_new_window_delegate_chromeos.cc
@@ -12,12 +12,15 @@ #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/extensions/app_launch_params.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h" #include "chrome/browser/ui/webui/chrome_web_contents_handler.h" #include "chrome/common/url_constants.h" #include "content/public/browser/web_contents.h" #include "extensions/browser/extension_system.h" +#include "extensions/common/constants.h" +#include "ui/base/window_open_disposition.h" ChromeNewWindowDelegateChromeos::ChromeNewWindowDelegateChromeos() {} ChromeNewWindowDelegateChromeos::~ChromeNewWindowDelegateChromeos() {} @@ -35,12 +38,9 @@ const extensions::Extension* const extension = service->GetInstalledExtension(kFileManagerAppId); - // event_flags = 0 means this invokes the same behavior as the launcher - // item is clicked without any keyboard modifiers. - OpenApplication(AppLaunchParams(profile, - extension, - 0 /* event_flags */, - chrome::HOST_DESKTOP_TYPE_ASH)); + OpenApplication(AppLaunchParams(profile, extension, CURRENT_TAB, + chrome::HOST_DESKTOP_TYPE_ASH, + extensions::SOURCE_CHROME_INTERNAL)); } void ChromeNewWindowDelegateChromeos::OpenCrosh() {
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc index 0d81c8f1..1ec9441 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
@@ -56,6 +56,7 @@ #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/browser_tabstrip.h" #include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/extensions/app_launch_params.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/browser/ui/extensions/extension_enable_flow.h" #include "chrome/browser/ui/host_desktop.h" @@ -85,6 +86,7 @@ #include "ui/aura/window.h" #include "ui/aura/window_event_dispatcher.h" #include "ui/base/l10n/l10n_util.h" +#include "ui/base/window_open_disposition.h" #include "ui/keyboard/keyboard_util.h" #include "ui/resources/grit/ui_resources.h" #include "ui/wm/core/window_animations.h" @@ -734,10 +736,9 @@ #endif // The app will be created for the currently active profile. - AppLaunchParams params(profile_, - extension, - event_flags, - chrome::HOST_DESKTOP_TYPE_ASH); + AppLaunchParams params( + profile_, extension, ui::DispositionFromEventFlags(event_flags), + chrome::HOST_DESKTOP_TYPE_ASH, extensions::SOURCE_APP_LAUNCHER); if (source != ash::LAUNCH_FROM_UNKNOWN && app_id == extensions::kWebStoreAppId) { // Get the corresponding source string. @@ -749,10 +750,6 @@ extension_url, extension_urls::kWebstoreSourceField, source_value); } - params.source = (source == ash::LAUNCH_FROM_UNKNOWN) - ? extensions::SOURCE_UNTRACKED - : extensions::SOURCE_APP_LAUNCHER; - OpenApplication(params); } @@ -1849,6 +1846,7 @@ model_->AddAt(index, item); app_icon_loader_->FetchImage(app_id); + app_icon_loader_->UpdateImage(app_id); SetShelfItemDelegate(id, controller);
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc index cd53877c..fa4e167 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_browsertest.cc
@@ -38,6 +38,7 @@ #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/chrome_pages.h" +#include "chrome/browser/ui/extensions/app_launch_params.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/browser/ui/host_desktop.h" #include "chrome/browser/ui/settings_window_manager.h" @@ -60,6 +61,7 @@ #include "ui/app_list/views/apps_grid_view.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/window.h" +#include "ui/base/window_open_disposition.h" #include "ui/events/event.h" #include "ui/events/test/event_generator.h" @@ -220,10 +222,8 @@ service->GetExtensionById(last_loaded_extension_id(), false); EXPECT_TRUE(extension); - OpenApplication(AppLaunchParams(profile(), - extension, - container, - disposition)); + OpenApplication(AppLaunchParams(profile(), extension, container, + disposition, extensions::SOURCE_UNTRACKED)); return extension; } @@ -2078,10 +2078,8 @@ // Create a windowed application. AppLaunchParams params( - profile(), - controller_->GetExtensionForAppID(extensions::kWebStoreAppId), - 0, - chrome::HOST_DESKTOP_TYPE_ASH); + profile(), controller_->GetExtensionForAppID(extensions::kWebStoreAppId), + CURRENT_TAB, chrome::HOST_DESKTOP_TYPE_ASH, extensions::SOURCE_UNTRACKED); params.container = extensions::LAUNCH_CONTAINER_WINDOW; OpenApplication(params); EXPECT_EQ(ash::STATUS_ACTIVE, model_->ItemByID(id)->status);
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc index 72e6c2b..ced23b6 100644 --- a/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc +++ b/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc
@@ -74,9 +74,8 @@ gfx::NativeView container_view, const gfx::RectF& element_bounds, base::i18n::TextDirection text_direction) { - DCHECK(!previous.get() || previous->delegate_.get() == delegate.get()); - if (previous.get() && previous->web_contents() == web_contents && + previous->delegate_.get() == delegate.get() && previous->container_view() == container_view && previous->element_bounds() == element_bounds) { previous->ClearState();
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_interactive_uitest.cc b/chrome/browser/ui/autofill/autofill_popup_controller_interactive_uitest.cc index 3d5a686..9331f1c 100644 --- a/chrome/browser/ui/autofill/autofill_popup_controller_interactive_uitest.cc +++ b/chrome/browser/ui/autofill/autofill_popup_controller_interactive_uitest.cc
@@ -10,6 +10,7 @@ #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/test/base/in_process_browser_test.h" #include "components/autofill/content/browser/content_autofill_driver.h" +#include "components/autofill/content/browser/content_autofill_driver_factory.h" #include "components/autofill/core/browser/autofill_manager.h" #include "components/autofill/core/browser/test_autofill_external_delegate.h" #include "content/public/browser/web_contents.h" @@ -78,7 +79,8 @@ Observe(web_contents); ContentAutofillDriver* driver = - ContentAutofillDriver::FromWebContents(web_contents); + ContentAutofillDriverFactory::FromWebContents(web_contents) + ->DriverForFrame(web_contents->GetMainFrame()); autofill_external_delegate_.reset( new TestAutofillExternalDelegate( web_contents,
diff --git a/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc b/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc index fef22be..9265f0a1 100644 --- a/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc +++ b/chrome/browser/ui/autofill/autofill_popup_controller_unittest.cc
@@ -13,12 +13,14 @@ #include "chrome/test/base/chrome_render_view_host_test_harness.h" #include "chrome/test/base/testing_profile.h" #include "components/autofill/content/browser/content_autofill_driver.h" +#include "components/autofill/content/browser/content_autofill_driver_factory.h" #include "components/autofill/core/browser/autofill_external_delegate.h" #include "components/autofill/core/browser/autofill_manager.h" #include "components/autofill/core/browser/autofill_test_utils.h" #include "components/autofill/core/browser/popup_item_ids.h" #include "components/autofill/core/browser/test_autofill_client.h" #include "components/autofill/core/browser/test_autofill_external_delegate.h" +#include "content/public/browser/web_contents.h" #include "grit/components_scaled_resources.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -129,13 +131,13 @@ void SetUp() override { ChromeRenderViewHostTestHarness::SetUp(); - ContentAutofillDriver::CreateForWebContentsAndDelegate( - web_contents(), - autofill_client_.get(), - "en-US", + ContentAutofillDriverFactory::CreateForWebContentsAndDelegate( + web_contents(), autofill_client_.get(), "en-US", AutofillManager::ENABLE_AUTOFILL_DOWNLOAD_MANAGER); + ContentAutofillDriverFactory* factory = + ContentAutofillDriverFactory::FromWebContents(web_contents()); ContentAutofillDriver* driver = - ContentAutofillDriver::FromWebContents(web_contents()); + factory->DriverForFrame(web_contents()->GetMainFrame()); external_delegate_.reset( new NiceMock<MockAutofillExternalDelegate>( driver->autofill_manager(), @@ -425,8 +427,10 @@ } TEST_F(AutofillPopupControllerUnitTest, GetOrCreate) { + ContentAutofillDriverFactory* factory = + ContentAutofillDriverFactory::FromWebContents(web_contents()); ContentAutofillDriver* driver = - ContentAutofillDriver::FromWebContents(web_contents()); + factory->DriverForFrame(web_contents()->GetMainFrame()); MockAutofillExternalDelegate delegate(driver->autofill_manager(), driver); WeakPtr<AutofillPopupControllerImpl> controller =
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc index c008944..45cad2ae 100644 --- a/chrome/browser/ui/autofill/chrome_autofill_client.cc +++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -24,6 +24,7 @@ #include "components/autofill/content/browser/content_autofill_driver.h" #include "components/autofill/content/common/autofill_messages.h" #include "components/autofill/core/common/autofill_pref_names.h" +#include "components/password_manager/content/browser/content_password_manager_driver.h" #include "content/public/browser/render_view_host.h" #include "ui/gfx/rect.h" @@ -205,12 +206,11 @@ } void ChromeAutofillClient::DetectAccountCreationForms( + content::RenderFrameHost* rfh, const std::vector<autofill::FormStructure*>& forms) { - password_manager::PasswordGenerationManager* manager = - ChromePasswordManagerClient::GetGenerationManagerFromWebContents( - web_contents_); - if (manager) - manager->DetectAccountCreationForms(forms); + password_manager::ContentPasswordManagerDriver::GetForRenderFrameHost(rfh) + ->GetPasswordGenerationManager() + ->DetectAccountCreationForms(forms); } void ChromeAutofillClient::DidFillOrPreviewField( @@ -222,4 +222,9 @@ #endif // defined(OS_ANDROID) } +void ChromeAutofillClient::OnFirstUserGestureObserved() { + web_contents()->SendToAllFrames( + new AutofillMsg_FirstUserGestureObservedInTab(routing_id())); +} + } // namespace autofill
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.h b/chrome/browser/ui/autofill/chrome_autofill_client.h index 09d346a8..772119c2 100644 --- a/chrome/browser/ui/autofill/chrome_autofill_client.h +++ b/chrome/browser/ui/autofill/chrome_autofill_client.h
@@ -67,9 +67,11 @@ void HideAutofillPopup() override; bool IsAutocompleteEnabled() override; void DetectAccountCreationForms( + content::RenderFrameHost* rfh, const std::vector<autofill::FormStructure*>& forms) override; void DidFillOrPreviewField(const base::string16& autofilled_value, const base::string16& profile_full_name) override; + void OnFirstUserGestureObserved() override; // content::WebContentsObserver implementation. void WebContentsDestroyed() override;
diff --git a/chrome/browser/ui/autofill/password_generation_popup_controller_impl.cc b/chrome/browser/ui/autofill/password_generation_popup_controller_impl.cc index 05f7f98..7c55fab 100644 --- a/chrome/browser/ui/autofill/password_generation_popup_controller_impl.cc +++ b/chrome/browser/ui/autofill/password_generation_popup_controller_impl.cc
@@ -44,6 +44,7 @@ const PasswordForm& form, int max_length, password_manager::PasswordManager* password_manager, + password_manager::PasswordManagerDriver* driver, PasswordGenerationPopupObserver* observer, content::WebContents* web_contents, gfx::NativeView container_view) { @@ -59,13 +60,8 @@ PasswordGenerationPopupControllerImpl* controller = new PasswordGenerationPopupControllerImpl( - bounds, - form, - max_length, - password_manager, - observer, - web_contents, - container_view); + bounds, form, max_length, password_manager, driver, observer, + web_contents, container_view); return controller->GetWeakPtr(); } @@ -74,12 +70,14 @@ const PasswordForm& form, int max_length, password_manager::PasswordManager* password_manager, + password_manager::PasswordManagerDriver* driver, PasswordGenerationPopupObserver* observer, content::WebContents* web_contents, gfx::NativeView container_view) : view_(NULL), form_(form), password_manager_(password_manager), + driver_(driver), observer_(observer), generator_(new PasswordGenerator(max_length)), controller_common_(bounds, container_view, web_contents), @@ -155,7 +153,7 @@ new AutofillMsg_GeneratedPasswordAccepted( web_contents()->GetRenderViewHost()->GetRoutingID(), current_password_)); - password_manager_->SetFormHasGeneratedPassword(form_); + password_manager_->SetFormHasGeneratedPassword(driver_, form_); Hide(); }
diff --git a/chrome/browser/ui/autofill/password_generation_popup_controller_impl.h b/chrome/browser/ui/autofill/password_generation_popup_controller_impl.h index 238d362..d56b9dd 100644 --- a/chrome/browser/ui/autofill/password_generation_popup_controller_impl.h +++ b/chrome/browser/ui/autofill/password_generation_popup_controller_impl.h
@@ -24,6 +24,7 @@ namespace password_manager { class PasswordManager; +class PasswordManagerDriver; } namespace autofill { @@ -52,6 +53,7 @@ const PasswordForm& form, int max_length, password_manager::PasswordManager* password_manager, + password_manager::PasswordManagerDriver* driver, PasswordGenerationPopupObserver* observer, content::WebContents* web_contents, gfx::NativeView container_view); @@ -77,6 +79,7 @@ const PasswordForm& form, int max_length, password_manager::PasswordManager* password_manager, + password_manager::PasswordManagerDriver* driver, PasswordGenerationPopupObserver* observer, content::WebContents* web_contents, gfx::NativeView container_view); @@ -121,6 +124,7 @@ PasswordForm form_; password_manager::PasswordManager* password_manager_; + password_manager::PasswordManagerDriver* driver_; // May be NULL. PasswordGenerationPopupObserver* observer_;
diff --git a/chrome/browser/ui/autofill/password_generation_popup_view_browsertest.cc b/chrome/browser/ui/autofill/password_generation_popup_view_browsertest.cc index 67bcc37..7789f67 100644 --- a/chrome/browser/ui/autofill/password_generation_popup_view_browsertest.cc +++ b/chrome/browser/ui/autofill/password_generation_popup_view_browsertest.cc
@@ -25,8 +25,9 @@ gfx::RectF(0, 0, 10, 10), PasswordForm(), 10, - NULL /* PasswordManager*/, - NULL /* PasswordGenerationPopupObserver*/, + nullptr /* PasswordManager*/, + nullptr /* PasswordManagerDriver*/, + nullptr /* PasswordGenerationPopupObserver*/, web_contents, native_view) {}
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc index 5c981d1..3f08285 100644 --- a/chrome/browser/ui/browser.cc +++ b/chrome/browser/ui/browser.cc
@@ -568,8 +568,8 @@ // |contents| can be NULL because GetWindowTitleForCurrentTab is called by the // window during the window's creation (before tabs have been added). if (contents) { - // Streamlined hosted apps use the host instead of the title. - if (is_app() && extensions::util::IsStreamlinedHostedAppsEnabled()) + // The web app frame uses the host instead of the title. + if (ShouldUseWebAppFrame()) return base::UTF8ToUTF16(contents->GetURL().host()); title = contents->GetTitle(); @@ -2354,6 +2354,23 @@ return !is_trusted_source(); } +bool Browser::ShouldUseWebAppFrame() const { + // Only use the web app frame for apps in ash, and only if streamlined hosted + // apps are enabled. + if (!is_app() || host_desktop_type() != chrome::HOST_DESKTOP_TYPE_ASH || + !extensions::util::IsStreamlinedHostedAppsEnabled()) { + return false; + } + + // Use the web app frame for hosted apps (which include bookmark apps). + const std::string extension_id = + web_app::GetExtensionIdFromApplicationName(app_name()); + const extensions::Extension* extension = + extensions::ExtensionRegistry::Get(profile_)->GetExtensionById( + extension_id, extensions::ExtensionRegistry::EVERYTHING); + return extension && extension->is_hosted_app(); +} + bool Browser::SupportsWindowFeatureImpl(WindowFeature feature, bool check_fullscreen) const { bool hide_ui_for_fullscreen = check_fullscreen && ShouldHideUIForFullscreen(); @@ -2375,6 +2392,9 @@ if (ShouldShowLocationBar()) features |= FEATURE_LOCATIONBAR; + + if (ShouldUseWebAppFrame()) + features |= FEATURE_WEBAPPFRAME; } return !!(features & feature); }
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h index d71fb796..b2b9999 100644 --- a/chrome/browser/ui/browser.h +++ b/chrome/browser/ui/browser.h
@@ -135,7 +135,8 @@ FEATURE_LOCATIONBAR = 8, FEATURE_BOOKMARKBAR = 16, FEATURE_INFOBAR = 32, - FEATURE_DOWNLOADSHELF = 64 + FEATURE_DOWNLOADSHELF = 64, + FEATURE_WEBAPPFRAME = 128 }; // The context for a download blocked notification from @@ -794,6 +795,9 @@ // Returns true if the Browser window should show the location bar. bool ShouldShowLocationBar() const; + // Returns true if the Browser window should use a web app style frame. + bool ShouldUseWebAppFrame() const; + // Implementation of SupportsWindowFeature and CanSupportWindowFeature. If // |check_fullscreen| is true, the set of features reflect the actual state of // the browser, otherwise the set of features reflect the possible state of
diff --git a/chrome/browser/ui/browser_browsertest.cc b/chrome/browser/ui/browser_browsertest.cc index c7e91e18..9e2905e 100644 --- a/chrome/browser/ui/browser_browsertest.cc +++ b/chrome/browser/ui/browser_browsertest.cc
@@ -40,6 +40,7 @@ #include "chrome/browser/ui/browser_tabstrip.h" #include "chrome/browser/ui/browser_ui_prefs.h" #include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/extensions/app_launch_params.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/browser/ui/host_desktop.h" #include "chrome/browser/ui/startup/startup_browser_creator.h" @@ -84,6 +85,7 @@ #include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_system.h" #include "extensions/browser/uninstall_reason.h" +#include "extensions/common/constants.h" #include "extensions/common/extension.h" #include "extensions/common/extension_set.h" #include "net/dns/mock_host_resolver.h" @@ -1342,11 +1344,9 @@ const Extension* extension_app = GetExtension(); // Launch it in a window, as AppLauncherHandler::HandleLaunchApp() would. - WebContents* app_window = - OpenApplication(AppLaunchParams(browser()->profile(), - extension_app, - extensions::LAUNCH_CONTAINER_WINDOW, - NEW_WINDOW)); + WebContents* app_window = OpenApplication(AppLaunchParams( + browser()->profile(), extension_app, extensions::LAUNCH_CONTAINER_WINDOW, + NEW_WINDOW, extensions::SOURCE_UNTRACKED)); ASSERT_TRUE(app_window); DevToolsWindow* devtools_window = @@ -1382,6 +1382,86 @@ } #endif +// Open a normal browser window, a hosted app window, a legacy packaged app +// window and a dev tools window, and check that the web app frame feature is +// supported correctly. +IN_PROC_BROWSER_TEST_F(BrowserTest, ShouldUseWebAppFrame) { + base::CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kEnableStreamlinedHostedApps); + + ASSERT_TRUE(test_server()->Start()); + + // Load a hosted app. + host_resolver()->AddRule("www.example.com", "127.0.0.1"); + ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app/"))); + const Extension* hosted_app = GetExtension(); + + // Launch it in a window, as AppLauncherHandler::HandleLaunchApp() would. + WebContents* hosted_app_window = OpenApplication(AppLaunchParams( + browser()->profile(), hosted_app, extensions::LAUNCH_CONTAINER_WINDOW, + NEW_WINDOW, extensions::SOURCE_UNTRACKED)); + ASSERT_TRUE(hosted_app_window); + + // Load a packaged app. + ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("packaged_app/"))); + const Extension* packaged_app = nullptr; + extensions::ExtensionRegistry* registry = + extensions::ExtensionRegistry::Get(browser()->profile()); + for (const scoped_refptr<const extensions::Extension>& extension : + registry->enabled_extensions()) { + if (extension->name() == "Packaged App Test") + packaged_app = extension.get(); + } + ASSERT_TRUE(packaged_app); + + // Launch it in a window, as AppLauncherHandler::HandleLaunchApp() would. + WebContents* packaged_app_window = OpenApplication(AppLaunchParams( + browser()->profile(), packaged_app, extensions::LAUNCH_CONTAINER_WINDOW, + NEW_WINDOW, extensions::SOURCE_UNTRACKED)); + ASSERT_TRUE(packaged_app_window); + + DevToolsWindow* devtools_window = + DevToolsWindowTesting::OpenDevToolsWindowSync(browser(), false); + + // The launch should have created a new app browser and a dev tools browser. + ASSERT_EQ(4u, chrome::GetBrowserCount(browser()->profile(), + browser()->host_desktop_type())); + + // Find the new browsers. + Browser* hosted_app_browser = NULL; + Browser* packaged_app_browser = NULL; + Browser* dev_tools_browser = NULL; + for (chrome::BrowserIterator it; !it.done(); it.Next()) { + if (*it == browser()) { + continue; + } else if ((*it)->app_name() == DevToolsWindow::kDevToolsApp) { + dev_tools_browser = *it; + } else if ((*it)->tab_strip_model()->GetActiveWebContents() == + hosted_app_window) { + hosted_app_browser = *it; + } else { + packaged_app_browser = *it; + } + } + ASSERT_TRUE(dev_tools_browser); + ASSERT_TRUE(hosted_app_browser); + ASSERT_TRUE(hosted_app_browser != browser()); + ASSERT_TRUE(packaged_app_browser); + ASSERT_TRUE(packaged_app_browser != browser()); + ASSERT_TRUE(packaged_app_browser != hosted_app_browser); + + EXPECT_FALSE(browser()->SupportsWindowFeature(Browser::FEATURE_WEBAPPFRAME)); + EXPECT_FALSE( + dev_tools_browser->SupportsWindowFeature(Browser::FEATURE_WEBAPPFRAME)); + EXPECT_EQ( + browser()->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH, + hosted_app_browser->SupportsWindowFeature(Browser::FEATURE_WEBAPPFRAME)); + EXPECT_FALSE(packaged_app_browser->SupportsWindowFeature( + Browser::FEATURE_WEBAPPFRAME)); + + DevToolsWindowTesting::CloseDevToolsWindowSync(devtools_window); +} + // Tests that the CLD (Compact Language Detection) works properly. IN_PROC_BROWSER_TEST_F(BrowserTest, PageLanguageDetection) { scoped_ptr<test::CldDataHarness> cld_data_harness = @@ -1536,9 +1616,9 @@ const Extension* extension_app = GetExtension(); // Launch it in a window, as AppLauncherHandler::HandleLaunchApp() would. - WebContents* app_window = OpenApplication( - AppLaunchParams(browser()->profile(), extension_app, - extensions::LAUNCH_CONTAINER_WINDOW, NEW_WINDOW)); + WebContents* app_window = OpenApplication(AppLaunchParams( + browser()->profile(), extension_app, extensions::LAUNCH_CONTAINER_WINDOW, + NEW_WINDOW, extensions::SOURCE_UNTRACKED)); ASSERT_TRUE(app_window); // Apps launched in a window from the NTP have an extensions tab helper but
diff --git a/chrome/browser/ui/browser_command_controller.cc b/chrome/browser/ui/browser_command_controller.cc index ee2f25c..a49e338 100644 --- a/chrome/browser/ui/browser_command_controller.cc +++ b/chrome/browser/ui/browser_command_controller.cc
@@ -1111,9 +1111,9 @@ command_updater_.UpdateCommandEnabled( IDC_CREATE_SHORTCUTS, CanCreateApplicationShortcuts(browser_)); +#endif command_updater_.UpdateCommandEnabled(IDC_CREATE_HOSTED_APP, CanCreateBookmarkApp(browser_)); -#endif command_updater_.UpdateCommandEnabled( IDC_TOGGLE_REQUEST_TABLET_SITE,
diff --git a/chrome/browser/ui/chrome_pages.cc b/chrome/browser/ui/chrome_pages.cc index f0b002e..ccfbac4 100644 --- a/chrome/browser/ui/chrome_pages.cc +++ b/chrome/browser/ui/chrome_pages.cc
@@ -15,6 +15,7 @@ #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_navigator.h" #include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/extensions/app_launch_params.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h" #include "chrome/browser/ui/settings_window_manager.h" @@ -25,8 +26,10 @@ #include "chrome/common/url_constants.h" #include "content/public/browser/user_metrics.h" #include "content/public/browser/web_contents.h" +#include "extensions/common/constants.h" #include "google_apis/gaia/gaia_urls.h" #include "net/base/url_util.h" +#include "ui/base/window_open_disposition.h" #if defined(OS_WIN) #include "chrome/browser/enumerate_modules_model_win.h" @@ -82,18 +85,22 @@ extensions::ExtensionRegistry::Get(profile)->GetExtensionById( genius_app::kGeniusAppId, extensions::ExtensionRegistry::EVERYTHING); - AppLaunchParams params(profile, extension, 0, host_desktop_type); + extensions::AppLaunchSource app_launch_source(extensions::SOURCE_UNTRACKED); switch (source) { case HELP_SOURCE_KEYBOARD: - params.source = extensions::SOURCE_KEYBOARD; + app_launch_source = extensions::SOURCE_KEYBOARD; break; case HELP_SOURCE_MENU: - params.source = extensions::SOURCE_SYSTEM_TRAY; + app_launch_source = extensions::SOURCE_SYSTEM_TRAY; break; case HELP_SOURCE_WEBUI: - params.source = extensions::SOURCE_ABOUT_PAGE; + app_launch_source = extensions::SOURCE_ABOUT_PAGE; break; + default: + NOTREACHED() << "Unhandled help source" << source; } + AppLaunchParams params(profile, extension, CURRENT_TAB, host_desktop_type, + app_launch_source); OpenApplication(params); #else GURL url;
diff --git a/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.h b/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.h index 018f05f..15119eb 100644 --- a/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.h +++ b/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.h
@@ -137,6 +137,7 @@ SkColor InactiveFrameColor() const override; gfx::Insets GetFrameInsets() const override; bool CanHaveAlphaEnabled() const override; + virtual void SetInterceptAllKeys(bool want_all_keys) override; // These are used to simulate Mac-style hide/show. Since windows can be hidden // and shown using the app.window API, this sets is_hidden_with_app_ to
diff --git a/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.mm b/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.mm index 832b53f..cd978fb 100644 --- a/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.mm +++ b/chrome/browser/ui/cocoa/apps/native_app_window_cocoa.mm
@@ -982,6 +982,11 @@ SetWorkspacesCollectionBehavior(window(), always_visible); } +void NativeAppWindowCocoa::SetInterceptAllKeys(bool want_all_key) { + // TODO(sriramsr): implement for OSX (http://crbug.com/166928). + NOTIMPLEMENTED(); +} + NativeAppWindowCocoa::~NativeAppWindowCocoa() { }
diff --git a/chrome/browser/ui/cocoa/apps/native_app_window_cocoa_browsertest.mm b/chrome/browser/ui/cocoa/apps/native_app_window_cocoa_browsertest.mm index cc88c56..6d6be232 100644 --- a/chrome/browser/ui/cocoa/apps/native_app_window_cocoa_browsertest.mm +++ b/chrome/browser/ui/cocoa/apps/native_app_window_cocoa_browsertest.mm
@@ -10,10 +10,12 @@ #include "base/mac/sdk_forward_declarations.h" #include "chrome/browser/apps/app_browsertest_util.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/extensions/app_launch_params.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "content/public/browser/notification_service.h" #include "content/public/test/test_utils.h" #include "extensions/browser/app_window/app_window_registry.h" +#include "extensions/common/constants.h" using extensions::PlatformAppBrowserTest; @@ -33,10 +35,8 @@ content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME, content::NotificationService::AllSources()); OpenApplication( - AppLaunchParams(profile(), - app_, - extensions::LAUNCH_CONTAINER_NONE, - NEW_WINDOW)); + AppLaunchParams(profile(), app_, extensions::LAUNCH_CONTAINER_NONE, + NEW_WINDOW, extensions::SOURCE_UNTRACKED)); app_loaded_observer.Wait(); } }
diff --git a/chrome/browser/ui/cocoa/extensions/browser_action_test_util_mac.mm b/chrome/browser/ui/cocoa/extensions/browser_action_test_util_mac.mm index 0c1ec7fb..294a5348 100644 --- a/chrome/browser/ui/cocoa/extensions/browser_action_test_util_mac.mm +++ b/chrome/browser/ui/cocoa/extensions/browser_action_test_util_mac.mm
@@ -22,30 +22,37 @@ namespace { -BrowserActionsController* GetController(Browser* browser) { +BrowserActionsController* GetController( + Browser* browser, + ToolbarActionsBarDelegate* barDelegate) { + if (barDelegate) + return [BrowserActionsController fromToolbarActionsBarDelegate:barDelegate]; + BrowserWindowCocoa* window = static_cast<BrowserWindowCocoa*>(browser->window()); - return [[window->cocoa_controller() toolbarController] browserActionsController]; } -BrowserActionButton* GetButton(Browser* browser, int index) { - return [GetController(browser) buttonWithIndex:index]; +BrowserActionButton* GetButton( + Browser* browser, + ToolbarActionsBarDelegate* barDelegate, + int index) { + return [GetController(browser, barDelegate) buttonWithIndex:index]; } } // namespace int BrowserActionTestUtil::NumberOfBrowserActions() { - return [GetController(browser_) buttonCount]; + return [GetController(browser_, bar_delegate_) buttonCount]; } int BrowserActionTestUtil::VisibleBrowserActions() { - return [GetController(browser_) visibleButtonCount]; + return [GetController(browser_, bar_delegate_) visibleButtonCount]; } bool BrowserActionTestUtil::IsChevronShowing() { - BrowserActionsController* controller = GetController(browser_); + BrowserActionsController* controller = GetController(browser_, bar_delegate_); // The magic "18" comes from kChevronWidth in browser_actions_controller.mm. return ![controller chevronIsHidden] && NSWidth([[controller containerView] animationEndFrame]) >= 18; @@ -56,11 +63,11 @@ } bool BrowserActionTestUtil::HasIcon(int index) { - return [GetButton(browser_, index) image] != nil; + return [GetButton(browser_, bar_delegate_, index) image] != nil; } gfx::Image BrowserActionTestUtil::GetIcon(int index) { - NSImage* ns_image = [GetButton(browser_, index) image]; + NSImage* ns_image = [GetButton(browser_, bar_delegate_, index) image]; // gfx::Image takes ownership of the |ns_image| reference. We have to increase // the ref count so |ns_image| stays around when the image object is // destroyed. @@ -69,16 +76,16 @@ } void BrowserActionTestUtil::Press(int index) { - NSButton* button = GetButton(browser_, index); + NSButton* button = GetButton(browser_, bar_delegate_, index); [button performClick:nil]; } std::string BrowserActionTestUtil::GetExtensionId(int index) { - return [GetButton(browser_, index) viewController]->GetId(); + return [GetButton(browser_, bar_delegate_, index) viewController]->GetId(); } std::string BrowserActionTestUtil::GetTooltip(int index) { - NSString* tooltip = [GetButton(browser_, index) toolTip]; + NSString* tooltip = [GetButton(browser_, bar_delegate_, index) toolTip]; return base::SysNSStringToUTF8(tooltip); }
diff --git a/chrome/browser/ui/cocoa/extensions/browser_actions_controller.h b/chrome/browser/ui/cocoa/extensions/browser_actions_controller.h index 1b42f02..6f2b0477 100644 --- a/chrome/browser/ui/cocoa/extensions/browser_actions_controller.h +++ b/chrome/browser/ui/cocoa/extensions/browser_actions_controller.h
@@ -97,6 +97,9 @@ @interface BrowserActionsController(TestingAPI) - (BrowserActionButton*)buttonWithIndex:(NSUInteger)index; +- (ToolbarActionsBar*)toolbarActionsBar; ++ (BrowserActionsController*)fromToolbarActionsBarDelegate: + (ToolbarActionsBarDelegate*)delegate; @end #endif // CHROME_BROWSER_UI_COCOA_EXTENSIONS_BROWSER_ACTIONS_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm b/chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm index a71d2ce..3673ce33 100644 --- a/chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm +++ b/chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm
@@ -137,6 +137,8 @@ explicit ToolbarActionsBarBridge(BrowserActionsController* controller); ~ToolbarActionsBarBridge() override; + BrowserActionsController* controller_for_test() { return controller_; } + private: // ToolbarActionsBarDelegate: void AddViewForAction(ToolbarActionViewController* action, @@ -329,7 +331,13 @@ DCHECK([referenceButton isFlipped]); NSPoint anchor = NSMakePoint(NSMidX(bounds), NSMaxY(bounds) - kBrowserActionBubbleYOffset); - return [referenceButton convertPoint:anchor toView:nil]; + // Convert the point to the container view's frame, and adjust for animation. + NSPoint anchorInContainer = + [containerView_ convertPoint:anchor fromView:referenceButton]; + anchorInContainer.x -= NSMinX([containerView_ frame]) - + NSMinX([containerView_ animationEndFrame]); + + return [containerView_ convertPoint:anchorInContainer toView:nil]; } - (BOOL)chevronIsHidden { @@ -695,4 +703,13 @@ return index < [buttons_ count] ? [buttons_ objectAtIndex:index] : nil; } +- (ToolbarActionsBar*)toolbarActionsBar { + return toolbarActionsBar_.get(); +} + ++ (BrowserActionsController*)fromToolbarActionsBarDelegate: + (ToolbarActionsBarDelegate*)delegate { + return static_cast<ToolbarActionsBarBridge*>(delegate)->controller_for_test(); +} + @end
diff --git a/chrome/browser/ui/cocoa/extensions/test_toolbar_actions_bar_helper_cocoa.mm b/chrome/browser/ui/cocoa/extensions/test_toolbar_actions_bar_helper_cocoa.mm new file mode 100644 index 0000000..ad448de --- /dev/null +++ b/chrome/browser/ui/cocoa/extensions/test_toolbar_actions_bar_helper_cocoa.mm
@@ -0,0 +1,57 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/toolbar/test_toolbar_actions_bar_helper.h" + +#import "base/mac/scoped_nsobject.h" +#import "chrome/browser/ui/cocoa/extensions/browser_actions_container_view.h" +#import "chrome/browser/ui/cocoa/extensions/browser_actions_controller.h" +#import "chrome/browser/ui/cocoa/cocoa_test_helper.h" + +namespace { + +// The cocoa implementation of the TestToolbarActionsBarHelper, which creates +// (and owns) a BrowserActionsController and BrowserActionsContainerView for +// testing purposes. +class TestToolbarActionsBarHelperCocoa : public TestToolbarActionsBarHelper { + public: + TestToolbarActionsBarHelperCocoa(Browser* browser); + ~TestToolbarActionsBarHelperCocoa() override; + + private: + // TestToolbarActionsBarHelper: + ToolbarActionsBar* GetToolbarActionsBar() override; + + // The owned BrowserActionsContainerView and BrowserActionsController; the + // mac implementation of the ToolbarActionsBar delegate and view. + base::scoped_nsobject<BrowserActionsContainerView> containerView_; + base::scoped_nsobject<BrowserActionsController> controller_; + + DISALLOW_COPY_AND_ASSIGN(TestToolbarActionsBarHelperCocoa); +}; + +TestToolbarActionsBarHelperCocoa::TestToolbarActionsBarHelperCocoa( + Browser* browser) { + // Make sure that Cocoa has been bootstrapped. + CocoaTest::BootstrapCocoa(); + + containerView_.reset([[BrowserActionsContainerView alloc] + initWithFrame:NSMakeRect(0, 0, 0, 15)]); + controller_.reset([[BrowserActionsController alloc] + initWithBrowser:browser + containerView:containerView_.get()]); +} + +TestToolbarActionsBarHelperCocoa::~TestToolbarActionsBarHelperCocoa() {} + +ToolbarActionsBar* TestToolbarActionsBarHelperCocoa::GetToolbarActionsBar() { + return [controller_ toolbarActionsBar]; +} + +} // namespace + +scoped_ptr<TestToolbarActionsBarHelper> TestToolbarActionsBarHelper::Create( + Browser* browser) { + return make_scoped_ptr(new TestToolbarActionsBarHelperCocoa(browser)); +}
diff --git a/chrome/browser/ui/cocoa/task_manager_mac.mm b/chrome/browser/ui/cocoa/task_manager_mac.mm index c5b7f01..9fba1b676 100644 --- a/chrome/browser/ui/cocoa/task_manager_mac.mm +++ b/chrome/browser/ui/cocoa/task_manager_mac.mm
@@ -515,8 +515,8 @@ // TaskManagerMac, public: void TaskManagerMac::WindowWasClosed() { - instance_ = NULL; delete this; + instance_ = NULL; // |instance_| is static } int TaskManagerMac::RowCount() const {
diff --git a/chrome/browser/ui/cocoa/wrench_menu/wrench_menu_controller.mm b/chrome/browser/ui/cocoa/wrench_menu/wrench_menu_controller.mm index a713125..dd4cea8 100644 --- a/chrome/browser/ui/cocoa/wrench_menu/wrench_menu_controller.mm +++ b/chrome/browser/ui/cocoa/wrench_menu/wrench_menu_controller.mm
@@ -24,6 +24,7 @@ #import "chrome/browser/ui/cocoa/wrench_menu/recent_tabs_menu_model_delegate.h" #include "chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.h" #include "chrome/browser/ui/toolbar/wrench_menu_model.h" +#include "chrome/browser/ui/zoom/zoom_event_manager.h" #include "chrome/grit/generated_resources.h" #include "content/public/browser/user_metrics.h" #include "ui/base/l10n/l10n_util.h" @@ -34,7 +35,6 @@ } using base::UserMetricsAction; -using content::HostZoomMap; @interface WrenchMenuController (Private) - (void)createModel; @@ -68,10 +68,9 @@ class ZoomLevelObserver { public: ZoomLevelObserver(WrenchMenuController* controller, - content::HostZoomMap* map) - : controller_(controller), - map_(map) { - subscription_ = map_->AddZoomLevelChangedCallback( + ZoomEventManager* manager) + : controller_(controller) { + subscription_ = manager->AddZoomLevelChangedCallback( base::Bind(&ZoomLevelObserver::OnZoomLevelChanged, base::Unretained(this))); } @@ -79,7 +78,7 @@ ~ZoomLevelObserver() {} private: - void OnZoomLevelChanged(const HostZoomMap::ZoomLevelChange& change) { + void OnZoomLevelChanged(const content::HostZoomMap::ZoomLevelChange& change) { WrenchMenuModel* wrenchMenuModel = [controller_ wrenchMenuModel]; wrenchMenuModel->UpdateZoomControls(); const base::string16 level = @@ -90,7 +89,6 @@ scoped_ptr<content::HostZoomMap::Subscription> subscription_; WrenchMenuController* controller_; // Weak; owns this. - content::HostZoomMap* map_; // Weak. DISALLOW_COPY_AND_ASSIGN(ZoomLevelObserver); }; @@ -104,7 +102,7 @@ browser_ = browser; observer_.reset(new WrenchMenuControllerInternal::ZoomLevelObserver( self, - content::HostZoomMap::GetDefaultForBrowserContext(browser->profile()))); + ZoomEventManager::GetForBrowserContext(browser->profile()))); acceleratorDelegate_.reset( new WrenchMenuControllerInternal::AcceleratorDelegate()); [self createModel];
diff --git a/chrome/browser/ui/extensions/app_launch_params.cc b/chrome/browser/ui/extensions/app_launch_params.cc index fdb6a9f..883ce47 100644 --- a/chrome/browser/ui/extensions/app_launch_params.cc +++ b/chrome/browser/ui/extensions/app_launch_params.cc
@@ -7,14 +7,17 @@ #include "chrome/browser/extensions/launch_util.h" #include "chrome/browser/profiles/profile.h" #include "extensions/browser/extension_prefs.h" +#include "extensions/common/constants.h" #include "extensions/common/extension.h" +#include "ui/base/window_open_disposition.h" using extensions::ExtensionPrefs; AppLaunchParams::AppLaunchParams(Profile* profile, const extensions::Extension* extension, extensions::LaunchContainer container, - WindowOpenDisposition disposition) + WindowOpenDisposition disposition, + extensions::AppLaunchSource source) : profile(profile), extension_id(extension ? extension->id() : std::string()), container(container), @@ -23,12 +26,13 @@ override_url(), override_bounds(), command_line(CommandLine::NO_PROGRAM), - source(extensions::SOURCE_UNTRACKED) { + source(source) { } AppLaunchParams::AppLaunchParams(Profile* profile, const extensions::Extension* extension, - WindowOpenDisposition disposition) + WindowOpenDisposition disposition, + extensions::AppLaunchSource source) : profile(profile), extension_id(extension ? extension->id() : std::string()), container(extensions::LAUNCH_CONTAINER_NONE), @@ -37,7 +41,7 @@ override_url(), override_bounds(), command_line(CommandLine::NO_PROGRAM), - source(extensions::SOURCE_UNTRACKED) { + source(source) { // Look up the app preference to find out the right launch container. Default // is to launch as a regular tab. container = @@ -46,21 +50,24 @@ AppLaunchParams::AppLaunchParams(Profile* profile, const extensions::Extension* extension, - int event_flags, - chrome::HostDesktopType desktop_type) + WindowOpenDisposition raw_disposition, + chrome::HostDesktopType desktop_type, + extensions::AppLaunchSource source) : profile(profile), extension_id(extension ? extension->id() : std::string()), container(extensions::LAUNCH_CONTAINER_NONE), - disposition(ui::DispositionFromEventFlags(event_flags)), desktop_type(desktop_type), override_url(), override_bounds(), command_line(CommandLine::NO_PROGRAM), - source(extensions::SOURCE_UNTRACKED) { - if (disposition == NEW_FOREGROUND_TAB || disposition == NEW_BACKGROUND_TAB) { + source(source) { + if (raw_disposition == NEW_FOREGROUND_TAB || + raw_disposition == NEW_BACKGROUND_TAB) { container = extensions::LAUNCH_CONTAINER_TAB; - } else if (disposition == NEW_WINDOW) { + disposition = raw_disposition; + } else if (raw_disposition == NEW_WINDOW) { container = extensions::LAUNCH_CONTAINER_WINDOW; + disposition = raw_disposition; } else { // Look at preference to find the right launch container. If no preference // is set, launch as a regular tab.
diff --git a/chrome/browser/ui/extensions/app_launch_params.h b/chrome/browser/ui/extensions/app_launch_params.h index a65ed757..5b66cec 100644 --- a/chrome/browser/ui/extensions/app_launch_params.h +++ b/chrome/browser/ui/extensions/app_launch_params.h
@@ -26,13 +26,15 @@ AppLaunchParams(Profile* profile, const extensions::Extension* extension, extensions::LaunchContainer container, - WindowOpenDisposition disposition); + WindowOpenDisposition disposition, + extensions::AppLaunchSource source); // Helper to create AppLaunchParams using extensions::GetLaunchContainer with // LAUNCH_TYPE_REGULAR to check for a user-configured container. AppLaunchParams(Profile* profile, const extensions::Extension* extension, - WindowOpenDisposition disposition); + WindowOpenDisposition disposition, + extensions::AppLaunchSource source); // Helper to create AppLaunchParams using event flags that allows user to // override the user-configured container using modifier keys, falling back to @@ -40,8 +42,9 @@ // indicates the desktop upon which to launch (Ash or Native). AppLaunchParams(Profile* profile, const extensions::Extension* extension, - int event_flags, - chrome::HostDesktopType desktop_type); + WindowOpenDisposition disposition, + chrome::HostDesktopType desktop_type, + extensions::AppLaunchSource source); ~AppLaunchParams();
diff --git a/chrome/browser/ui/extensions/application_launch.cc b/chrome/browser/ui/extensions/application_launch.cc index af6d038..fb6799d 100644 --- a/chrome/browser/ui/extensions/application_launch.cc +++ b/chrome/browser/ui/extensions/application_launch.cc
@@ -24,6 +24,7 @@ #include "extensions/browser/extension_prefs.h" #include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_system.h" +#include "extensions/common/constants.h" #include "extensions/common/extension.h" #include "extensions/common/features/feature.h" #include "extensions/common/features/feature_provider.h" @@ -220,11 +221,10 @@ WebContents* OpenAppShortcutWindow(Profile* profile, const GURL& url) { - AppLaunchParams launch_params( - profile, - NULL, // this is a URL app. No extension. - extensions::LAUNCH_CONTAINER_WINDOW, - NEW_WINDOW); + AppLaunchParams launch_params(profile, + NULL, // this is a URL app. No extension. + extensions::LAUNCH_CONTAINER_WINDOW, NEW_WINDOW, + extensions::SOURCE_COMMAND_LINE); launch_params.override_url = url; WebContents* tab = OpenWebAppWindow(launch_params, url);
diff --git a/chrome/browser/ui/extensions/extension_action_view_controller.cc b/chrome/browser/ui/extensions/extension_action_view_controller.cc index 70ff4d4..2693fd15 100644 --- a/chrome/browser/ui/extensions/extension_action_view_controller.cc +++ b/chrome/browser/ui/extensions/extension_action_view_controller.cc
@@ -117,6 +117,12 @@ ExtensionWantsToRun(extension(), web_contents); } +bool ExtensionActionViewController::WantsToRun( + content::WebContents* web_contents) const { + return extensions::ExtensionActionAPI::Get(browser_->profile())-> + ExtensionWantsToRun(extension(), web_contents); +} + bool ExtensionActionViewController::HasPopup( content::WebContents* web_contents) const { if (!ExtensionIsValid())
diff --git a/chrome/browser/ui/extensions/extension_action_view_controller.h b/chrome/browser/ui/extensions/extension_action_view_controller.h index c0c2cd0e..c7eb2303 100644 --- a/chrome/browser/ui/extensions/extension_action_view_controller.h +++ b/chrome/browser/ui/extensions/extension_action_view_controller.h
@@ -49,6 +49,7 @@ override; base::string16 GetTooltip(content::WebContents* web_contents) const override; bool IsEnabled(content::WebContents* web_contents) const override; + bool WantsToRun(content::WebContents* web_contents) const override; bool HasPopup(content::WebContents* web_contents) const override; void HidePopup() override; gfx::NativeView GetPopupNativeView() override;
diff --git a/chrome/browser/ui/global_error/global_error.cc b/chrome/browser/ui/global_error/global_error.cc index 94083a2..10fa705 100644 --- a/chrome/browser/ui/global_error/global_error.cc +++ b/chrome/browser/ui/global_error/global_error.cc
@@ -63,6 +63,10 @@ IDR_INPUT_ALERT); } +bool GlobalErrorWithStandardBubble::ShouldAddElevationIconToAcceptButton() { + return false; +} + void GlobalErrorWithStandardBubble::BubbleViewDidClose(Browser* browser) { DCHECK(browser); bubble_view_ = NULL;
diff --git a/chrome/browser/ui/global_error/global_error.h b/chrome/browser/ui/global_error/global_error.h index d1f2fdd..2f9a55459 100644 --- a/chrome/browser/ui/global_error/global_error.h +++ b/chrome/browser/ui/global_error/global_error.h
@@ -42,7 +42,7 @@ // Returns the label for the menu item. virtual base::string16 MenuItemLabel() = 0; // Returns the resource ID for the menu item icon. - int MenuItemIconResourceID(); + virtual int MenuItemIconResourceID(); // Called when the user clicks on the menu item. virtual void ExecuteMenuItem(Browser* browser) = 0; @@ -77,6 +77,9 @@ virtual std::vector<base::string16> GetBubbleViewMessages() = 0; // Returns the accept button label for the bubble view. virtual base::string16 GetBubbleViewAcceptButtonLabel() = 0; + // Returns true if the accept button needs elevation icon (only effective + // on Windows platform). + virtual bool ShouldAddElevationIconToAcceptButton(); // Returns the cancel button label for the bubble view. To hide the cancel // button return an empty string. virtual base::string16 GetBubbleViewCancelButtonLabel() = 0;
diff --git a/chrome/browser/ui/login/login_prompt.cc b/chrome/browser/ui/login/login_prompt.cc index 99cc885..edc52f7 100644 --- a/chrome/browser/ui/login/login_prompt.cc +++ b/chrome/browser/ui/login/login_prompt.cc
@@ -17,6 +17,7 @@ #include "chrome/browser/tab_contents/tab_util.h" #include "chrome/browser/ui/login/login_interstitial_delegate.h" #include "chrome/grit/generated_resources.h" +#include "components/password_manager/content/browser/content_password_manager_driver.h" #include "components/password_manager/core/browser/browser_save_password_progress_logger.h" #include "components/password_manager/core/browser/password_manager.h" #include "content/public/browser/browser_thread.h" @@ -135,6 +136,14 @@ return WebContents::FromRenderFrameHost(rfh); } +password_manager::ContentPasswordManagerDriver* +LoginHandler::GetPasswordManagerDriverForLogin() { + content::RenderFrameHost* rfh = content::RenderFrameHost::FromID( + render_process_host_id_, render_frame_id_); + return password_manager::ContentPasswordManagerDriver::GetForRenderFrameHost( + rfh); +} + void LoginHandler::SetAuth(const base::string16& username, const base::string16& password) { DCHECK_CURRENTLY_ON(BrowserThread::UI); @@ -460,14 +469,17 @@ return; } - password_manager::PasswordManager* password_manager = - ChromePasswordManagerClient::GetManagerFromWebContents(parent_contents); - if (!password_manager) { + password_manager::ContentPasswordManagerDriver* driver = + handler->GetPasswordManagerDriverForLogin(); + + if (!driver) { // Same logic as above. handler->CancelAuth(); return; } + password_manager::PasswordManager* password_manager = + driver->GetPasswordManager(); if (password_manager && password_manager->client()->IsLoggingActive()) { password_manager::BrowserSavePasswordProgressLogger logger( password_manager->client()); @@ -478,8 +490,8 @@ // Tell the password manager to look for saved passwords. std::vector<PasswordForm> v; MakeInputForPasswordManager(request_url, auth_info, handler, &v); - password_manager->OnPasswordFormsParsed(v); - handler->SetPasswordManager(password_manager); + driver->OnPasswordFormsParsed(v); + handler->SetPasswordManager(driver->GetPasswordManager()); // The realm is controlled by the remote server, so there is no reason // to believe it is of a reasonable length. @@ -494,7 +506,8 @@ l10n_util::GetStringFUTF16(IDS_LOGIN_DIALOG_DESCRIPTION, host_and_port, elided_realm); - handler->BuildViewForPasswordManager(password_manager, explanation); + handler->BuildViewForPasswordManager(driver->GetPasswordManager(), + explanation); } // This callback is run on the UI thread and creates a constrained window with
diff --git a/chrome/browser/ui/login/login_prompt.h b/chrome/browser/ui/login/login_prompt.h index 8f55581d..9f58dcd 100644 --- a/chrome/browser/ui/login/login_prompt.h +++ b/chrome/browser/ui/login/login_prompt.h
@@ -27,6 +27,10 @@ class URLRequest; } // namespace net +namespace password_manager { +class ContentPasswordManagerDriver; +} // namespace password_manager + // This is the base implementation for the OS-specific classes that route // authentication info to the net::URLRequest that needs it. These functions // must be implemented in a thread safe manner. @@ -57,6 +61,10 @@ // Returns the WebContents that needs authentication. content::WebContents* GetWebContentsForLogin() const; + // Returns the PasswordManager for the render frame that needs login. + password_manager::ContentPasswordManagerDriver* + GetPasswordManagerDriverForLogin(); + // Resend the request with authentication credentials. // This function can be called from either thread. void SetAuth(const base::string16& username, const base::string16& password);
diff --git a/chrome/browser/ui/passwords/manage_passwords_bubble_model.cc b/chrome/browser/ui/passwords/manage_passwords_bubble_model.cc index 4c39768..d572f6e 100644 --- a/chrome/browser/ui/passwords/manage_passwords_bubble_model.cc +++ b/chrome/browser/ui/passwords/manage_passwords_bubble_model.cc
@@ -123,7 +123,7 @@ } void ManagePasswordsBubbleModel::OnBubbleHidden() { - if (password_manager::ui::IsCredentialsState(state_)) { + if (password_manager::ui::IsCredentialsState(state_) && web_contents()) { // It's time to run the pending callback if it wasn't called in // OnChooseCredentials(). ManagePasswordsUIController* manage_passwords_ui_controller =
diff --git a/chrome/browser/ui/search/instant_search_prerenderer_unittest.cc b/chrome/browser/ui/search/instant_search_prerenderer_unittest.cc index b708b85..3b263d6 100644 --- a/chrome/browser/ui/search/instant_search_prerenderer_unittest.cc +++ b/chrome/browser/ui/search/instant_search_prerenderer_unittest.cc
@@ -123,8 +123,7 @@ prerender_contents_.reset(content::WebContents::CreateWithSessionStorage( content::WebContents::CreateParams(profile_), session_storage_namespace_map_)); - PrerenderTabHelper::CreateForWebContentsWithPasswordManager( - prerender_contents_.get(), NULL); + PrerenderTabHelper::CreateForWebContents(prerender_contents_.get()); content::NavigationController::LoadURLParams params(url_); prerender_contents_->GetController().LoadURLWithParams(params); SearchTabHelper::CreateForWebContents(prerender_contents_.get());
diff --git a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc index 81ff4226..a2a9455 100644 --- a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc +++ b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
@@ -61,7 +61,7 @@ using testing::Return; #endif // defined(ENABLE_CONFIGURATION_POLICY) && !defined(OS_CHROMEOS) -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) #include "chrome/browser/supervised_user/supervised_user_navigation_observer.h" #include "chrome/browser/supervised_user/supervised_user_service.h" #include "chrome/browser/supervised_user/supervised_user_service_factory.h"
diff --git a/chrome/browser/ui/startup/startup_browser_creator_impl.cc b/chrome/browser/ui/startup/startup_browser_creator_impl.cc index 5924fe11..79e89d09 100644 --- a/chrome/browser/ui/startup/startup_browser_creator_impl.cc +++ b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
@@ -57,6 +57,7 @@ #include "chrome/browser/ui/browser_tabrestore.h" #include "chrome/browser/ui/browser_tabstrip.h" #include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/extensions/app_launch_params.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/browser/ui/host_desktop.h" #include "chrome/browser/ui/startup/autolaunch_prompt.h" @@ -336,7 +337,8 @@ if (extension) { RecordCmdLineAppHistogram(extensions::Manifest::TYPE_PLATFORM_APP); AppLaunchParams params(profile, extension, - extensions::LAUNCH_CONTAINER_NONE, NEW_WINDOW); + extensions::LAUNCH_CONTAINER_NONE, NEW_WINDOW, + extensions::SOURCE_COMMAND_LINE); params.command_line = command_line_; params.current_directory = cur_dir_; // If we are being launched from the command line, default to native @@ -424,9 +426,9 @@ RecordCmdLineAppHistogram(extension->GetType()); - WebContents* app_tab = OpenApplication(AppLaunchParams( - profile, extension, extensions::LAUNCH_CONTAINER_TAB, - NEW_FOREGROUND_TAB)); + WebContents* app_tab = OpenApplication( + AppLaunchParams(profile, extension, extensions::LAUNCH_CONTAINER_TAB, + NEW_FOREGROUND_TAB, extensions::SOURCE_COMMAND_LINE)); return (app_tab != NULL); } @@ -460,7 +462,8 @@ RecordCmdLineAppHistogram(extension->GetType()); - AppLaunchParams params(profile, extension, launch_container, NEW_WINDOW); + AppLaunchParams params(profile, extension, launch_container, NEW_WINDOW, + extensions::SOURCE_COMMAND_LINE); params.command_line = command_line_; params.current_directory = cur_dir_; WebContents* tab_in_app_window = OpenApplication(params);
diff --git a/chrome/browser/ui/sync/one_click_signin_helper.cc b/chrome/browser/ui/sync/one_click_signin_helper.cc index f1e9de93..4d80e2c 100644 --- a/chrome/browser/ui/sync/one_click_signin_helper.cc +++ b/chrome/browser/ui/sync/one_click_signin_helper.cc
@@ -29,6 +29,7 @@ #include "chrome/browser/defaults.h" #include "chrome/browser/history/history_service.h" #include "chrome/browser/history/history_service_factory.h" +#include "chrome/browser/password_manager/chrome_password_manager_client.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_info_cache.h" #include "chrome/browser/profiles/profile_io_data.h" @@ -672,9 +673,7 @@ // static const int OneClickSigninHelper::kMaxNavigationsSince = 10; -OneClickSigninHelper::OneClickSigninHelper( - content::WebContents* web_contents, - password_manager::PasswordManager* password_manager) +OneClickSigninHelper::OneClickSigninHelper(content::WebContents* web_contents) : content::WebContentsObserver(web_contents), showing_signin_(false), auto_accept_(AUTO_ACCEPT_NONE), @@ -685,9 +684,11 @@ do_not_clear_pending_email_(false), do_not_start_sync_for_testing_(false), weak_pointer_factory_(this) { + ChromePasswordManagerClient* client = + ChromePasswordManagerClient::FromWebContents(web_contents); // May be NULL during testing. - if (password_manager) { - password_manager->AddSubmissionCallback( + if (client) { + client->GetPasswordManager()->AddSubmissionCallback( base::Bind(&OneClickSigninHelper::PasswordSubmitted, weak_pointer_factory_.GetWeakPtr())); } @@ -759,16 +760,6 @@ } // static -void OneClickSigninHelper::CreateForWebContentsWithPasswordManager( - content::WebContents* contents, - password_manager::PasswordManager* password_manager) { - if (!FromWebContents(contents)) { - contents->SetUserData(UserDataKey(), - new OneClickSigninHelper(contents, password_manager)); - } -} - -// static bool OneClickSigninHelper::CanOffer(content::WebContents* web_contents, CanOfferFor can_offer_for, const std::string& email,
diff --git a/chrome/browser/ui/sync/one_click_signin_helper.h b/chrome/browser/ui/sync/one_click_signin_helper.h index c80816d..a007d7d 100644 --- a/chrome/browser/ui/sync/one_click_signin_helper.h +++ b/chrome/browser/ui/sync/one_click_signin_helper.h
@@ -171,10 +171,6 @@ static void LogHistogramValue(signin::Source source, int action); - static void CreateForWebContentsWithPasswordManager( - content::WebContents* contents, - password_manager::PasswordManager* password_manager); - // Returns true if the one-click signin feature can be offered at this time. // If |email| is not empty, then the profile is checked to see if it's // already connected to a google account or if the user has already rejected @@ -282,8 +278,7 @@ // SAML-based accounts, but causes bug crbug.com/181163. static const int kMaxNavigationsSince; - OneClickSigninHelper(content::WebContents* web_contents, - password_manager::PasswordManager* password_manager); + explicit OneClickSigninHelper(content::WebContents* web_contents); ~OneClickSigninHelper() override;
diff --git a/chrome/browser/ui/sync/one_click_signin_helper_unittest.cc b/chrome/browser/ui/sync/one_click_signin_helper_unittest.cc index b1ab8e8..886b2d1 100644 --- a/chrome/browser/ui/sync/one_click_signin_helper_unittest.cc +++ b/chrome/browser/ui/sync/one_click_signin_helper_unittest.cc
@@ -673,7 +673,7 @@ TEST_F(OneClickSigninHelperTest, CleanTransientStateOnNavigate) { content::WebContents* contents = web_contents(); - OneClickSigninHelper::CreateForWebContentsWithPasswordManager(contents, NULL); + OneClickSigninHelper::CreateForWebContents(contents); OneClickSigninHelper* helper = OneClickSigninHelper::FromWebContents(contents); helper->SetDoNotClearPendingEmailForTesting();
diff --git a/chrome/browser/ui/sync/tab_contents_synced_tab_delegate.cc b/chrome/browser/ui/sync/tab_contents_synced_tab_delegate.cc index f417daf..9ed9bb9 100644 --- a/chrome/browser/ui/sync/tab_contents_synced_tab_delegate.cc +++ b/chrome/browser/ui/sync/tab_contents_synced_tab_delegate.cc
@@ -17,7 +17,7 @@ #include "extensions/common/extension.h" #endif -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) #include "chrome/browser/supervised_user/supervised_user_navigation_observer.h" #endif @@ -87,7 +87,7 @@ const std::vector<const content::NavigationEntry*>* TabContentsSyncedTabDelegate::GetBlockedNavigations() const { -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) SupervisedUserNavigationObserver* navigation_observer = SupervisedUserNavigationObserver::FromWebContents(web_contents_); DCHECK(navigation_observer);
diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc index a5a6262..a3ebe138 100644 --- a/chrome/browser/ui/tab_helpers.cc +++ b/chrome/browser/ui/tab_helpers.cc
@@ -29,7 +29,7 @@ #include "chrome/browser/ui/search/search_tab_helper.h" #include "chrome/browser/ui/tab_contents/core_tab_helper.h" #include "chrome/common/chrome_switches.h" -#include "components/autofill/content/browser/content_autofill_driver.h" +#include "components/autofill/content/browser/content_autofill_driver_factory.h" #include "components/autofill/core/browser/autofill_manager.h" #include "components/dom_distiller/content/web_contents_main_frame_observer.h" #include "components/password_manager/core/browser/password_manager.h" @@ -72,7 +72,7 @@ #include "extensions/browser/view_type_utils.h" #endif -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) #include "chrome/browser/supervised_user/supervised_user_navigation_observer.h" #endif @@ -129,7 +129,7 @@ // --- Common tab helpers --- autofill::ChromeAutofillClient::CreateForWebContents(web_contents); - autofill::ContentAutofillDriver::CreateForWebContentsAndDelegate( + autofill::ContentAutofillDriverFactory::CreateForWebContentsAndDelegate( web_contents, autofill::ChromeAutofillClient::FromWebContents(web_contents), g_browser_process->GetApplicationLocale(), @@ -148,9 +148,7 @@ NavigationMetricsRecorder::CreateForWebContents(web_contents); PopupBlockerTabHelper::CreateForWebContents(web_contents); PrefsTabHelper::CreateForWebContents(web_contents); - prerender::PrerenderTabHelper::CreateForWebContentsWithPasswordManager( - web_contents, - ChromePasswordManagerClient::GetManagerFromWebContents(web_contents)); + prerender::PrerenderTabHelper::CreateForWebContents(web_contents); SearchTabHelper::CreateForWebContents(web_contents); // TODO(vabr): Remove TabSpecificContentSettings from here once their function // is taken over by ChromeContentSettingsClient. http://crbug.com/387075 @@ -200,7 +198,7 @@ extensions::TabHelper::CreateForWebContents(web_contents); #endif -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) SupervisedUserNavigationObserver::CreateForWebContents(web_contents); #endif @@ -230,9 +228,7 @@ OneClickSigninHelper::CAN_OFFER_FOR_ALL, std::string(), NULL)) { - OneClickSigninHelper::CreateForWebContentsWithPasswordManager( - web_contents, - ChromePasswordManagerClient::GetManagerFromWebContents(web_contents)); + OneClickSigninHelper::CreateForWebContents(web_contents); } #endif
diff --git a/chrome/browser/ui/toolbar/test_toolbar_actions_bar_helper.h b/chrome/browser/ui/toolbar/test_toolbar_actions_bar_helper.h new file mode 100644 index 0000000..91dee00 --- /dev/null +++ b/chrome/browser/ui/toolbar/test_toolbar_actions_bar_helper.h
@@ -0,0 +1,29 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_TOOLBAR_TEST_TOOLBAR_ACTIONS_BAR_HELPER_H_ +#define CHROME_BROWSER_UI_TOOLBAR_TEST_TOOLBAR_ACTIONS_BAR_HELPER_H_ + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" + +class Browser; +class ToolbarActionsBar; + +// A cross-platform container that creates and owns a ToolbarActionsBar and the +// corresponding view. +class TestToolbarActionsBarHelper { + public: + TestToolbarActionsBarHelper() {} + virtual ~TestToolbarActionsBarHelper() {} + + static scoped_ptr<TestToolbarActionsBarHelper> Create(Browser* browser); + + virtual ToolbarActionsBar* GetToolbarActionsBar() = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(TestToolbarActionsBarHelper); +}; + +#endif // CHROME_BROWSER_UI_TOOLBAR_TEST_TOOLBAR_ACTIONS_BAR_HELPER_H_
diff --git a/chrome/browser/ui/toolbar/toolbar_action_view_controller.h b/chrome/browser/ui/toolbar/toolbar_action_view_controller.h index 458c43b..de1dfc0 100644 --- a/chrome/browser/ui/toolbar/toolbar_action_view_controller.h +++ b/chrome/browser/ui/toolbar/toolbar_action_view_controller.h
@@ -54,6 +54,10 @@ // Returns true if the action should be enabled on the given |web_contents|. virtual bool IsEnabled(content::WebContents* web_contents) const = 0; + // Returns true if the action wants to run, and should be popped out of the + // overflow menu on the given |web_contents|. + virtual bool WantsToRun(content::WebContents* web_contents) const = 0; + // Returns true if the action has a popup for the given |web_contents|. virtual bool HasPopup(content::WebContents* web_contents) const = 0;
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_bar.cc b/chrome/browser/ui/toolbar/toolbar_actions_bar.cc index d6956d3..d933849 100644 --- a/chrome/browser/ui/toolbar/toolbar_actions_bar.cc +++ b/chrome/browser/ui/toolbar/toolbar_actions_bar.cc
@@ -7,6 +7,7 @@ #include "base/auto_reset.h" #include "chrome/browser/extensions/extension_action_manager.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/sessions/session_tab_helper.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/extensions/extension_action_view_controller.h" @@ -171,10 +172,7 @@ if (!model_) return 0u; - // Find the absolute value for the model's visible count. - size_t model_visible_size = model_->GetVisibleIconCountForTab( - browser_->tab_strip_model()->GetActiveWebContents()); - + size_t visible_icons = model_->visible_icon_count(); #if DCHECK_IS_ON // Good time for some sanity checks: We should never try to display more // icons than we have, and we should always have a view per item in the model. @@ -190,14 +188,23 @@ if (crx_file::id_util::IdIsValid(action->GetId())) ++num_extension_actions; } - DCHECK_LE(model_visible_size, num_extension_actions); + DCHECK_LE(visible_icons, num_extension_actions); DCHECK_EQ(model_->toolbar_items().size(), num_extension_actions); } #endif + int tab_id = SessionTabHelper::IdForTab( + browser_->tab_strip_model()->GetActiveWebContents()); + for (ToolbarActionViewController* action : toolbar_actions_) { + auto actions_tabs = popped_out_in_tabs_.find(action); + if (actions_tabs != popped_out_in_tabs_.end() && + actions_tabs->second.count(tab_id)) + ++visible_icons; + } + // The overflow displays any icons not shown by the main bar. return in_overflow_mode_ ? - model_->toolbar_items().size() - model_visible_size : model_visible_size; + model_->toolbar_items().size() - visible_icons : visible_icons; } void ToolbarActionsBar::CreateActions() { @@ -214,8 +221,7 @@ // Extension actions come first. extensions::ExtensionActionManager* action_manager = extensions::ExtensionActionManager::Get(browser_->profile()); - const extensions::ExtensionList& toolbar_items = model_->GetItemOrderForTab( - GetCurrentWebContents()); + const extensions::ExtensionList& toolbar_items = model_->toolbar_items(); for (const scoped_refptr<const extensions::Extension>& extension : toolbar_items) { toolbar_actions_.push_back(new ExtensionActionViewController( @@ -242,10 +248,8 @@ delegate_->AddViewForAction(toolbar_actions_[i], i); } - if (!toolbar_actions_.empty()) { - delegate_->Redraw(false); - ResizeDelegate(gfx::Tween::EASE_OUT, false); - } + if (!toolbar_actions_.empty()) + ReorderActions(); // Once the actions are created, we should animate the changes. suppress_animation_ = false; @@ -343,6 +347,7 @@ return; delegate_->RemoveViewForAction(*iter); + popped_out_in_tabs_.erase(*iter); toolbar_actions_.erase(iter); // If the extension is being upgraded we don't want the bar to shrink @@ -388,8 +393,27 @@ ToolbarActionViewController* action = GetActionForId(extension->id()); // There might not be a view in cases where we are highlighting or if we // haven't fully initialized the actions. - if (action) + if (action) { + content::WebContents* web_contents = GetCurrentWebContents(); action->UpdateState(); + bool wants_to_run = action->WantsToRun(web_contents); + + // The action may need to be popped in or out of overflow. + int index = std::find(toolbar_actions_.begin(), + toolbar_actions_.end(), + action) - toolbar_actions_.begin(); + bool reorder_necessary = false; + int tab_id = SessionTabHelper::IdForTab(web_contents); + if (wants_to_run && static_cast<size_t>(index) >= GetIconCount()) { + popped_out_in_tabs_[action].insert(tab_id); + reorder_necessary = true; + } else if (!wants_to_run && popped_out_in_tabs_[action].count(tab_id)) { + popped_out_in_tabs_[action].erase(tab_id); + reorder_necessary = true; + } + if (reorder_necessary) + ReorderActions(); + } } bool ToolbarActionsBar::ShowExtensionActionPopup( @@ -445,47 +469,43 @@ CreateActions(); } -void ToolbarActionsBar::OnToolbarReorderNecessary( - content::WebContents* web_contents) { - if (GetCurrentWebContents() == web_contents) - ReorderActions(); -} - Browser* ToolbarActionsBar::GetBrowser() { return browser_; } void ToolbarActionsBar::ReorderActions() { - extensions::ExtensionList new_order = - model_->GetItemOrderForTab(GetCurrentWebContents()); - if (new_order.empty()) - return; // Nothing to do. - -#if DCHECK_IS_ON - // Make sure the lists are in sync. There should be a view for each action in - // the new order. - // |toolbar_actions_| may have more views than actions are present in - // |new_order| if there are any component toolbar actions. - // TODO(devlin): Change this to DCHECK_EQ when all toolbar actions are shown - // in the model. - DCHECK_LE(new_order.size(), toolbar_actions_.size()); - for (const scoped_refptr<const extensions::Extension>& extension : new_order) - DCHECK(GetActionForId(extension->id())); -#endif - - // Run through the views and compare them to the desired order. If something - // is out of place, find the correct spot for it. - for (size_t i = 0; i < new_order.size() - 1; ++i) { - if (new_order[i]->id() != toolbar_actions_[i]->GetId()) { + // First, reset the order to that of the model. Run through the views and + // compare them to the model; if something is out of place, find the correct + // spot for it. + const extensions::ExtensionList& model_order = model_->toolbar_items(); + for (int i = 0; i < static_cast<int>(model_order.size() - 1); ++i) { + if (model_order[i]->id() != toolbar_actions_[i]->GetId()) { // Find where the correct view is (it's guaranteed to be after our current // index, since everything up to this point is correct). size_t j = i + 1; - while (new_order[i]->id() != toolbar_actions_[j]->GetId()) + while (model_order[i]->id() != toolbar_actions_[j]->GetId()) ++j; std::swap(toolbar_actions_[i], toolbar_actions_[j]); } } + // Only adjust the order if the model isn't highlighting a particular subset. + if (!model_->is_highlighting()) { + // Then, shift any actions that want to run to the front. + int tab_id = SessionTabHelper::IdForTab(GetCurrentWebContents()); + size_t insert_at = 0; + // Rotate any actions that want to run to the boundary between visible and + // overflowed actions. + for (ToolbarActions::iterator iter = + toolbar_actions_.begin() + model_->visible_icon_count(); + iter != toolbar_actions_.end(); ++iter) { + if (popped_out_in_tabs_[(*iter)].count(tab_id)) { + std::rotate(toolbar_actions_.begin() + insert_at, iter, iter + 1); + ++insert_at; + } + } + } + // Our visible browser actions may have changed - re-Layout() and check the // size. ResizeDelegate(gfx::Tween::EASE_OUT, false);
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_bar.h b/chrome/browser/ui/toolbar/toolbar_actions_bar.h index 00fc415..ba88fd4b 100644 --- a/chrome/browser/ui/toolbar/toolbar_actions_bar.h +++ b/chrome/browser/ui/toolbar/toolbar_actions_bar.h
@@ -123,6 +123,8 @@ return platform_settings_; } + ToolbarActionsBarDelegate* delegate_for_test() { return delegate_; } + private: using ToolbarActions = ScopedVector<ToolbarActionViewController>; @@ -138,7 +140,6 @@ void ToolbarVisibleCountChanged() override; void ToolbarHighlightModeChanged(bool is_highlighting) override; void OnToolbarModelInitialized() override; - void OnToolbarReorderNecessary(content::WebContents* web_contents) override; Browser* GetBrowser() override; // Resizes the delegate (if necessary) to the preferred size using the given @@ -172,6 +173,11 @@ // The toolbar actions. ToolbarActions toolbar_actions_; + // The set of tabs for the given action (the key) is currently "popped out". + // "Popped out" actions are those that were in the overflow menu normally, but + // want to run and are moved to the main bar so the user can see them. + std::map<ToolbarActionViewController*, std::set<int>> popped_out_in_tabs_; + ScopedObserver<extensions::ExtensionToolbarModel, extensions::ExtensionToolbarModel::Observer> model_observer_;
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_bar_unittest.cc b/chrome/browser/ui/toolbar/toolbar_actions_bar_unittest.cc new file mode 100644 index 0000000..1afffe40 --- /dev/null +++ b/chrome/browser/ui/toolbar/toolbar_actions_bar_unittest.cc
@@ -0,0 +1,498 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/toolbar/toolbar_actions_bar.h" + +#include "base/command_line.h" +#include "base/memory/scoped_ptr.h" +#include "base/run_loop.h" +#include "base/strings/stringprintf.h" +#include "base/strings/utf_string_conversions.h" +#include "chrome/browser/extensions/api/extension_action/extension_action_api.h" +#include "chrome/browser/extensions/browser_action_test_util.h" +#include "chrome/browser/extensions/extension_action.h" +#include "chrome/browser/extensions/extension_action_manager.h" +#include "chrome/browser/extensions/extension_action_test_util.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/extensions/test_extension_system.h" +#include "chrome/browser/sessions/session_tab_helper.h" +#include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "chrome/browser/ui/toolbar/test_toolbar_actions_bar_helper.h" +#include "chrome/browser/ui/toolbar/toolbar_action_view_controller.h" +#include "chrome/browser/ui/toolbar/toolbar_actions_bar_delegate.h" +#include "chrome/test/base/browser_with_test_window_test.h" +#include "extensions/browser/extension_system.h" +#include "extensions/common/extension.h" +#include "extensions/common/feature_switch.h" + +// A cross-platform unit test for the ToolbarActionsBar that uses the +// TestToolbarActionsBarHelper to create the platform-specific containers. +// TODO(devlin): Since this *does* use the real platform containers, in theory, +// we can move all the BrowserActionsBarBrowserTests to be unittests. See about +// doing this. +class ToolbarActionsBarUnitTest : public BrowserWithTestWindowTest { + public: + ToolbarActionsBarUnitTest() : toolbar_model_(nullptr) {} + ~ToolbarActionsBarUnitTest() override {} + + protected: + void SetUp() override; + void TearDown() override; + + // Activates the tab at the given |index| in the tab strip model. + void ActivateTab(int index); + + // Set whether or not the given |action| wants to run on the |web_contents|. + void SetActionWantsToRunOnTab(ExtensionAction* action, + content::WebContents* web_contents, + bool wants_to_run); + + // Creates an extension with the given |name| and |action_type|, adds it to + // the associated extension service, and returns the created extension. (It's + // safe to ignore the returned value.) + scoped_refptr<const extensions::Extension> CreateAndAddExtension( + const std::string& name, + extensions::extension_action_test_util::ActionType action_type); + + // Verifies that the toolbar is in order specified by |expected_names|, has + // the total action count of |total_size|, and has the same |visible_count|. + // This verifies that both the ToolbarActionsBar and the associated + // (platform-specific) view is correct. + // We use expected names (instead of ids) because they're much more readable + // in a debug message. These aren't enforced to be unique, so don't make + // duplicates. + // If any of these is wrong, returns testing::AssertionFailure() with a + // message. + testing::AssertionResult VerifyToolbarOrder( + const char* expected_names[], + size_t total_size, + size_t visible_count) WARN_UNUSED_RESULT; + + ToolbarActionsBar* toolbar_actions_bar() { + return toolbar_actions_bar_helper_->GetToolbarActionsBar(); + } + extensions::ExtensionToolbarModel* toolbar_model() { + return toolbar_model_; + } + BrowserActionTestUtil* browser_action_test_util() { + return browser_action_test_util_.get(); + } + + private: + // The test helper that owns the ToolbarActionsBar and the platform-specific + // view for it. + scoped_ptr<TestToolbarActionsBarHelper> toolbar_actions_bar_helper_; + + // The associated ExtensionToolbarModel (owned by the keyed service setup). + extensions::ExtensionToolbarModel* toolbar_model_; + + // A BrowserActionTestUtil object constructed with the associated + // ToolbarActionsBar. + scoped_ptr<BrowserActionTestUtil> browser_action_test_util_; + + DISALLOW_COPY_AND_ASSIGN(ToolbarActionsBarUnitTest); +}; + +void ToolbarActionsBarUnitTest::SetUp() { + BrowserWithTestWindowTest::SetUp(); + // The toolbar typically displays extension icons, so create some extension + // test infrastructure. + extensions::TestExtensionSystem* extension_system = + static_cast<extensions::TestExtensionSystem*>( + extensions::ExtensionSystem::Get(profile())); + extension_system->CreateExtensionService( + base::CommandLine::ForCurrentProcess(), + base::FilePath(), + false); + toolbar_model_ = + extensions::extension_action_test_util::CreateToolbarModelForProfile( + profile()); + + toolbar_actions_bar_helper_ = TestToolbarActionsBarHelper::Create(browser()); + + BrowserActionTestUtil::DisableAnimations(); + browser_action_test_util_.reset( + new BrowserActionTestUtil(browser(), + toolbar_actions_bar()->delegate_for_test())); +} + +void ToolbarActionsBarUnitTest::TearDown() { + // Since the profile gets destroyed in BrowserWithTestWindowTest::TearDown(), + // we need to delete this now. + toolbar_actions_bar_helper_.reset(); + BrowserWithTestWindowTest::TearDown(); +} + +void ToolbarActionsBarUnitTest::ActivateTab(int index) { + ASSERT_NE(nullptr, browser()->tab_strip_model()->GetWebContentsAt(index)); + browser()->tab_strip_model()->ActivateTabAt(index, true); + // Normally, the toolbar view would (indirectly) tell the toolbar actions + // bar to update itself on tab change. Since this is a unittest, we have tell + // it to. + toolbar_actions_bar()->Update(); +} + +scoped_refptr<const extensions::Extension> +ToolbarActionsBarUnitTest::CreateAndAddExtension( + const std::string& name, + extensions::extension_action_test_util::ActionType action_type) { + scoped_refptr<const extensions::Extension> extension = + extensions::extension_action_test_util::CreateActionExtension( + name, action_type); + extensions::ExtensionSystem::Get(profile())->extension_service()-> + AddExtension(extension.get()); + return extension; +} + +void ToolbarActionsBarUnitTest::SetActionWantsToRunOnTab( + ExtensionAction* action, + content::WebContents* web_contents, + bool wants_to_run) { + action->SetIsVisible(SessionTabHelper::IdForTab(web_contents), wants_to_run); + extensions::ExtensionActionAPI::Get(profile())->NotifyChange( + action, web_contents, profile()); +} + +testing::AssertionResult ToolbarActionsBarUnitTest::VerifyToolbarOrder( + const char* expected_names[], + size_t total_size, + size_t visible_count) { + std::vector<ToolbarActionViewController*> toolbar_actions = + toolbar_actions_bar()->toolbar_actions(); + // If the total size is wrong, we risk segfaulting by continuing. Abort now. + if (total_size != toolbar_actions.size()) { + return testing::AssertionFailure() << "Incorrect action count: expected " << + total_size << ", found " << toolbar_actions.size(); + } + + // Check that the ToolbarActionsBar matches the expected state. + std::string error; + for (size_t i = 0; i < total_size; ++i) { + if (std::string(expected_names[i]) != + base::UTF16ToUTF8(toolbar_actions[i]->GetActionName())) { + error += base::StringPrintf( + "Incorrect action in bar at index %d: expected '%s', found '%s'.\n", + static_cast<int>(i), + expected_names[i], + base::UTF16ToUTF8(toolbar_actions[i]->GetActionName()).c_str()); + } + } + size_t icon_count = toolbar_actions_bar()->GetIconCount(); + if (visible_count != icon_count) + error += base::StringPrintf( + "Incorrect visible count: expected %d, found %d", + static_cast<int>(visible_count), static_cast<int>(icon_count)); + + // Test that the (platform-specific) toolbar view matches the expected state. + for (size_t i = 0; i < total_size; ++i) { + std::string id = browser_action_test_util()->GetExtensionId(i); + if (id != toolbar_actions[i]->GetId()) { + error += base::StringPrintf( + "Incorrect action in view at index %d: expected '%s', found '%s'.\n", + static_cast<int>(i), + toolbar_actions[i]->GetId().c_str(), + id.c_str()); + } + } + size_t view_icon_count = browser_action_test_util()->VisibleBrowserActions(); + if (visible_count != view_icon_count) + error += base::StringPrintf( + "Incorrect visible count in view: expected %d, found %d", + static_cast<int>(visible_count), static_cast<int>(view_icon_count)); + + return error.empty() ? testing::AssertionSuccess() : + testing::AssertionFailure() << error; +} + +// A version of the ToolbarActionsBarUnitTest that enables the toolbar redesign. +class ToolbarActionsBarUnitTestWithSwitch : public ToolbarActionsBarUnitTest { + public: + ToolbarActionsBarUnitTestWithSwitch() {} + ~ToolbarActionsBarUnitTestWithSwitch() override {} + + protected: + void SetUp() override { + redesign_switch_.reset(new extensions::FeatureSwitch::ScopedOverride( + extensions::FeatureSwitch::extension_action_redesign(), true)); + ToolbarActionsBarUnitTest::SetUp(); + } + void TearDown() override { + redesign_switch_.reset(); + ToolbarActionsBarUnitTest::TearDown(); + } + + private: + scoped_ptr<extensions::FeatureSwitch::ScopedOverride> redesign_switch_; + + DISALLOW_COPY_AND_ASSIGN(ToolbarActionsBarUnitTestWithSwitch); +}; + +TEST_F(ToolbarActionsBarUnitTest, BasicToolbarActionsBarTest) { + // Add three extensions to the profile; this is the easiest way to have + // toolbar actions. + for (int i = 0; i < 3; ++i) { + CreateAndAddExtension( + base::StringPrintf("extension %d", i), + extensions::extension_action_test_util::BROWSER_ACTION); + } + + const ToolbarActionsBar::PlatformSettings& platform_settings = + toolbar_actions_bar()->platform_settings(); + + // By default, all three actions should be visible. + EXPECT_EQ(3u, toolbar_actions_bar()->GetIconCount()); + // Check the widths. + int expected_width = 3 * ToolbarActionsBar::IconWidth(true) - + platform_settings.item_spacing + + platform_settings.left_padding + + platform_settings.right_padding; + EXPECT_EQ(expected_width, toolbar_actions_bar()->GetPreferredSize().width()); + // Since all icons are showing, the current width should be the max width. + int maximum_width = expected_width; + EXPECT_EQ(maximum_width, toolbar_actions_bar()->GetMaximumWidth()); + // The minimum width should be just enough for the chevron to be displayed. + int minimum_width = platform_settings.left_padding + + platform_settings.right_padding + + toolbar_actions_bar()->delegate_for_test()-> + GetChevronWidth(); + EXPECT_EQ(minimum_width, toolbar_actions_bar()->GetMinimumWidth()); + + // Test the connection between the ToolbarActionsBar and the model by + // adjusting the visible count. + toolbar_model()->SetVisibleIconCount(2u); + EXPECT_EQ(2u, toolbar_actions_bar()->GetIconCount()); + + // The current width should now be enough for two icons, and the chevron. + expected_width = 2 * ToolbarActionsBar::IconWidth(true) - + platform_settings.item_spacing + + platform_settings.left_padding + + platform_settings.right_padding + + toolbar_actions_bar()->delegate_for_test()-> + GetChevronWidth(); + EXPECT_EQ(expected_width, toolbar_actions_bar()->GetPreferredSize().width()); + // The maximum and minimum widths should have remained constant (since we have + // the same number of actions). + EXPECT_EQ(maximum_width, toolbar_actions_bar()->GetMaximumWidth()); + EXPECT_EQ(minimum_width, toolbar_actions_bar()->GetMinimumWidth()); + + // Test drag-and-drop logic. + const char kExtension0[] = "extension 0"; + const char kExtension1[] = "extension 1"; + const char kExtension2[] = "extension 2"; + + { + // The order should start as 0, 1, 2. + const char* expected_names[] = { kExtension0, kExtension1, kExtension2 }; + EXPECT_TRUE(VerifyToolbarOrder(expected_names, 3u, 2u)); + } + + { + // Drag 0 to be in the second spot; 1, 0, 2, within the same container. + toolbar_actions_bar()->OnDragDrop(0, 1, ToolbarActionsBar::DRAG_TO_SAME); + const char* expected_names[] = { kExtension1, kExtension0, kExtension2 }; + EXPECT_TRUE(VerifyToolbarOrder(expected_names, 3u, 2u)); + } + + { + // Drag 0 to be in the third spot, in the overflow container. + // Order should be 1, 2, 0, and the icon count should reduce by 1. + toolbar_actions_bar()->OnDragDrop( + 1, 2, ToolbarActionsBar::DRAG_TO_OVERFLOW); + const char* expected_names[] = { kExtension1, kExtension2, kExtension0 }; + EXPECT_TRUE(VerifyToolbarOrder(expected_names, 3u, 1u)); + // The model should also reflect the updated icon count. + EXPECT_EQ(1u, toolbar_model()->visible_icon_count()); + // Dragging 2 to the main container should work, even if its spot in the + // "list" remains constant. + // Order remains 1, 2, 0, but now we have 2 icons visible. + toolbar_actions_bar()->OnDragDrop(1, 1, ToolbarActionsBar::DRAG_TO_MAIN); + EXPECT_TRUE(VerifyToolbarOrder(expected_names, 3u, 2u)); + // Similarly, dragging 2 to overflow, with the same "list" spot, should also + // work. Order remains 1, 2, 0, but icon count goes back to 1. + toolbar_actions_bar()->OnDragDrop( + 1, 1, ToolbarActionsBar::DRAG_TO_OVERFLOW); + EXPECT_TRUE(VerifyToolbarOrder(expected_names, 3u, 1u)); + } + + // Try resizing the toolbar. Start with the current width (enough for 1 icon). + int width = toolbar_actions_bar()->GetPreferredSize().width(); + + // If we try to resize by increasing, without allowing enough room for a new + // icon, width, and icon count should stay the same. + toolbar_actions_bar()->OnResizeComplete(width + 1); + EXPECT_EQ(width, toolbar_actions_bar()->GetPreferredSize().width()); + EXPECT_EQ(1u, toolbar_actions_bar()->GetIconCount()); + + // If we resize by enough to include a new icon, width and icon count should + // both increase. + width += ToolbarActionsBar::IconWidth(true); + toolbar_actions_bar()->OnResizeComplete(width); + EXPECT_EQ(width, toolbar_actions_bar()->GetPreferredSize().width()); + EXPECT_EQ(2u, toolbar_actions_bar()->GetIconCount()); + + // If we shrink the bar so that a full icon can't fit, it should resize to + // hide that icon. + toolbar_actions_bar()->OnResizeComplete(width - 1); + width -= ToolbarActionsBar::IconWidth(true); + EXPECT_EQ(width, toolbar_actions_bar()->GetPreferredSize().width()); + EXPECT_EQ(1u, toolbar_actions_bar()->GetIconCount()); +} + +// Test that toolbar actions can pop themselves out of overflow if they want to +// act on a given tab. +TEST_F(ToolbarActionsBarUnitTestWithSwitch, ActionsPopOutToAct) { + // Add three extensions to the profile; this is the easiest way to have + // toolbar actions. + const char kBrowserAction[] = "browser action"; + const char kPageAction[] = "page action"; + const char kNoAction[] = "no action"; + + CreateAndAddExtension(kBrowserAction, + extensions::extension_action_test_util::BROWSER_ACTION); + scoped_refptr<const extensions::Extension> page_action = + CreateAndAddExtension( + kPageAction, extensions::extension_action_test_util::PAGE_ACTION); + CreateAndAddExtension(kNoAction, + extensions::extension_action_test_util::NO_ACTION); + + { + // We should start in the order of "browser action", "page action", + // "no action" and have all actions visible. + const char* expected_names[] = { kBrowserAction, kPageAction, kNoAction }; + EXPECT_TRUE(VerifyToolbarOrder(expected_names, 3u, 3u)); + } + + // Shrink the bar to only show one action, and move the page action to the + // end. + toolbar_model()->SetVisibleIconCount(1); + toolbar_model()->MoveExtensionIcon(page_action->id(), 2u); + + { + // Quickly verify that the move/visible count worked. + const char* expected_names[] = { kBrowserAction, kNoAction, kPageAction }; + EXPECT_TRUE(VerifyToolbarOrder(expected_names, 3u, 1u)); + } + + // Create two tabs. + AddTab(browser(), GURL("http://www.google.com/")); + AddTab(browser(), GURL("http://www.youtube.com/")); + content::WebContents* web_contents = + browser()->tab_strip_model()->GetWebContentsAt(0); + + { + // First, check the order for the first tab. Since we haven't changed + // anything (i.e., no extensions want to act), this should be the same as we + // left it: "browser action", "no action", "page action", with only one + // visible. + ActivateTab(0); + const char* expected_names[] = { kBrowserAction, kNoAction, kPageAction }; + EXPECT_TRUE(VerifyToolbarOrder(expected_names, 3u, 1u)); + } + + extensions::ExtensionActionManager* action_manager = + extensions::ExtensionActionManager::Get(profile()); + ExtensionAction* action = action_manager->GetExtensionAction(*page_action); + ASSERT_TRUE(action); + + { + // Make "page action" want to act. + SetActionWantsToRunOnTab(action, web_contents, true); + // This should result in "page action" being popped out of the overflow + // menu. + // This has two visible effects: + // - page action should moved to the zero-index (left-most side of the bar). + // - The visible count should increase by one (so page action is visible). + const char* expected_names[] = { kPageAction, kBrowserAction, kNoAction }; + EXPECT_TRUE(VerifyToolbarOrder(expected_names, 3u, 2u)); + } + + { + // This should not have any effect on the second tab, which should still + // have the original order and visible count. + ActivateTab(1); + const char* expected_names[] = { kBrowserAction, kNoAction, kPageAction }; + EXPECT_TRUE(VerifyToolbarOrder(expected_names, 3u, 1u)); + } + + { + // Switching back to the first tab should mean that actions that want to run + // are re-popped out. + ActivateTab(0); + const char* expected_names[] = { kPageAction, kBrowserAction, kNoAction }; + EXPECT_TRUE(VerifyToolbarOrder(expected_names, 3u, 2u)); + } + + { + // Now, set the action to be hidden again, and notify of the change. + SetActionWantsToRunOnTab(action, web_contents, false); + // The order and visible count should return to normal (the page action + // should move back to its original index in overflow). + const char* expected_names[] = { kBrowserAction, kNoAction, kPageAction }; + EXPECT_TRUE(VerifyToolbarOrder(expected_names, 3u, 1u)); + } + + { + // Move page action to the second index and increase visible size to 2 (so + // it's naturally visible). + toolbar_model()->MoveExtensionIcon(page_action->id(), 1u); + toolbar_model()->SetVisibleIconCount(2u); + const char* expected_names[] = { kBrowserAction, kPageAction, kNoAction }; + EXPECT_TRUE(VerifyToolbarOrder(expected_names, 3u, 2u)); + // Make the now-visible page action want to act. + // Since the action is already visible, this should have no effect - the + // order and visible count should remain unchanged. + SetActionWantsToRunOnTab(action, web_contents, true); + EXPECT_TRUE(VerifyToolbarOrder(expected_names, 3u, 2u)); + } + + { + // We should still be able to increase the size of the model, and to move + // the page action. + toolbar_model()->SetVisibleIconCount(3); + toolbar_model()->MoveExtensionIcon(page_action->id(), 0u); + const char* expected_names[] = { kPageAction, kBrowserAction, kNoAction }; + EXPECT_TRUE(VerifyToolbarOrder(expected_names, 3u, 3u)); + // If we moved the page action, the move should remain in effect even after + // the action no longer wants to act. + SetActionWantsToRunOnTab(action, web_contents, false); + EXPECT_TRUE(VerifyToolbarOrder(expected_names, 3u, 3u)); + } + + { + // Test the edge case of having no icons visible. + toolbar_model()->SetVisibleIconCount(0); + const char* expected_names[] = { kPageAction, kBrowserAction, kNoAction }; + EXPECT_TRUE(VerifyToolbarOrder(expected_names, 3u, 0u)); + SetActionWantsToRunOnTab(action, web_contents, true); + EXPECT_TRUE(VerifyToolbarOrder(expected_names, 3u, 1u)); + } + + // Reset the action, and create another page action extension. + SetActionWantsToRunOnTab(action, web_contents, false); + const char kPageAction2[] = "page action2"; + scoped_refptr<const extensions::Extension> page_action2 = + CreateAndAddExtension( + kPageAction2, extensions::extension_action_test_util::PAGE_ACTION); + + { + // The second page action should be added to the end, and no icons should + // be visible. + const char* expected_names[] = + { kPageAction, kBrowserAction, kNoAction, kPageAction2 }; + EXPECT_TRUE(VerifyToolbarOrder(expected_names, 4u, 0u)); + } + + { + // Make both page actions want to run, with the second triggering first. + SetActionWantsToRunOnTab( + action_manager->GetExtensionAction(*page_action2), web_contents, true); + SetActionWantsToRunOnTab(action, web_contents, true); + + // Even though the second page action triggered first, the order of actions + // wanting to run should respect the normal order of actions. + const char* expected_names[] = + { kPageAction, kPageAction2, kBrowserAction, kNoAction }; + EXPECT_TRUE(VerifyToolbarOrder(expected_names, 4u, 2u)); + } +}
diff --git a/chrome/browser/ui/view_ids.h b/chrome/browser/ui/view_ids.h index 27183b56..7532a79 100644 --- a/chrome/browser/ui/view_ids.h +++ b/chrome/browser/ui/view_ids.h
@@ -22,7 +22,7 @@ VIEW_ID_CLOSE_BUTTON, VIEW_ID_WINDOW_ICON, VIEW_ID_WINDOW_TITLE, -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) VIEW_ID_SUPERVISED_USER_AVATAR_LABEL, #endif VIEW_ID_AVATAR_BUTTON,
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views.cc b/chrome/browser/ui/views/apps/chrome_native_app_window_views.cc index 849f453..bf33c479 100644 --- a/chrome/browser/ui/views/apps/chrome_native_app_window_views.cc +++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views.cc
@@ -12,6 +12,7 @@ #include "chrome/browser/favicon/favicon_tab_helper.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/host_desktop.h" +#include "chrome/browser/ui/views/apps/desktop_keyboard_capture.h" #include "chrome/browser/ui/views/apps/shaped_app_window_targeter.h" #include "chrome/browser/ui/views/extensions/extension_keybinding_registry_views.h" #include "chrome/browser/ui/views/frame/taskbar_decorator.h" @@ -684,6 +685,14 @@ return inactive_frame_color_; } +void ChromeNativeAppWindowViews::SetInterceptAllKeys(bool want_all_keys) { + if (want_all_keys && (desktop_keyboard_capture_.get() == NULL)) { + desktop_keyboard_capture_.reset(new DesktopKeyboardCapture(widget())); + } else if (!want_all_keys) { + desktop_keyboard_capture_.reset(NULL); + } +} + // NativeAppWindowViews implementation. void ChromeNativeAppWindowViews::InitializeWindow(
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views.h b/chrome/browser/ui/views/apps/chrome_native_app_window_views.h index ca0c96f8..d6a7c16 100644 --- a/chrome/browser/ui/views/apps/chrome_native_app_window_views.h +++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views.h
@@ -19,6 +19,7 @@ } #endif +class DesktopKeyboardCapture; class ExtensionKeybindingRegistryViews; namespace views { @@ -82,6 +83,7 @@ bool HasFrameColor() const override; SkColor ActiveFrameColor() const override; SkColor InactiveFrameColor() const override; + virtual void SetInterceptAllKeys(bool want_all_keys) override; // NativeAppWindowViews implementation. void InitializeWindow( @@ -115,6 +117,9 @@ // Used to show the system menu. scoped_ptr<views::MenuRunner> menu_runner_; + // Used to capture all keyboard events including task switching sequence. + scoped_ptr<DesktopKeyboardCapture> desktop_keyboard_capture_; + DISALLOW_COPY_AND_ASSIGN(ChromeNativeAppWindowViews); };
diff --git a/chrome/browser/ui/views/apps/desktop_keyboard_capture.cc b/chrome/browser/ui/views/apps/desktop_keyboard_capture.cc new file mode 100644 index 0000000..578b1da --- /dev/null +++ b/chrome/browser/ui/views/apps/desktop_keyboard_capture.cc
@@ -0,0 +1,40 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/views/apps/desktop_keyboard_capture.h" +#include "chrome/browser/ui/views/apps/keyboard_hook_handler.h" + +DesktopKeyboardCapture::DesktopKeyboardCapture(views::Widget* widget) + : widget_(widget), is_registered_(false) { + widget_->AddObserver(this); + + if (widget_->IsActive()) + RegisterKeyboardHooks(); +} + +DesktopKeyboardCapture::~DesktopKeyboardCapture() { + if (is_registered_) + DeregisterKeyboardHooks(); + + widget_->RemoveObserver(this); +} + +void DesktopKeyboardCapture::RegisterKeyboardHooks() { + KeyboardHookHandler::GetInstance()->Register(widget_); + is_registered_ = true; +} + +void DesktopKeyboardCapture::DeregisterKeyboardHooks() { + KeyboardHookHandler::GetInstance()->Deregister(widget_); + is_registered_ = false; +} + +void DesktopKeyboardCapture::OnWidgetActivationChanged(views::Widget* widget, + bool active) { + if (active) { + RegisterKeyboardHooks(); + } else { + DeregisterKeyboardHooks(); + } +}
diff --git a/chrome/browser/ui/views/apps/desktop_keyboard_capture.h b/chrome/browser/ui/views/apps/desktop_keyboard_capture.h new file mode 100644 index 0000000..fb769619 --- /dev/null +++ b/chrome/browser/ui/views/apps/desktop_keyboard_capture.h
@@ -0,0 +1,34 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_VIEWS_APPS_DESKTOP_KEYBOARD_CAPTURE_H_ +#define CHROME_BROWSER_UI_VIEWS_APPS_DESKTOP_KEYBOARD_CAPTURE_H_ + +#include "ui/views/widget/widget.h" +#include "ui/views/widget/widget_observer.h" + +// This class installs/uninstalls keyboard hook as the widget activation +// changes. +class DesktopKeyboardCapture : public views::WidgetObserver { + public: + explicit DesktopKeyboardCapture(views::Widget* widget); + ~DesktopKeyboardCapture(); + + private: + // views::WidgetObserver implementation. + void OnWidgetActivationChanged(views::Widget* widget, bool active) override; + + void RegisterKeyboardHooks(); + void DeregisterKeyboardHooks(); + + // The widget registering for keyboard intercept. Weak reference. + views::Widget* widget_; + + // Current state of keyboard intercept registration. + bool is_registered_; + + DISALLOW_COPY_AND_ASSIGN(DesktopKeyboardCapture); +}; + +#endif // CHROME_BROWSER_UI_VIEWS_APPS_DESKTOP_KEYBOARD_CAPTURE_H_
diff --git a/chrome/browser/ui/views/apps/keyboard_hook_handler.cc b/chrome/browser/ui/views/apps/keyboard_hook_handler.cc new file mode 100644 index 0000000..60178f03 --- /dev/null +++ b/chrome/browser/ui/views/apps/keyboard_hook_handler.cc
@@ -0,0 +1,21 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/views/apps/keyboard_hook_handler.h" + +#include "base/memory/singleton.h" + +// TODO(sriramsr): Implement for other platforms. +// Empty implementation for other platforms. +void KeyboardHookHandler::Register(views::Widget* widget) { +} + +void KeyboardHookHandler::Deregister(views::Widget* widget) { +} + +// static +KeyboardHookHandler* KeyboardHookHandler::GetInstance() { + return Singleton<KeyboardHookHandler, + DefaultSingletonTraits<KeyboardHookHandler>>::get(); +}
diff --git a/chrome/browser/ui/views/apps/keyboard_hook_handler.h b/chrome/browser/ui/views/apps/keyboard_hook_handler.h new file mode 100644 index 0000000..a1412c0 --- /dev/null +++ b/chrome/browser/ui/views/apps/keyboard_hook_handler.h
@@ -0,0 +1,23 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_VIEWS_APPS_KEYBOARD_HOOK_HANDLER_H_ +#define CHROME_BROWSER_UI_VIEWS_APPS_KEYBOARD_HOOK_HANDLER_H_ + +#include "ui/views/widget/widget.h" + +// Interface to control keyboard hook on different platform. +class KeyboardHookHandler { + public: + // Request all keyboard events to be routed to the given window. + void Register(views::Widget* widget); + + // Release the request for all keyboard events. + void Deregister(views::Widget* widget); + + // Implemented in platform specific code. + static KeyboardHookHandler* GetInstance(); +}; + +#endif // CHROME_BROWSER_UI_VIEWS_APPS_KEYBOARD_HOOK_HANDLER_H_
diff --git a/chrome/browser/ui/views/apps/keyboard_hook_handler_win.cc b/chrome/browser/ui/views/apps/keyboard_hook_handler_win.cc new file mode 100644 index 0000000..3d34ab6d --- /dev/null +++ b/chrome/browser/ui/views/apps/keyboard_hook_handler_win.cc
@@ -0,0 +1,428 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/views/apps/keyboard_hook_handler.h" + +#include <map> + +#include "base/containers/scoped_ptr_hash_map.h" +#include "base/logging.h" +#include "base/macros.h" +#include "base/memory/singleton.h" +#include "base/message_loop/message_loop.h" +#include "base/message_loop/message_pump_win.h" +#include "ui/aura/window.h" +#include "ui/aura/window_tree_host.h" + +namespace { +// Some helper routines used to construct keyboard event. + +// Return true of WPARAM corresponds to a UP keyboard event. +bool IsKeyUp(WPARAM w_param) { + return (w_param == WM_KEYUP) || (w_param == WM_SYSKEYUP); +} + +// Check if the given bit is set. +bool IsBitSet(ULONG value, ULONG mask) { + return ((value & mask) != 0); +} + +// Get Window handle from widget. +HWND GetWindowHandle(views::Widget* widget) { + return widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget(); +} + +// Return the location independent keycode corresponding to given keycode (e.g. +// return shift when left/right shift is pressed). This is needed as low level +// hooks get location information which is not returned as part of normal window +// keyboard events. +DWORD RemoveLocationOnKeycode(DWORD vk_code) { + // Virtual keycode from low level hook include location while window messages + // does not. So convert them to be without location. + switch (vk_code) { + case VK_LSHIFT: + case VK_RSHIFT: + return VK_SHIFT; + case VK_LCONTROL: + case VK_RCONTROL: + return VK_CONTROL; + case VK_LMENU: + case VK_RMENU: + return VK_MENU; + } + return vk_code; +} + +// Construct LPARAM corresponding to the given low level hook callback +// structure. +LPARAM GetLParamFromHookStruct(WPARAM w_param, KBDLLHOOKSTRUCT* hook_struct) { + ULONG key_state = 0; + // There is no way to get repeat count so always set it to 1. + key_state = 1; + + // Scan code. + key_state |= (hook_struct->scanCode & 0xFF) << 16; + + // Extended key when the event is received as part window event and so skip + // it. + + // Context code. + key_state |= IsBitSet(hook_struct->flags, LLKHF_ALTDOWN) << 29; + + // Previous key state - set to 1 for KEYUP events. + key_state |= IsKeyUp(w_param) << 30; + + // Transition state. + key_state |= IsBitSet(hook_struct->flags, LLKHF_UP) << 31; + + return static_cast<LPARAM>(key_state); +} + +// List of key state that we want to save. +const int kKeysToSave[] = {VK_SHIFT, VK_CONTROL, VK_MENU}; + +// Make sure that we are not going to run out of bits saving the state. +C_ASSERT((arraysize(kKeysToSave) * 2) <= (sizeof(WPARAM) * 8)); + +// Save keyboard state to WPARAM so it can be restored later before the keyboard +// message is processed in the main thread. This is necessary for +// GetKeyboardState() to work as keyboard state will be different by the time +// main thread processes the message. +WPARAM SaveKeyboardState() { + WPARAM value = 0; + + for (int index = 0; index < arraysize(kKeysToSave); index++) { + value <<= 2; + SHORT key_state = GetAsyncKeyState(kKeysToSave[index]); + value |= ((IsBitSet(key_state, 0x8000) ? 0x2 : 0) | + (IsBitSet(key_state, 0x1) ? 0x1 : 0)); + } + return value; +} + +// Restore keyboard state based on saved values. +bool RestoreKeyboardState(WPARAM w_param) { + const int kKeyboardStateLength = 256; + BYTE keyboard_state[kKeyboardStateLength]; + if (!GetKeyboardState(keyboard_state)) { + DVLOG(ERROR) << "Error getting keyboard state"; + return false; + } + + // restore in the reverse order of what was saved so we have the right bit for + // each key that was saved. + for (int index = arraysize(kKeysToSave) - 1; index >= 0; index--) { + int key = kKeysToSave[index]; + keyboard_state[key] = + (IsBitSet(w_param, 0x2) ? 0x80 : 0) | (IsBitSet(w_param, 0x1) ? 1 : 0); + w_param >>= 2; + } + + if (!SetKeyboardState(keyboard_state)) { + DVLOG(ERROR) << "Error setting keyboard state"; + return false; + } + + return true; +} + +// Data corresponding to keyboard event. +struct KeyboardEventInfo { + UINT message_id; + WPARAM event_w_param; + LPARAM event_l_param; + WPARAM keyboard_state_to_restore; +}; + +// Maintains low level registration for a window. +class KeyboardInterceptRegistration { + public: + KeyboardInterceptRegistration(); + + // Are there any keyboard events queued. + bool IsKeyboardEventQueueEmpty(); + + // Insert keyboard event in the queue. + void QueueKeyboardEvent(const KeyboardEventInfo& info); + + KeyboardEventInfo DequeueKeyboardEvent(); + + private: + std::queue<KeyboardEventInfo> keyboard_events_; + + DISALLOW_COPY_AND_ASSIGN(KeyboardInterceptRegistration); +}; + +// Implements low level hook and manages registration for all the windows. +class LowLevelHookHandler { + public: + // Request all keyboard events to be routed to the given window. + void Register(HWND window_handle); + + // Release the request for all keyboard events. + void Deregister(HWND window_handle); + + // Get singleton instance. + static LowLevelHookHandler* GetInstance(); + + private: + // Private constructor/destructor so it is accessible only + // DefaultSingletonTraits. + friend struct DefaultSingletonTraits<LowLevelHookHandler>; + LowLevelHookHandler(); + + ~LowLevelHookHandler(); + + // Low level keyboard hook processing related functions. + // Hook callback called from the OS. + static LRESULT CALLBACK + KeyboardHook(int code, WPARAM w_param, LPARAM l_param); + + // Low level keyboard hook handler. + LRESULT HandleKeyboardHook(int code, WPARAM w_param, LPARAM l_param); + + // Message filter to set keyboard state based on private message. + static LRESULT CALLBACK + MessageFilterHook(int code, WPARAM w_param, LPARAM l_param); + + // Message filter handler. + LRESULT HandleMessageFilterHook(int code, WPARAM w_param, LPARAM l_param); + + bool EnableHooks(); + void DisableHooks(); + + // Hook handle for window message to set keyboard state based on private + // message. + HHOOK message_filter_hook_; + + // Hook handle for low level keyboard hook. + HHOOK keyboard_hook_; + + // Private window message to set keyboard state for the thread. + UINT restore_keyboard_state_message_id_; + + // Private message to inject keyboard event after current injected message is + // processed. + UINT inject_keyboard_event_message_id_; + + // There is no lock protecting this list as the low level hook callbacks are + // executed on same thread that registered the hook and there is only one + // thread + // that execute all view code in browser. + base::ScopedPtrHashMap<HWND, KeyboardInterceptRegistration> registrations_; + + DISALLOW_COPY_AND_ASSIGN(LowLevelHookHandler); +}; + +KeyboardInterceptRegistration::KeyboardInterceptRegistration() { +} + +bool KeyboardInterceptRegistration::IsKeyboardEventQueueEmpty() { + return keyboard_events_.empty(); +} + +void KeyboardInterceptRegistration::QueueKeyboardEvent( + const KeyboardEventInfo& info) { + keyboard_events_.push(info); +} + +KeyboardEventInfo KeyboardInterceptRegistration::DequeueKeyboardEvent() { + KeyboardEventInfo info = keyboard_events_.front(); + keyboard_events_.pop(); + return info; +} + +LowLevelHookHandler::LowLevelHookHandler() + : message_filter_hook_(NULL), + keyboard_hook_(NULL), + restore_keyboard_state_message_id_(0), + inject_keyboard_event_message_id_(0) { + restore_keyboard_state_message_id_ = + RegisterWindowMessage(L"chrome:restore_keyboard_state"); + inject_keyboard_event_message_id_ = + RegisterWindowMessage(L"chrome:inject_keyboard_event"); +} + +LowLevelHookHandler::~LowLevelHookHandler() { + DisableHooks(); +} + +// static +LRESULT CALLBACK +LowLevelHookHandler::KeyboardHook(int code, WPARAM w_param, LPARAM l_param) { + return GetInstance()->HandleKeyboardHook(code, w_param, l_param); +} + +// static +LRESULT CALLBACK LowLevelHookHandler::MessageFilterHook(int code, + WPARAM w_param, + LPARAM l_param) { + return GetInstance()->HandleMessageFilterHook(code, w_param, l_param); +} + +// static +LowLevelHookHandler* LowLevelHookHandler::GetInstance() { + return Singleton<LowLevelHookHandler, + DefaultSingletonTraits<LowLevelHookHandler>>::get(); +} + +void LowLevelHookHandler::Register(HWND window_handle) { + if (registrations_.contains(window_handle)) + return; + + if (!EnableHooks()) + return; + + scoped_ptr<KeyboardInterceptRegistration> registration( + new KeyboardInterceptRegistration()); + registrations_.add(window_handle, registration.Pass()); +} + +void LowLevelHookHandler::Deregister(HWND window_handle) { + registrations_.erase(window_handle); + if (registrations_.empty()) + DisableHooks(); + + DVLOG(1) << "Keyboard hook unregistered for handle = " << window_handle; +} + +bool LowLevelHookHandler::EnableHooks() { + // Make sure that hook is set from main thread as it has to be valid for + // the lifetime of the registration. + DCHECK(base::MessageLoopForUI::IsCurrent()); + + if (keyboard_hook_) + return true; + + message_filter_hook_ = SetWindowsHookEx(WH_MSGFILTER, MessageFilterHook, NULL, + GetCurrentThreadId()); + if (message_filter_hook_ == NULL) { + DVLOG(ERROR) << "Error calling SetWindowsHookEx() to set message hook, " + << "gle = " << GetLastError(); + return false; + } + + DCHECK(keyboard_hook_ == NULL) << "Keyboard hook already registered"; + + keyboard_hook_ = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHook, NULL, 0); + if (keyboard_hook_ == NULL) { + DVLOG(ERROR) << "Error calling SetWindowsHookEx() - GLE = " + << GetLastError(); + DisableHooks(); + return false; + } + + return true; +} + +void LowLevelHookHandler::DisableHooks() { + if (keyboard_hook_ != NULL) { + UnhookWindowsHookEx(keyboard_hook_); + keyboard_hook_ = NULL; + } + + if (message_filter_hook_ != NULL) { + UnhookWindowsHookEx(message_filter_hook_); + message_filter_hook_ = NULL; + } +} + +LRESULT +LowLevelHookHandler::HandleMessageFilterHook(int code, + WPARAM w_param, + LPARAM l_param) { + // Ignore if not called from main message loop. + if (code != base::MessagePumpForUI::kMessageFilterCode) + return CallNextHookEx(NULL, code, w_param, l_param); + + MSG* msg = reinterpret_cast<MSG*>(l_param); + if (msg->message == restore_keyboard_state_message_id_) { + RestoreKeyboardState(msg->wParam); + return true; + } else if (msg->message == inject_keyboard_event_message_id_) { + KeyboardInterceptRegistration* registration = registrations_.get(msg->hwnd); + if (registration) { + // Post keyboard state and key event to main thread for processing. + KeyboardEventInfo event_info = registration->DequeueKeyboardEvent(); + PostMessage(msg->hwnd, restore_keyboard_state_message_id_, + event_info.keyboard_state_to_restore, static_cast<LPARAM>(0)); + + PostMessage(msg->hwnd, event_info.message_id, event_info.event_w_param, + event_info.event_l_param); + + if (!registration->IsKeyboardEventQueueEmpty()) { + // Post another inject keyboard event if there are more key events to + // process after the current injected event is processed. + PostMessage(msg->hwnd, inject_keyboard_event_message_id_, + static_cast<WPARAM>(0), static_cast<LPARAM>(0)); + } + + return true; + } + } + + return CallNextHookEx(NULL, code, w_param, l_param); +} + +LRESULT +LowLevelHookHandler::HandleKeyboardHook(int code, + WPARAM w_param, + LPARAM l_param) { + HWND current_active_window = GetForegroundWindow(); + + // Additional check to make sure that the current window is indeed owned by + // this proccess. + DWORD pid = 0; + ::GetWindowThreadProcessId(current_active_window, &pid); + if (!pid || (pid != ::GetCurrentProcessId())) + return CallNextHookEx(NULL, code, w_param, l_param); + + if ((code >= 0) && (current_active_window != NULL)) { + KeyboardInterceptRegistration* registration = + registrations_.get(current_active_window); + if (registration) { + // Save keyboard state to queue and post message to handle keyboard event + // if the queue is not empty. It is done this way as keyboard state should + // be preserved until char event corresponding to the keyboard event is + // handled (so correct alt/shift/control key state is set). Also + // SendMessage() cannot be used as it would bypass both message loop + // delegates and TransalateMessage() calls (which will inserts char + // events). + PKBDLLHOOKSTRUCT hook_struct = + reinterpret_cast<PKBDLLHOOKSTRUCT>(l_param); + + KeyboardEventInfo event_info = {0}; + event_info.message_id = w_param; + event_info.event_w_param = RemoveLocationOnKeycode(hook_struct->vkCode); + event_info.event_l_param = GetLParamFromHookStruct(w_param, hook_struct); + event_info.keyboard_state_to_restore = SaveKeyboardState(); + + bool should_queue_inject_event = + registration->IsKeyboardEventQueueEmpty(); + + registration->QueueKeyboardEvent(event_info); + if (should_queue_inject_event) { + PostMessage(current_active_window, inject_keyboard_event_message_id_, + static_cast<WPARAM>(0), static_cast<LPARAM>(0)); + } + return 1; + } + } + + return CallNextHookEx(NULL, code, w_param, l_param); +} +} // namespace + +KeyboardHookHandler* KeyboardHookHandler::GetInstance() { + return Singleton<KeyboardHookHandler, + DefaultSingletonTraits<KeyboardHookHandler>>::get(); +} + +void KeyboardHookHandler::Register(views::Widget* widget) { + LowLevelHookHandler::GetInstance()->Register(GetWindowHandle(widget)); +} + +void KeyboardHookHandler::Deregister(views::Widget* widget) { + LowLevelHookHandler::GetInstance()->Deregister(GetWindowHandle(widget)); +}
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc index 394aef7..d125b92 100644 --- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc +++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
@@ -100,6 +100,15 @@ using views::MenuButton; using views::View; +// How inset the bookmarks bar is when displayed on the new tab page. +static const int kNewTabHorizontalPadding = 2; + +// Maximum size of buttons on the bookmark bar. +static const int kMaxButtonWidth = 150; + +// Number of pixels the attached bookmark bar overlaps with the toolbar. +static const int kToolbarAttachedBookmarkBarOverlap = 3; + // Margins around the content. static const int kDetachedTopMargin = 1; // When attached, we use 0 and let the // toolbar above serve as the margin. @@ -107,9 +116,6 @@ static const int kLeftMargin = 1; static const int kRightMargin = 1; -// static -const char BookmarkBarView::kViewClassName[] = "BookmarkBarView"; - // Padding between buttons. static const int kButtonPadding = 0; @@ -164,6 +170,22 @@ // animations are enabled by default. bool animations_enabled = true; +const gfx::ImageSkia& GetDefaultFavicon() { + if (!kDefaultFavicon) { + ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); + kDefaultFavicon = rb->GetImageSkiaNamed(IDR_DEFAULT_FAVICON); + } + return *kDefaultFavicon; +} + +const gfx::ImageSkia& GetFolderIcon() { + if (!kFolderIcon) { + ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); + kFolderIcon = rb->GetImageSkiaNamed(IDR_BOOKMARK_BAR_FOLDER); + } + return *kFolderIcon; +} + // BookmarkButtonBase ----------------------------------------------- // Base class for buttons used on the bookmark bar. @@ -441,25 +463,7 @@ // BookmarkBarView ------------------------------------------------------------ // static -const int BookmarkBarView::kMaxButtonWidth = 150; -const int BookmarkBarView::kNewtabHorizontalPadding = 2; -const int BookmarkBarView::kToolbarAttachedBookmarkBarOverlap = 3; - -const gfx::ImageSkia& GetDefaultFavicon() { - if (!kDefaultFavicon) { - ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); - kDefaultFavicon = rb->GetImageSkiaNamed(IDR_DEFAULT_FAVICON); - } - return *kDefaultFavicon; -} - -const gfx::ImageSkia& GetFolderIcon() { - if (!kFolderIcon) { - ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); - kFolderIcon = rb->GetImageSkiaNamed(IDR_BOOKMARK_BAR_FOLDER); - } - return *kFolderIcon; -} +const char BookmarkBarView::kViewClassName[] = "BookmarkBarView"; BookmarkBarView::BookmarkBarView(Browser* browser, BrowserView* browser_view) : page_navigator_(NULL), @@ -747,7 +751,7 @@ int height = chrome::kBookmarkBarHeight; if (IsDetached()) { double current_state = 1 - size_animation_->GetCurrentValue(); - width += 2 * static_cast<int>(kNewtabHorizontalPadding * current_state); + width += 2 * static_cast<int>(kNewTabHorizontalPadding * current_state); height += static_cast<int>( (chrome::kNTPBookmarkBarHeight - chrome::kBookmarkBarHeight) * current_state); @@ -791,9 +795,9 @@ if (IsDetached()) { double current_state = 1 - size_animation_->GetCurrentValue(); - x += static_cast<int>(kNewtabHorizontalPadding * current_state); + x += static_cast<int>(kNewTabHorizontalPadding * current_state); y += (View::height() - chrome::kBookmarkBarHeight) / 2; - width -= static_cast<int>(kNewtabHorizontalPadding * current_state); + width -= static_cast<int>(kNewTabHorizontalPadding * current_state); separator_margin -= static_cast<int>(kSeparatorMargin * current_state); } else { // For the attached appearance, pin the content to the bottom of the bar
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.h b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.h index fd352028..d150d8a9 100644 --- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.h +++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.h
@@ -73,16 +73,6 @@ // The internal view class name. static const char kViewClassName[]; - // Constant used in Browser View, as well as here. - // How inset the bookmarks bar is when displayed on the new tab page. - static const int kNewtabHorizontalPadding; - - // Maximum size of buttons on the bookmark bar. - static const int kMaxButtonWidth; - - // Number of pixels the attached bookmark bar overlaps with the toolbar. - static const int kToolbarAttachedBookmarkBarOverlap; - // |browser_view| can be NULL during tests. BookmarkBarView(Browser* browser, BrowserView* browser_view); ~BookmarkBarView() override;
diff --git a/chrome/browser/ui/views/chrome_views_delegate.cc b/chrome/browser/ui/views/chrome_views_delegate.cc index c8c15950..38977af 100644 --- a/chrome/browser/ui/views/chrome_views_delegate.cc +++ b/chrome/browser/ui/views/chrome_views_delegate.cc
@@ -230,6 +230,10 @@ return GetAppIcon(); } +HICON ChromeViewsDelegate::GetSmallWindowIcon() const { + return GetSmallAppIcon(); +} + bool ChromeViewsDelegate::IsWindowInMetro(gfx::NativeWindow window) const { return chrome::IsNativeViewInAsh(window); }
diff --git a/chrome/browser/ui/views/chrome_views_delegate.h b/chrome/browser/ui/views/chrome_views_delegate.h index 4d307f3..693bec61 100644 --- a/chrome/browser/ui/views/chrome_views_delegate.h +++ b/chrome/browser/ui/views/chrome_views_delegate.h
@@ -34,6 +34,7 @@ bool has_submenu) override; #if defined(OS_WIN) virtual HICON GetDefaultWindowIcon() const override; + virtual HICON GetSmallWindowIcon() const override; virtual bool IsWindowInMetro(gfx::NativeWindow window) const override; #elif defined(OS_LINUX) && !defined(OS_CHROMEOS) gfx::ImageSkia* GetDefaultWindowIcon() const override;
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc index b01d32d..35e4ea2 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
@@ -24,7 +24,7 @@ #include "ui/gfx/image/image.h" #include "ui/views/background.h" -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) #include "chrome/browser/ui/views/profiles/supervised_user_avatar_label.h" #endif @@ -33,7 +33,7 @@ : frame_(frame), browser_view_(browser_view), avatar_button_(nullptr), -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) supervised_user_avatar_label_(nullptr), #endif new_avatar_button_(nullptr) { @@ -80,7 +80,7 @@ OnProfileAvatarChanged(base::FilePath()); } -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) void BrowserNonClientFrameView::OnThemeChanged() { if (supervised_user_avatar_label_) supervised_user_avatar_label_->UpdateLabelStyle(); @@ -90,7 +90,7 @@ void BrowserNonClientFrameView::UpdateAvatarInfo() { if (browser_view_->ShouldShowAvatar()) { if (!avatar_button_) { -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) Profile* profile = browser_view_->browser()->profile(); if (profile->IsSupervised() && !supervised_user_avatar_label_) { supervised_user_avatar_label_ = @@ -109,7 +109,7 @@ frame_->GetRootView()->Layout(); } } else if (avatar_button_) { -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) // The avatar label can just be there if there is also an avatar button. if (supervised_user_avatar_label_) { RemoveChildView(supervised_user_avatar_label_);
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view.h b/chrome/browser/ui/views/frame/browser_non_client_frame_view.h index e5bd8953..43c820a 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view.h +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view.h
@@ -8,7 +8,7 @@ #include "chrome/browser/ui/views/profiles/new_avatar_button.h" #include "ui/views/window/non_client_view.h" -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) class SupervisedUserAvatarLabel; #endif class AvatarMenuButton; @@ -28,7 +28,7 @@ NewAvatarButton* new_avatar_button() const { return new_avatar_button_; } -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) SupervisedUserAvatarLabel* supervised_user_avatar_label() const { return supervised_user_avatar_label_; } @@ -97,7 +97,7 @@ // icon. May be null for some frame styles. AvatarMenuButton* avatar_button_; -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) SupervisedUserAvatarLabel* supervised_user_avatar_label_; #endif
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc index 31fab2d9..fe0dcba 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
@@ -43,7 +43,7 @@ #include "ui/views/widget/widget.h" #include "ui/views/widget/widget_delegate.h" -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) #include "chrome/browser/ui/views/profiles/supervised_user_avatar_label.h" #endif @@ -260,7 +260,7 @@ return HTCLIENT; } -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) // ...or within the avatar label, if it's a supervised user. if (hit_test == HTCAPTION && supervised_user_avatar_label() && ConvertedHitTest(this, supervised_user_avatar_label(), point)) { @@ -509,10 +509,8 @@ } bool BrowserNonClientFrameViewAsh::UseWebAppHeaderStyle() const { - // Use of the experimental WebApp header style is guarded with the - // streamlined hosted app style. - return browser_view()->browser()->is_app() && - extensions::util::IsStreamlinedHostedAppsEnabled(); + return browser_view()->browser()->SupportsWindowFeature( + Browser::FEATURE_WEBAPPFRAME); } void BrowserNonClientFrameViewAsh::LayoutAvatar() {
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc index 19b92bb..5d081a8 100644 --- a/chrome/browser/ui/views/frame/browser_view.cc +++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -1574,12 +1574,11 @@ } bool BrowserView::ShouldShowWindowTitle() const { - // For Ash only, trusted windows (apps and settings) do not show an icon, - // crbug.com/119411. Child windows (i.e. popups) do show an icon. + // For Ash only, trusted windows (apps and settings) do not show a title, + // crbug.com/119411. Child windows (i.e. popups) do show a title. if (browser_->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH && browser_->is_trusted_source() && - !(browser_->is_app() && - extensions::util::IsStreamlinedHostedAppsEnabled())) + !browser_->SupportsWindowFeature(Browser::FEATURE_WEBAPPFRAME)) return false; return browser_->SupportsWindowFeature(Browser::FEATURE_TITLEBAR); @@ -1609,8 +1608,7 @@ // crbug.com/119411. Child windows (i.e. popups) do show an icon. if (browser_->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH && browser_->is_trusted_source() && - !(browser_->is_app() && - extensions::util::IsStreamlinedHostedAppsEnabled())) + !browser_->SupportsWindowFeature(Browser::FEATURE_WEBAPPFRAME)) return false; return browser_->SupportsWindowFeature(Browser::FEATURE_TITLEBAR);
diff --git a/chrome/browser/ui/views/frame/browser_window_property_manager_browsertest_win.cc b/chrome/browser/ui/views/frame/browser_window_property_manager_browsertest_win.cc index 4e23d74..942d8b1 100644 --- a/chrome/browser/ui/views/frame/browser_window_property_manager_browsertest_win.cc +++ b/chrome/browser/ui/views/frame/browser_window_property_manager_browsertest_win.cc
@@ -25,6 +25,7 @@ #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_iterator.h" #include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/extensions/app_launch_params.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/browser/web_applications/web_app.h" #include "chrome/browser/web_applications/web_app_win.h" @@ -34,6 +35,7 @@ #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/test_switches.h" #include "content/public/test/test_utils.h" +#include "extensions/common/constants.h" #include "extensions/common/extension.h" #include "ui/views/win/hwnd_util.h" @@ -242,10 +244,9 @@ LoadExtension(test_data_dir_.AppendASCII("app/")); EXPECT_TRUE(extension); - OpenApplication(AppLaunchParams(browser()->profile(), - extension, - extensions::LAUNCH_CONTAINER_WINDOW, - NEW_FOREGROUND_TAB)); + OpenApplication(AppLaunchParams( + browser()->profile(), extension, extensions::LAUNCH_CONTAINER_WINDOW, + NEW_FOREGROUND_TAB, extensions::SOURCE_UNTRACKED)); // Check that the new browser has an app name. // The launch should have created a new browser.
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc index 17a2f3d..104e580a 100644 --- a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc +++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
@@ -50,7 +50,7 @@ #include "ui/views/window/frame_background.h" #include "ui/views/window/window_shape.h" -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) #include "chrome/browser/ui/views/profiles/supervised_user_avatar_label.h" #endif @@ -227,7 +227,7 @@ // See if the point is within the avatar menu button. if (IsWithinAvatarMenuButtons(point)) return HTCLIENT; -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) // ...or within the avatar label, if it's a supervised user. if ((supervised_user_avatar_label() && supervised_user_avatar_label()->GetMirroredBounds().Contains(point)))
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc index ab96987..91f71c9 100644 --- a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc +++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc
@@ -14,7 +14,7 @@ #include "ui/views/controls/button/image_button.h" #include "ui/views/controls/label.h" -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) #include "chrome/browser/ui/views/profiles/supervised_user_avatar_label.h" #endif @@ -55,7 +55,7 @@ // Space between the edge of the avatar and the tabstrip. const int kAvatarInnerSpacing = 4; -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) // Space between the trailing edge of the avatar label and the tabstrip. const int kSupervisedUserAvatarLabelInnerSpacing = 10; #endif @@ -120,7 +120,7 @@ close_button_(nullptr), window_icon_(nullptr), window_title_(nullptr), -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) supervised_user_avatar_label_(nullptr), #endif avatar_button_(nullptr), @@ -153,7 +153,7 @@ int leading_tabstrip_indent = kTabStripIndent; if (delegate_->ShouldShowAvatar() && !ShouldAvatarBeOnRight()) { -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) if (supervised_user_avatar_label_ && supervised_user_avatar_label_->bounds().width()) leading_tabstrip_indent += kSupervisedUserAvatarLabelInnerSpacing; @@ -444,7 +444,7 @@ avatar_button_->SetBoundsRect(avatar_bounds_); int edge_offset; -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) if (supervised_user_avatar_label_) { supervised_user_avatar_label_->SetLabelOnRight(avatar_on_right); // Space between the bottom of the avatar and the bottom of the avatar @@ -647,7 +647,7 @@ } window_title_ = static_cast<views::Label*>(view); break; -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) case VIEW_ID_SUPERVISED_USER_AVATAR_LABEL: supervised_user_avatar_label_ = static_cast<SupervisedUserAvatarLabel*>(view);
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.h b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.h index 17d13b6..30f3d97 100644 --- a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.h +++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.h
@@ -13,7 +13,7 @@ class NewAvatarButton; class OpaqueBrowserFrameViewLayoutDelegate; -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) class SupervisedUserAvatarLabel; #endif @@ -188,7 +188,7 @@ views::View* window_icon_; views::Label* window_title_; -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) SupervisedUserAvatarLabel* supervised_user_avatar_label_; #endif AvatarMenuButton* avatar_button_;
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout_unittest.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout_unittest.cc index ac200e0..51ae68c 100644 --- a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout_unittest.cc +++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout_unittest.cc
@@ -20,7 +20,7 @@ #include "ui/views/controls/label.h" #include "ui/views/test/views_test_base.h" -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) #include "chrome/browser/ui/views/profiles/supervised_user_avatar_label.h" #endif @@ -210,7 +210,7 @@ root_view_->AddChildView(menu_button_); } -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) void AddSupervisedUserAvatarLabel() { supervised_user_avatar_label_ = new SupervisedUserAvatarLabel(nullptr); supervised_user_avatar_label_->set_id(VIEW_ID_SUPERVISED_USER_AVATAR_LABEL); @@ -252,7 +252,7 @@ TabIconView* tab_icon_view_; views::Label* window_title_; -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) SupervisedUserAvatarLabel* supervised_user_avatar_label_; #endif AvatarMenuButton* menu_button_; @@ -478,7 +478,7 @@ EXPECT_EQ("261x73", layout_manager_->GetMinimumSize(kWidth).ToString()); } -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) TEST_F(OpaqueBrowserFrameViewLayoutTest, WindowWithAvatarWithButtonsOnLeft) { // Tests the layout of a chrome window with an avatar icon and caption buttons // on the left. The avatar icon should therefore be on the right.
diff --git a/chrome/browser/ui/views/frame/web_app_left_header_view_ash_unittest.cc b/chrome/browser/ui/views/frame/web_app_left_header_view_ash_unittest.cc index fe51e60..0354002 100644 --- a/chrome/browser/ui/views/frame/web_app_left_header_view_ash_unittest.cc +++ b/chrome/browser/ui/views/frame/web_app_left_header_view_ash_unittest.cc
@@ -6,11 +6,15 @@ #include "ash/frame/caption_buttons/frame_caption_button.h" #include "base/command_line.h" +#include "base/values.h" #include "chrome/browser/ui/toolbar/test_toolbar_model.h" #include "chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/frame/test_with_browser_view.h" #include "chrome/common/chrome_switches.h" +#include "extensions/browser/extension_registry.h" +#include "extensions/common/extension.h" +#include "extensions/common/manifest_constants.h" #include "grit/theme_resources.h" #include "ui/aura/window.h" #include "ui/views/controls/button/button.h" @@ -48,6 +52,23 @@ widget->non_client_view()->frame_view()); } + Browser* CreateBrowser(Profile* profile, + Browser::Type browser_type, + bool hosted_app, + chrome::HostDesktopType host_desktop_type, + BrowserWindow* browser_window) override { + RegisterExtension(profile); + + Browser::CreateParams params(profile, host_desktop_type); + params = Browser::CreateParams::CreateForApp("_crx_abc", + true /* trusted_source */, + gfx::Rect(), + profile, + host_desktop_type); + params.window = browser_window; + return new Browser(params); + } + protected: // Owned by the browser view. BrowserNonClientFrameViewAsh* frame_view_; @@ -56,6 +77,25 @@ TestToolbarModel* test_toolbar_model_; private: + void RegisterExtension(Profile* profile) { + base::DictionaryValue manifest; + manifest.SetString(extensions::manifest_keys::kName, "Test"); + manifest.SetString(extensions::manifest_keys::kVersion, "1"); + manifest.SetString(extensions::manifest_keys::kLaunchWebURL, + "http://www.google.com"); + + std::string error; + scoped_refptr<extensions::Extension> extension( + extensions::Extension::Create( + base::FilePath(), extensions::Manifest::UNPACKED, manifest, + extensions::Extension::NO_FLAGS, "abc", &error)); + + ASSERT_TRUE(extension.get()) << error; + + extensions::ExtensionRegistry::Get(profile)-> + AddEnabled(extension); + } + DISALLOW_COPY_AND_ASSIGN(WebAppLeftHeaderViewTest); };
diff --git a/chrome/browser/ui/views/global_error_bubble_view.cc b/chrome/browser/ui/views/global_error_bubble_view.cc index 6272f90..0a5cc07a0e 100644 --- a/chrome/browser/ui/views/global_error_bubble_view.cc +++ b/chrome/browser/ui/views/global_error_bubble_view.cc
@@ -8,6 +8,7 @@ #include "chrome/browser/ui/global_error/global_error.h" #include "chrome/browser/ui/global_error/global_error_service.h" #include "chrome/browser/ui/global_error/global_error_service_factory.h" +#include "chrome/browser/ui/views/elevation_icon_setter.h" #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/toolbar/toolbar_view.h" #include "ui/base/resource/resource_bundle.h" @@ -97,6 +98,8 @@ accept_button->SetStyle(views::Button::STYLE_BUTTON); accept_button->SetIsDefault(true); accept_button->set_tag(TAG_ACCEPT_BUTTON); + if (error_->ShouldAddElevationIconToAcceptButton()) + elevation_icon_setter_.reset(new ElevationIconSetter(accept_button.get())); base::string16 cancel_string(error_->GetBubbleViewCancelButtonLabel()); scoped_ptr<views::LabelButton> cancel_button; @@ -164,6 +167,9 @@ } GlobalErrorBubbleView::~GlobalErrorBubbleView() { + // |elevation_icon_setter_| references |accept_button_|, so make sure it is + // destroyed before |accept_button_|. + elevation_icon_setter_.reset(); } void GlobalErrorBubbleView::ButtonPressed(views::Button* sender,
diff --git a/chrome/browser/ui/views/global_error_bubble_view.h b/chrome/browser/ui/views/global_error_bubble_view.h index ffe097db..9cad1d3 100644 --- a/chrome/browser/ui/views/global_error_bubble_view.h +++ b/chrome/browser/ui/views/global_error_bubble_view.h
@@ -11,6 +11,7 @@ #include "ui/views/controls/button/button.h" class Browser; +class ElevationIconSetter; class GlobalErrorWithStandardBubble; class GlobalErrorBubbleView : public views::ButtonListener, @@ -37,6 +38,8 @@ Browser* browser_; base::WeakPtr<GlobalErrorWithStandardBubble> error_; + scoped_ptr<ElevationIconSetter> elevation_icon_setter_; + DISALLOW_COPY_AND_ASSIGN(GlobalErrorBubbleView); };
diff --git a/chrome/browser/ui/views/passwords/credentials_item_view.cc b/chrome/browser/ui/views/passwords/credentials_item_view.cc index 568542c..cb57f9d 100644 --- a/chrome/browser/ui/views/passwords/credentials_item_view.cc +++ b/chrome/browser/ui/views/passwords/credentials_item_view.cc
@@ -11,25 +11,102 @@ #include "grit/theme_resources.h" #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/image/image.h" +#include "ui/views/border.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/controls/label.h" namespace { -const int kButtonHeight = 50; +const int kIconSize = 50; +// The default spacing between the icon and text. +const int kSpacing = 5; + +gfx::Size GetTextLabelsSize(const views::Label* full_name_label, + const views::Label* username_label) { + gfx::Size full_name = full_name_label->GetPreferredSize(); + gfx::Size username = username_label ? username_label->GetPreferredSize() : + gfx::Size(); + return gfx::Size(std::max(full_name.width(), username.width()), + full_name.height() + username.height()); } +} // namespace CredentialsItemView::CredentialsItemView(views::ButtonListener* button_listener, const autofill::PasswordForm& form) - : LabelButton(button_listener, form.username_value), + : LabelButton(button_listener, base::string16()), form_(form) { - SetMinSize(gfx::Size(0, kButtonHeight)); + set_notify_enter_exit_on_child(true); + // Create an image-view for the avatar. Make sure it ignores events so that + // the parent can receive the events instead. + image_view_ = new views::ImageView; + image_view_->set_interactive(false); + // TODO(vasilii): temporary code below shows the built-in profile icon instead // of avatar. const ProfileInfoCache& cache = g_browser_process->profile_manager()->GetProfileInfoCache(); const gfx::Image& image = cache.GetAvatarIconOfProfileAtIndex(0); - SetImage(STATE_NORMAL, *profiles::GetSizedAvatarIcon( - image, true, kButtonHeight, kButtonHeight).ToImageSkia()); + image_view_->SetImage(profiles::GetSizedAvatarIcon( + image, true, kIconSize, kIconSize).ToImageSkia()); + AddChildView(image_view_); + + // Add a label to show the full name. + // TODO(vasilii): temporarily the label shows username. + ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); + full_name_label_ = new views::Label( + form_.username_value, rb->GetFontList(ui::ResourceBundle::BoldFont)); + full_name_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); + AddChildView(full_name_label_); + + // Add a label to show the user name. + username_label_ = new views::Label( + form_.username_value, rb->GetFontList(ui::ResourceBundle::SmallFont)); + username_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); + username_label_->SetEnabled(false); + AddChildView(username_label_); + SetFocusable(true); } CredentialsItemView::~CredentialsItemView() { } + +gfx::Size CredentialsItemView::GetPreferredSize() const { + gfx::Size labels_size = GetTextLabelsSize(full_name_label_, username_label_); + gfx::Size size = gfx::Size(kIconSize + labels_size.width(), + std::max(kIconSize, labels_size.height())); + const gfx::Insets insets(GetInsets()); + size.Enlarge(insets.width(), insets.height()); + size.Enlarge(kSpacing, 0); + + // Make the size at least as large as the minimum size needed by the border. + size.SetToMax(border() ? border()->GetMinimumSize() : gfx::Size()); + return size; +} + +int CredentialsItemView::GetHeightForWidth(int w) const { + return View::GetHeightForWidth(w); +} + +void CredentialsItemView::Layout() { + gfx::Rect child_area(GetChildAreaBounds()); + child_area.Inset(GetInsets()); + + gfx::Size image_size(image_view_->GetPreferredSize()); + image_size.SetToMin(child_area.size()); + gfx::Point image_origin(child_area.origin()); + image_origin.Offset(0, (child_area.height() - image_size.height()) / 2); + image_view_->SetBoundsRect(gfx::Rect(image_origin, image_size)); + + gfx::Size full_name_size = full_name_label_->GetPreferredSize(); + gfx::Size username_size = + username_label_ ? username_label_->GetPreferredSize() : gfx::Size(); + int y_offset = (child_area.height() - + (full_name_size.height() + username_size.height())) / 2; + gfx::Point label_origin(image_origin.x() + image_size.width() + kSpacing, + child_area.origin().y() + y_offset); + full_name_label_->SetBoundsRect(gfx::Rect(label_origin, full_name_size)); + if (username_label_) { + label_origin.Offset(0, full_name_size.height()); + username_label_->SetBoundsRect(gfx::Rect(label_origin, username_size)); + } +}
diff --git a/chrome/browser/ui/views/passwords/credentials_item_view.h b/chrome/browser/ui/views/passwords/credentials_item_view.h index a2aecaea..4ff70a11 100644 --- a/chrome/browser/ui/views/passwords/credentials_item_view.h +++ b/chrome/browser/ui/views/passwords/credentials_item_view.h
@@ -9,6 +9,11 @@ #include "components/autofill/core/common/password_form.h" #include "ui/views/controls/button/label_button.h" +namespace views { +class ImageView; +class Label; +} + // CredentialsItemView represents a credential view in the account chooser // bubble. class CredentialsItemView : public views::LabelButton { @@ -20,8 +25,17 @@ const autofill::PasswordForm& form() const { return form_; } private: + // views::LabelButton: + gfx::Size GetPreferredSize() const override; + int GetHeightForWidth(int w) const override; + void Layout() override; + autofill::PasswordForm form_; + views::ImageView* image_view_; + views::Label* full_name_label_; + views::Label* username_label_; + DISALLOW_COPY_AND_ASSIGN(CredentialsItemView); };
diff --git a/chrome/browser/ui/views/profiles/avatar_menu_button.cc b/chrome/browser/ui/views/profiles/avatar_menu_button.cc index bad06f4..3100a62 100644 --- a/chrome/browser/ui/views/profiles/avatar_menu_button.cc +++ b/chrome/browser/ui/views/profiles/avatar_menu_button.cc
@@ -111,8 +111,9 @@ #if !defined(OS_CHROMEOS) bool is_badge_rectangle = false; // The taskbar badge should be the profile avatar, not the OTR avatar. - profiles::GetTransparentBackgroundProfileAvatar( - profile->GetPath(), taskbar_badge_avatar, &is_badge_rectangle); + AvatarMenu::GetImageForMenuButton(profile->GetPath(), + taskbar_badge_avatar, + &is_badge_rectangle); #endif } else if (should_show_avatar_menu) { ProfileInfoCache& cache = @@ -127,15 +128,17 @@ // this function will only be called for badging the taskbar icon. The // function can be renamed to something like GetAvatarImageForBadging() // and only needs to return the avatar from - // profiles::GetTransparentBackgroundProfileAvatar. + // AvatarMenu::GetImageForMenuButton(). #if !defined(OS_CHROMEOS) bool is_badge_rectangle = false; - profiles::GetTransparentBackgroundProfileAvatar( - profile->GetPath(), taskbar_badge_avatar, &is_badge_rectangle); + AvatarMenu::GetImageForMenuButton(profile->GetPath(), + taskbar_badge_avatar, + &is_badge_rectangle); #endif } else { - profiles::GetTransparentBackgroundProfileAvatar( - profile->GetPath(), avatar, is_rectangle); + AvatarMenu::GetImageForMenuButton(profile->GetPath(), + avatar, + is_rectangle); } } return true;
diff --git a/chrome/browser/ui/views/select_file_dialog_extension_browsertest.cc b/chrome/browser/ui/views/select_file_dialog_extension_browsertest.cc index 40c51672..81a7b7f 100644 --- a/chrome/browser/ui/views/select_file_dialog_extension_browsertest.cc +++ b/chrome/browser/ui/views/select_file_dialog_extension_browsertest.cc
@@ -279,7 +279,7 @@ // waiting for chrome.test.sendMessage('selection-change-complete'). ASSERT_NO_FATAL_FAILURE(OpenDialog(ui::SelectFileDialog::SELECT_OPEN_FILE, test_file, owning_window, - "selection-change-complete")); + "dialog-ready")); // Click open button. CloseDialog(DIALOG_BTN_OK, owning_window); @@ -305,7 +305,7 @@ // chrome.test.sendMessage(). ASSERT_NO_FATAL_FAILURE(OpenDialog(ui::SelectFileDialog::SELECT_SAVEAS_FILE, test_file, owning_window, - "directory-change-complete")); + "dialog-ready")); // Click save button. CloseDialog(DIALOG_BTN_OK, owning_window);
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc index 4a9423f..c4cab6c 100644 --- a/chrome/browser/ui/views/tabs/tab_strip.cc +++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -58,6 +58,7 @@ #include "ui/views/window/non_client_view.h" #if defined(OS_WIN) +#include "ui/gfx/win/dpi.h" #include "ui/gfx/win/hwnd_util.h" #include "ui/views/widget/monitor_win.h" #include "ui/views/win/hwnd_util.h" @@ -297,6 +298,7 @@ if (event.IsOnlyRightMouseButton()) { gfx::Point point = event.location(); views::View::ConvertPointToScreen(this, &point); + point = gfx::win::DIPToScreenPoint(point); bool destroyed = false; destroyed_ = &destroyed; gfx::ShowSystemMenuAtPoint(views::HWNDForView(this), point);
diff --git a/chrome/browser/ui/views/toolbar/browser_action_test_util_views.cc b/chrome/browser/ui/views/toolbar/browser_action_test_util_views.cc index 85a8dab7..8a03938f 100644 --- a/chrome/browser/ui/views/toolbar/browser_action_test_util_views.cc +++ b/chrome/browser/ui/views/toolbar/browser_action_test_util_views.cc
@@ -23,7 +23,10 @@ namespace { -BrowserActionsContainer* GetContainer(Browser* browser) { +BrowserActionsContainer* GetContainer(Browser* browser, + ToolbarActionsBarDelegate* bar_delegate) { + if (bar_delegate) + return static_cast<BrowserActionsContainer*>(bar_delegate); return browser->window()->GetBrowserWindowTesting()->GetToolbarView()-> browser_actions(); } @@ -31,15 +34,15 @@ } // namespace int BrowserActionTestUtil::NumberOfBrowserActions() { - return GetContainer(browser_)->num_toolbar_actions(); + return GetContainer(browser_, bar_delegate_)->num_toolbar_actions(); } int BrowserActionTestUtil::VisibleBrowserActions() { - return GetContainer(browser_)->VisibleBrowserActions(); + return GetContainer(browser_, bar_delegate_)->VisibleBrowserActions(); } bool BrowserActionTestUtil::IsChevronShowing() { - BrowserActionsContainer* container = GetContainer(browser_); + BrowserActionsContainer* container = GetContainer(browser_, bar_delegate_); gfx::Size visible_size = container->GetVisibleBounds().size(); return container->chevron() && container->chevron()->visible() && @@ -50,55 +53,56 @@ void BrowserActionTestUtil::InspectPopup(int index) { ToolbarActionView* view = - GetContainer(browser_)->GetToolbarActionViewAt(index); + GetContainer(browser_, bar_delegate_)->GetToolbarActionViewAt(index); static_cast<ExtensionActionViewController*>(view->view_controller())-> InspectPopup(); } bool BrowserActionTestUtil::HasIcon(int index) { - return !GetContainer(browser_)->GetToolbarActionViewAt(index)-> + return !GetContainer(browser_, bar_delegate_)->GetToolbarActionViewAt(index)-> GetImage(views::Button::STATE_NORMAL).isNull(); } gfx::Image BrowserActionTestUtil::GetIcon(int index) { - gfx::ImageSkia icon = GetContainer(browser_)->GetToolbarActionViewAt(index)-> - GetIconForTest(); + gfx::ImageSkia icon = + GetContainer(browser_, bar_delegate_)->GetToolbarActionViewAt(index)-> + GetIconForTest(); return gfx::Image(icon); } void BrowserActionTestUtil::Press(int index) { - GetContainer(browser_)->GetToolbarActionViewAt(index)-> + GetContainer(browser_, bar_delegate_)->GetToolbarActionViewAt(index)-> view_controller()->ExecuteAction(true); } std::string BrowserActionTestUtil::GetExtensionId(int index) { - return GetContainer(browser_)->GetToolbarActionViewAt(index)-> + return GetContainer(browser_, bar_delegate_)->GetToolbarActionViewAt(index)-> view_controller()->GetId(); } std::string BrowserActionTestUtil::GetTooltip(int index) { base::string16 text; - GetContainer(browser_)->GetToolbarActionViewAt(index)-> + GetContainer(browser_, bar_delegate_)->GetToolbarActionViewAt(index)-> GetTooltipText(gfx::Point(), &text); return base::UTF16ToUTF8(text); } gfx::NativeView BrowserActionTestUtil::GetPopupNativeView() { - return GetContainer(browser_)->TestGetPopup(); + return GetContainer(browser_, bar_delegate_)->TestGetPopup(); } bool BrowserActionTestUtil::HasPopup() { - return GetContainer(browser_)->TestGetPopup() != NULL; + return GetContainer(browser_, bar_delegate_)->TestGetPopup() != NULL; } gfx::Size BrowserActionTestUtil::GetPopupSize() { - gfx::NativeView popup = GetContainer(browser_)->TestGetPopup(); + gfx::NativeView popup = GetContainer(browser_, bar_delegate_)->TestGetPopup(); views::Widget* widget = views::Widget::GetWidgetForNativeView(popup); return widget->GetWindowBoundsInScreen().size(); } bool BrowserActionTestUtil::HidePopup() { - GetContainer(browser_)->HideActivePopup(); + GetContainer(browser_, bar_delegate_)->HideActivePopup(); return !HasPopup(); }
diff --git a/chrome/browser/ui/views/toolbar/browser_actions_container.cc b/chrome/browser/ui/views/toolbar/browser_actions_container.cc index 1f04108..31b3456 100644 --- a/chrome/browser/ui/views/toolbar/browser_actions_container.cc +++ b/chrome/browser/ui/views/toolbar/browser_actions_container.cc
@@ -727,7 +727,8 @@ return; if (details.is_add && details.child == this) { - if (!in_overflow_mode()) { // We only need one keybinding registry. + if (!in_overflow_mode() && // We only need one keybinding registry. + parent()->GetFocusManager()) { // focus manager can be null in tests. extension_keybinding_registry_.reset(new ExtensionKeybindingRegistryViews( browser_->profile(), parent()->GetFocusManager(),
diff --git a/chrome/browser/ui/views/toolbar/component_toolbar_actions_browsertest.cc b/chrome/browser/ui/views/toolbar/component_toolbar_actions_browsertest.cc index 3625872..6b840d3 100644 --- a/chrome/browser/ui/views/toolbar/component_toolbar_actions_browsertest.cc +++ b/chrome/browser/ui/views/toolbar/component_toolbar_actions_browsertest.cc
@@ -50,6 +50,9 @@ bool IsEnabled(content::WebContents* web_contents) const override { return true; } + bool WantsToRun(content::WebContents* web_contents) const override { + return false; + } bool HasPopup(content::WebContents* web_contents) const override { return true; }
diff --git a/chrome/browser/ui/views/toolbar/test_toolbar_actions_bar_helper_views.cc b/chrome/browser/ui/views/toolbar/test_toolbar_actions_bar_helper_views.cc new file mode 100644 index 0000000..3c790a2 --- /dev/null +++ b/chrome/browser/ui/views/toolbar/test_toolbar_actions_bar_helper_views.cc
@@ -0,0 +1,55 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/toolbar/test_toolbar_actions_bar_helper.h" + +#include "chrome/browser/ui/views/toolbar/browser_actions_container.h" +#include "ui/views/view.h" + +namespace { + +// The views-specific implementation of the TestToolbarActionsBarHelper, which +// creates and owns a BrowserActionsContainer. +class TestToolbarActionsBarHelperViews : public TestToolbarActionsBarHelper { + public: + explicit TestToolbarActionsBarHelperViews(Browser* browser); + ~TestToolbarActionsBarHelperViews() override; + + private: + // TestToolbarActionsBarHelper: + ToolbarActionsBar* GetToolbarActionsBar() override; + + // The parent of the BrowserActionsContainer, which directly owns the + // container as part of the views hierarchy. + views::View container_parent_; + + // The created BrowserActionsContainer. Owned by |container_parent_|. + BrowserActionsContainer* browser_actions_container_; + + DISALLOW_COPY_AND_ASSIGN(TestToolbarActionsBarHelperViews); +}; + +TestToolbarActionsBarHelperViews::TestToolbarActionsBarHelperViews( + Browser* browser) + : browser_actions_container_( + new BrowserActionsContainer(browser, nullptr)) { + // The BrowserActionsContainer expects to have a parent (and be added to the + // view hierarchy), so wrap it in a shell view. + container_parent_.set_owned_by_client(); + container_parent_.AddChildView(browser_actions_container_); +} + +TestToolbarActionsBarHelperViews::~TestToolbarActionsBarHelperViews() {} + +ToolbarActionsBar* TestToolbarActionsBarHelperViews::GetToolbarActionsBar() { + return browser_actions_container_->toolbar_actions_bar(); +} + +} // namespace + +// static +scoped_ptr<TestToolbarActionsBarHelper> +TestToolbarActionsBarHelper::Create(Browser* browser) { + return make_scoped_ptr(new TestToolbarActionsBarHelperViews(browser)); +}
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.cc b/chrome/browser/ui/views/toolbar/toolbar_view.cc index 3385884..dd44218 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_view.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_view.cc
@@ -74,6 +74,7 @@ #include "ui/views/window/non_client_view.h" #if defined(OS_WIN) +#include "chrome/browser/recovery/recovery_install_global_error_factory.h" #include "chrome/browser/ui/views/conflicting_module_view_win.h" #include "chrome/browser/ui/views/critical_notification_bubble_view.h" #endif @@ -234,7 +235,7 @@ LoadImages(); - // Start global error services now so we badge the menu correctly in non-Ash. + // Start global error services now so we badge the menu correctly. #if !defined(OS_CHROMEOS) if (!HasAshShell()) { SigninGlobalErrorFactory::GetForProfile(browser_->profile()); @@ -242,6 +243,10 @@ SyncGlobalErrorFactory::GetForProfile(browser_->profile()); #endif } + +#if defined(OS_WIN) + RecoveryInstallGlobalErrorFactory::GetForProfile(browser_->profile()); +#endif #endif // OS_CHROMEOS // Add any necessary badges to the menu item based on the system state.
diff --git a/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc index b25aa16..add8c88 100644 --- a/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc
@@ -15,6 +15,7 @@ #include "chrome/browser/extensions/component_loader.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/profiles/profile_manager.h" +#include "chrome/browser/ui/extensions/app_launch_params.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/browser/ui/webui/chromeos/login/native_window_delegate.h" #include "chrome/browser/ui/webui/chromeos/login/network_state_informer.h" @@ -28,6 +29,7 @@ #include "chromeos/network/portal_detector/network_portal_detector_strategy.h" #include "components/user_manager/user_manager.h" #include "extensions/browser/extension_system.h" +#include "extensions/common/constants.h" #include "grit/browser_resources.h" #include "ui/strings/grit/ui_strings.h" @@ -218,9 +220,9 @@ const extensions::Extension* extension = extension_service-> GetExtensionById(extension_id, true); - OpenApplication(AppLaunchParams(profile, extension, - extensions::LAUNCH_CONTAINER_WINDOW, - NEW_WINDOW)); + OpenApplication( + AppLaunchParams(profile, extension, extensions::LAUNCH_CONTAINER_WINDOW, + NEW_WINDOW, extensions::SOURCE_CHROME_INTERNAL)); InitAppSession(profile, extension_id); user_manager::UserManager::Get()->SessionStarted();
diff --git a/chrome/browser/ui/webui/extensions/extension_settings_handler.cc b/chrome/browser/ui/webui/extensions/extension_settings_handler.cc index 1d4b6f7..0c3d3db 100644 --- a/chrome/browser/ui/webui/extensions/extension_settings_handler.cc +++ b/chrome/browser/ui/webui/extensions/extension_settings_handler.cc
@@ -49,6 +49,7 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/extensions/app_launch_params.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/browser/ui/webui/extensions/extension_basic_info.h" #include "chrome/browser/ui/webui/extensions/extension_icon_source.h" @@ -1029,7 +1030,8 @@ extension_service_->GetExtensionById(extension_id, false); OpenApplication(AppLaunchParams(extension_service_->profile(), extension, extensions::LAUNCH_CONTAINER_WINDOW, - NEW_WINDOW)); + NEW_WINDOW, + extensions::SOURCE_EXTENSIONS_PAGE)); } void ExtensionSettingsHandler::HandleReloadMessage(
diff --git a/chrome/browser/ui/webui/help/version_updater_win.cc b/chrome/browser/ui/webui/help/version_updater_win.cc index 449ef19..46253f6a 100644 --- a/chrome/browser/ui/webui/help/version_updater_win.cc +++ b/chrome/browser/ui/webui/help/version_updater_win.cc
@@ -20,6 +20,7 @@ #include "chrome/installer/util/install_util.h" #include "content/public/browser/browser_thread.h" #include "ui/base/l10n/l10n_util.h" +#include "ui/gfx/native_widget_types.h" #include "ui/views/widget/widget.h" using content::BrowserThread; @@ -28,8 +29,7 @@ // Windows implementation of version update functionality, used by the WebUI // About/Help page. -class VersionUpdaterWin : public VersionUpdater, - public GoogleUpdateStatusListener { +class VersionUpdaterWin : public VersionUpdater { private: friend class VersionReader; friend class VersionUpdater; @@ -42,11 +42,11 @@ virtual void CheckForUpdate(const StatusCallback& callback) override; virtual void RelaunchBrowser() const override; - // GoogleUpdateStatusListener implementation. - virtual void OnReportResults(GoogleUpdateUpgradeResult result, - GoogleUpdateErrorCode error_code, - const base::string16& error_message, - const base::string16& version) override; + // chrome::UpdateCheckCallback. + void OnUpdateCheckResults(GoogleUpdateUpgradeResult result, + GoogleUpdateErrorCode error_code, + const base::string16& error_message, + const base::string16& version); // Update the UI to show the status of the upgrade. void UpdateStatus(GoogleUpdateUpgradeResult result, @@ -57,18 +57,10 @@ // result case can now be completeb on the UI thread. void GotInstalledVersion(const Version& version); - // Little helper function to create google_updater_. - void CreateGoogleUpdater(); - - // Helper function to clear google_updater_. - void ClearGoogleUpdater(); - // Returns a window that can be used for elevation. - HWND GetElevationParent(); + gfx::AcceleratedWidget GetElevationParent(); - // The class that communicates with Google Update to find out if an update is - // available and asks it to start an upgrade. - scoped_refptr<GoogleUpdate> google_updater_; + void BeginUpdateCheckOnFileThread(bool install_if_newer); // Used for callbacks. base::WeakPtrFactory<VersionUpdaterWin> weak_factory_; @@ -122,13 +114,9 @@ VersionUpdaterWin::VersionUpdaterWin() : weak_factory_(this) { - CreateGoogleUpdater(); } VersionUpdaterWin::~VersionUpdaterWin() { - // The Google Updater will hold a pointer to the listener until it reports - // status, so that pointer must be cleared when the listener is destoyed. - ClearGoogleUpdater(); } void VersionUpdaterWin::CheckForUpdate(const StatusCallback& callback) { @@ -142,13 +130,10 @@ if (!(base::win::GetVersion() == base::win::VERSION_VISTA && (base::win::OSInfo::GetInstance()->service_pack().major == 0) && !base::win::UserAccountControlIsEnabled())) { - // This could happen if the page got refreshed after results were returned. - if (!google_updater_.get()) - CreateGoogleUpdater(); UpdateStatus(UPGRADE_CHECK_STARTED, GOOGLE_UPDATE_NO_ERROR, base::string16()); // Specify false to not upgrade yet. - google_updater_->CheckForUpdate(false, GetElevationParent()); + BeginUpdateCheckOnFileThread(false); } } @@ -156,11 +141,11 @@ chrome::AttemptRestart(); } -void VersionUpdaterWin::OnReportResults( - GoogleUpdateUpgradeResult result, GoogleUpdateErrorCode error_code, - const base::string16& error_message, const base::string16& version) { - // Drop the last reference to the object so that it gets cleaned up here. - ClearGoogleUpdater(); +void VersionUpdaterWin::OnUpdateCheckResults( + GoogleUpdateUpgradeResult result, + GoogleUpdateErrorCode error_code, + const base::string16& error_message, + const base::string16& version) { UpdateStatus(result, error_code, error_message); } @@ -184,11 +169,9 @@ break; } case UPGRADE_IS_AVAILABLE: { - DCHECK(!google_updater_.get()); // Should have been nulled out already. - CreateGoogleUpdater(); UpdateStatus(UPGRADE_STARTED, GOOGLE_UPDATE_NO_ERROR, base::string16()); // Specify true to upgrade now. - google_updater_->CheckForUpdate(true, GetElevationParent()); + BeginUpdateCheckOnFileThread(true); return; } case UPGRADE_ALREADY_UP_TO_DATE: { @@ -252,19 +235,6 @@ base::string16()); } -void VersionUpdaterWin::CreateGoogleUpdater() { - ClearGoogleUpdater(); - google_updater_ = new GoogleUpdate(); - google_updater_->set_status_listener(this); -} - -void VersionUpdaterWin::ClearGoogleUpdater() { - if (google_updater_.get()) { - google_updater_->set_status_listener(NULL); - google_updater_ = NULL; - } -} - BOOL CALLBACK WindowEnumeration(HWND window, LPARAM param) { if (IsWindowVisible(window)) { HWND* returned_window = reinterpret_cast<HWND*>(param); @@ -274,7 +244,7 @@ return TRUE; } -HWND VersionUpdaterWin::GetElevationParent() { +gfx::AcceleratedWidget VersionUpdaterWin::GetElevationParent() { // Look for a visible window belonging to the UI thread. DCHECK_CURRENTLY_ON(BrowserThread::UI); HWND window = NULL; @@ -290,6 +260,15 @@ return window; } +void VersionUpdaterWin::BeginUpdateCheckOnFileThread(bool install_if_newer) { + scoped_refptr<base::TaskRunner> task_runner( + content::BrowserThread::GetMessageLoopProxyForThread( + content::BrowserThread::FILE)); + BeginUpdateCheck(task_runner, install_if_newer, GetElevationParent(), + base::Bind(&VersionUpdaterWin::OnUpdateCheckResults, + weak_factory_.GetWeakPtr())); +} + } // namespace VersionUpdater* VersionUpdater::Create(content::BrowserContext* /* context */) {
diff --git a/chrome/browser/ui/webui/history_ui.cc b/chrome/browser/ui/webui/history_ui.cc index 4210158..a4340a1 100644 --- a/chrome/browser/ui/webui/history_ui.cc +++ b/chrome/browser/ui/webui/history_ui.cc
@@ -61,7 +61,7 @@ #include "chrome/browser/extensions/activity_log/activity_log.h" #endif -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) #include "chrome/browser/supervised_user/supervised_user_navigation_observer.h" #include "chrome/browser/supervised_user/supervised_user_service.h" #include "chrome/browser/supervised_user/supervised_user_service_factory.h" @@ -382,7 +382,7 @@ result->SetString("deviceName", device_name); result->SetString("deviceType", device_type); -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) if (supervised_user_service) { const SupervisedUserURLFilter* url_filter = supervised_user_service->GetURLFilterForUIThread(); @@ -729,7 +729,7 @@ Profile* profile = Profile::FromWebUI(web_ui()); BookmarkModel* bookmark_model = BookmarkModelFactory::GetForProfile(profile); SupervisedUserService* supervised_user_service = NULL; -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) if (profile->IsSupervised()) supervised_user_service = SupervisedUserServiceFactory::GetForProfile(profile);
diff --git a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc index 8389d98..c9c973b 100644 --- a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc +++ b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
@@ -30,6 +30,7 @@ #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_tabstrip.h" #include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/extensions/app_launch_params.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/browser/ui/extensions/extension_enable_flow.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" @@ -520,12 +521,11 @@ disposition == NEW_WINDOW) { // TODO(jamescook): Proper support for background tabs. AppLaunchParams params(profile, extension, - disposition == NEW_WINDOW ? - extensions::LAUNCH_CONTAINER_WINDOW : - extensions::LAUNCH_CONTAINER_TAB, - disposition); + disposition == NEW_WINDOW + ? extensions::LAUNCH_CONTAINER_WINDOW + : extensions::LAUNCH_CONTAINER_TAB, + disposition, extensions::SOURCE_NEW_TAB_PAGE); params.override_url = GURL(url); - params.source = extensions::SOURCE_NEW_TAB_PAGE; OpenApplication(params); } else { // To give a more "launchy" experience when using the NTP launcher, we close @@ -537,9 +537,9 @@ old_contents = browser->tab_strip_model()->GetActiveWebContents(); AppLaunchParams params(profile, extension, - old_contents ? CURRENT_TAB : NEW_FOREGROUND_TAB); + old_contents ? CURRENT_TAB : NEW_FOREGROUND_TAB, + extensions::SOURCE_NEW_TAB_PAGE); params.override_url = GURL(url); - params.source = extensions::SOURCE_NEW_TAB_PAGE; WebContents* new_contents = OpenApplication(params); // This will also destroy the handler, so do not perform any actions after.
diff --git a/chrome/browser/ui/webui/options/browser_options_handler.cc b/chrome/browser/ui/webui/options/browser_options_handler.cc index 6b5a18b..d7c47ca 100644 --- a/chrome/browser/ui/webui/options/browser_options_handler.cc +++ b/chrome/browser/ui/webui/options/browser_options_handler.cc
@@ -1722,17 +1722,14 @@ if (retrain) { DCHECK(profile->GetPrefs()->GetBoolean( prefs::kHotwordAlwaysOnSearchEnabled)); - DCHECK(profile->GetPrefs()->GetBoolean( - prefs::kHotwordAudioHistoryEnabled)); launch_mode = HotwordService::RETRAIN; + // TODO(rlp): Make sure the Chrome Audio History pref is synced + // to the account-level Audio History setting from footprints. } else if (profile->GetPrefs()->GetBoolean( prefs::kHotwordAudioHistoryEnabled)) { DCHECK(!profile->GetPrefs()->GetBoolean( prefs::kHotwordAlwaysOnSearchEnabled)); - - // TODO(kcarattini): Make sure the Chrome Audio History pref is synced - // to the account-level Audio History setting from footprints. launch_mode = HotwordService::HOTWORD_ONLY; } else { DCHECK(!profile->GetPrefs()->GetBoolean(
diff --git a/chrome/browser/ui/webui/options/create_profile_handler.cc b/chrome/browser/ui/webui/options/create_profile_handler.cc index 9c4a88d..1305354b 100644 --- a/chrome/browser/ui/webui/options/create_profile_handler.cc +++ b/chrome/browser/ui/webui/options/create_profile_handler.cc
@@ -23,7 +23,7 @@ #include "content/public/browser/web_ui.h" #include "ui/base/l10n/l10n_util.h" -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) #include "chrome/browser/supervised_user/supervised_user_registration_utility.h" #include "chrome/browser/supervised_user/supervised_user_service.h" #include "chrome/browser/supervised_user/supervised_user_service_factory.h" @@ -39,7 +39,7 @@ } CreateProfileHandler::~CreateProfileHandler() { -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) // Cancellation is only supported for supervised users. CancelProfileRegistration(false); #endif @@ -50,7 +50,7 @@ } void CreateProfileHandler::RegisterMessages() { -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) // Cancellation is only supported for supervised users. web_ui()->RegisterMessageCallback( "cancelCreateProfile", @@ -64,7 +64,7 @@ } void CreateProfileHandler::CreateProfile(const base::ListValue* args) { -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) // This handler could have been called for a supervised user, for example // because the user fiddled with the web inspector. Silently return. if (Profile::FromWebUI(web_ui())->IsSupervised()) @@ -94,7 +94,7 @@ args->GetBoolean(2, &create_shortcut); } std::string supervised_user_id; -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) if (!ProcessSupervisedCreateProfileArgs(args, &supervised_user_id)) return; #endif @@ -158,7 +158,7 @@ CreateShortcutAndShowSuccess(create_shortcut, desktop_type, profile); break; } -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) case SUPERVISED_PROFILE_CREATION: case SUPERVISED_PROFILE_IMPORT: RegisterSupervisedUser(create_shortcut, desktop_type, @@ -190,7 +190,7 @@ dict.SetString("name", profile->GetPrefs()->GetString(prefs::kProfileName)); dict.Set("filePath", base::CreateFilePathValue(profile->GetPath())); -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) bool is_supervised = profile_creation_type_ == SUPERVISED_PROFILE_CREATION || profile_creation_type_ == SUPERVISED_PROFILE_IMPORT; @@ -205,7 +205,7 @@ // new non-supervised user profile we don't show any confirmation, so open // the new window now. bool should_open_new_window = true; -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) if (profile_creation_type_ == SUPERVISED_PROFILE_CREATION) should_open_new_window = false; #endif @@ -247,7 +247,7 @@ base::string16 CreateProfileHandler::GetProfileCreationErrorMessageLocal() const { int message_id = IDS_PROFILES_CREATE_LOCAL_ERROR; -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) // Local errors can occur during supervised profile import. if (profile_creation_type_ == SUPERVISED_PROFILE_IMPORT) message_id = IDS_SUPERVISED_USER_IMPORT_LOCAL_ERROR; @@ -255,7 +255,7 @@ return l10n_util::GetStringUTF16(message_id); } -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) base::string16 CreateProfileHandler::GetProfileCreationErrorMessageRemote() const { return l10n_util::GetStringUTF16( @@ -276,7 +276,7 @@ std::string CreateProfileHandler::GetJavascriptMethodName( ProfileCreationStatus status) const { switch (profile_creation_type_) { -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) case SUPERVISED_PROFILE_IMPORT: switch (status) { case PROFILE_CREATION_SUCCESS: @@ -300,7 +300,7 @@ return std::string(); } -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) bool CreateProfileHandler::ProcessSupervisedCreateProfileArgs( const base::ListValue* args, std::string* supervised_user_id) { bool supervised_user = false;
diff --git a/chrome/browser/ui/webui/options/create_profile_handler.h b/chrome/browser/ui/webui/options/create_profile_handler.h index cf1262b..6ee91ba 100644 --- a/chrome/browser/ui/webui/options/create_profile_handler.h +++ b/chrome/browser/ui/webui/options/create_profile_handler.h
@@ -19,7 +19,7 @@ class ListValue; } -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) class SupervisedUserRegistrationUtility; #endif @@ -49,7 +49,7 @@ // It is used to map the type of the profile creation operation to the // correct UMA metric name. enum ProfileCreationOperationType { -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) SUPERVISED_PROFILE_CREATION, SUPERVISED_PROFILE_IMPORT, #endif @@ -100,7 +100,7 @@ void RecordProfileCreationMetrics(Profile::CreateStatus status); base::string16 GetProfileCreationErrorMessageLocal() const; -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) // The following error messages only apply to supervised profiles. base::string16 GetProfileCreationErrorMessageRemote() const; base::string16 GetProfileCreationErrorMessageSignin() const; @@ -120,7 +120,7 @@ // The value is only relevant while we are creating/importing a profile. ProfileCreationOperationType profile_creation_type_; -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) // Extracts the supervised user ID from the args passed into CreateProfile, // sets |profile_creation_type_| if necessary, and returns true if the // supervised user id specified in |args| are valid.
diff --git a/chrome/browser/ui/webui/options/options_ui.cc b/chrome/browser/ui/webui/options/options_ui.cc index cd5a3e1..1678f09 100644 --- a/chrome/browser/ui/webui/options/options_ui.cc +++ b/chrome/browser/ui/webui/options/options_ui.cc
@@ -70,7 +70,7 @@ #include "ui/base/webui/web_ui_util.h" #include "url/gurl.h" -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) #include "chrome/browser/ui/webui/options/supervised_user_create_confirm_handler.h" #include "chrome/browser/ui/webui/options/supervised_user_import_handler.h" #include "chrome/browser/ui/webui/options/supervised_user_learn_more_handler.h" @@ -305,7 +305,7 @@ AddOptionsPageUIHandler(localized_strings, new SearchEngineManagerHandler()); AddOptionsPageUIHandler(localized_strings, new ImportDataHandler()); AddOptionsPageUIHandler(localized_strings, new StartupPagesHandler()); -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) AddOptionsPageUIHandler(localized_strings, new SupervisedUserCreateConfirmHandler()); AddOptionsPageUIHandler(localized_strings, new SupervisedUserImportHandler());
diff --git a/chrome/browser/ui/webui/signin/login_ui_test_utils.cc b/chrome/browser/ui/webui/signin/login_ui_test_utils.cc index 739e97c3..3c26e2e 100644 --- a/chrome/browser/ui/webui/signin/login_ui_test_utils.cc +++ b/chrome/browser/ui/webui/signin/login_ui_test_utils.cc
@@ -130,12 +130,17 @@ GURL signin_url = signin::GetPromoURL(signin::SOURCE_START_PAGE, false); DVLOG(1) << "Navigating to " << signin_url; - content::WindowedNotificationObserver observer( - content::NOTIFICATION_LOAD_STOP, - content::NotificationService::AllSources()); - ui_test_utils::NavigateToURL(browser, signin_url); - observer.Wait(); - // Wait until the signin page is ready. + // For some tests, the window is not shown yet and this might be the first tab + // navigation, so GetActiveWebContents() for CURRENT_TAB is NULL. That's why + // we use NEW_FOREGROUND_TAB rather than the CURRENT_TAB used by default in + // ui_test_utils::NavigateToURL(). + ui_test_utils::NavigateToURLWithDisposition( + browser, + signin_url, + NEW_FOREGROUND_TAB, + ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); + + DVLOG(1) << "Wait for login UI to be ready."; WaitUntilUIReady(browser); DVLOG(1) << "Sign in user: " << username; ExecuteJsToSigninInSigninFrame(browser, username, password);
diff --git a/chrome/browser/ui/zoom/chrome_zoom_level_otr_delegate.cc b/chrome/browser/ui/zoom/chrome_zoom_level_otr_delegate.cc new file mode 100644 index 0000000..79af1b8 --- /dev/null +++ b/chrome/browser/ui/zoom/chrome_zoom_level_otr_delegate.cc
@@ -0,0 +1,41 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/zoom/chrome_zoom_level_otr_delegate.h" + +#include "base/bind.h" +#include "chrome/browser/ui/zoom/zoom_event_manager.h" + +namespace chrome { + +ChromeZoomLevelOTRDelegate::ChromeZoomLevelOTRDelegate( + base::WeakPtr<ZoomEventManager> zoom_event_manager) + : zoom_event_manager_(zoom_event_manager), + host_zoom_map_(nullptr) { +} + +ChromeZoomLevelOTRDelegate::~ChromeZoomLevelOTRDelegate() { +} + +void ChromeZoomLevelOTRDelegate::InitHostZoomMap( + content::HostZoomMap* host_zoom_map) { + // This init function must be called only once. + DCHECK(!host_zoom_map_); + DCHECK(host_zoom_map); + host_zoom_map_ = host_zoom_map; + + zoom_subscription_ = host_zoom_map_->AddZoomLevelChangedCallback(base::Bind( + &ChromeZoomLevelOTRDelegate::OnZoomLevelChanged, base::Unretained(this))); +} + +void ChromeZoomLevelOTRDelegate::OnZoomLevelChanged( + const content::HostZoomMap::ZoomLevelChange& change) { + // If there's a manager to aggregate ZoomLevelChanged events, pass this event + // along. Since we already hold a subscription to our associated HostZoomMap, + // we don't need to create a separate subscription for this. + if (zoom_event_manager_) + zoom_event_manager_->OnZoomLevelChanged(change); +} + +} // namespace chrome
diff --git a/chrome/browser/ui/zoom/chrome_zoom_level_otr_delegate.h b/chrome/browser/ui/zoom/chrome_zoom_level_otr_delegate.h new file mode 100644 index 0000000..f76b2325 --- /dev/null +++ b/chrome/browser/ui/zoom/chrome_zoom_level_otr_delegate.h
@@ -0,0 +1,45 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_ZOOM_CHROME_ZOOM_LEVEL_OTR_DELEGATE_H_ +#define CHROME_BROWSER_UI_ZOOM_CHROME_ZOOM_LEVEL_OTR_DELEGATE_H_ + +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" +#include "content/public/browser/host_zoom_map.h" +#include "content/public/browser/zoom_level_delegate.h" + +class ZoomEventManager; + +namespace chrome { + +// This class is a light-weight version of ChromeZoomLevelPrefs and is used +// to connect an OTR StoragePartition's HostZoomMap to the OTR profile's +// ZoomEventManager. +class ChromeZoomLevelOTRDelegate : public content::ZoomLevelDelegate { + public: + ChromeZoomLevelOTRDelegate( + base::WeakPtr<ZoomEventManager> zoom_event_manager); + virtual ~ChromeZoomLevelOTRDelegate(); + + // content::ZoomLevelDelegate + void InitHostZoomMap(content::HostZoomMap* host_zoom_map) override; + + private: + // This is a callback function that receives notifications from HostZoomMap + // when per-host zoom levels change. It is used to update the per-host + // zoom levels (if any) managed by this class (for its associated partition). + void OnZoomLevelChanged(const content::HostZoomMap::ZoomLevelChange& change); + + base::WeakPtr<ZoomEventManager> zoom_event_manager_; + content::HostZoomMap* host_zoom_map_; + scoped_ptr<content::HostZoomMap::Subscription> zoom_subscription_; + + DISALLOW_COPY_AND_ASSIGN(ChromeZoomLevelOTRDelegate); +}; + +} // namespace chrome + +#endif // CHROME_BROWSER_UI_ZOOM_CHROME_ZOOM_LEVEL_OTR_DELEGATE_H_
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index a2929ee..a81d4e4 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi
@@ -738,6 +738,10 @@ 'browser/media_galleries/fileapi/safe_picasa_album_table_reader.h', 'browser/media_galleries/fileapi/safe_picasa_albums_indexer.cc', 'browser/media_galleries/fileapi/safe_picasa_albums_indexer.h', + 'browser/recovery/recovery_install_global_error.cc', + 'browser/recovery/recovery_install_global_error.h', + 'browser/recovery/recovery_install_global_error_factory.cc', + 'browser/recovery/recovery_install_global_error_factory.h', ], 'chrome_browser_extensions_sources': [ 'browser/accessibility/accessibility_extension_api.cc', @@ -1322,8 +1326,6 @@ 'chrome_browser_pref_sources': [ 'browser/prefs/browser_prefs.cc', 'browser/prefs/browser_prefs.h', - 'browser/prefs/browser_ui_prefs_migrator.cc', - 'browser/prefs/browser_ui_prefs_migrator.h', 'browser/prefs/chrome_pref_service_factory.cc', 'browser/prefs/chrome_pref_service_factory.h', 'browser/prefs/command_line_pref_store.cc', @@ -2309,6 +2311,7 @@ ], # Everything but Android, iOS, and CrOS. 'chrome_browser_desktop_sources': [ + 'browser/profiles/avatar_menu_desktop.cc', 'browser/profiles/avatar_menu_observer.h', 'browser/profiles/avatar_menu_actions_desktop.cc', 'browser/profiles/avatar_menu_actions_desktop.h', @@ -2779,7 +2782,7 @@ 'android/java/src/org/chromium/chrome/browser/JavascriptAppModalDialog.java', 'android/java/src/org/chromium/chrome/browser/NavigationPopup.java', 'android/java/src/org/chromium/chrome/browser/net/spdyproxy/DataReductionProxySettings.java', - 'android/java/src/org/chromium/chrome/browser/NotificationUIManager.java', + 'android/java/src/org/chromium/chrome/browser/notifications/NotificationUIManager.java', 'android/java/src/org/chromium/chrome/browser/omnibox/AnswersImage.java', 'android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteController.java', 'android/java/src/org/chromium/chrome/browser/omnibox/OmniboxPrerender.java', @@ -3465,10 +3468,10 @@ '../ui/app_list/app_list.gyp:app_list', ] }], - ['enable_managed_users==1', { + ['enable_supervised_users==1', { 'sources': [ '<@(chrome_browser_supervised_user_sources)' ], }], - ['enable_managed_users==1 and enable_themes==1', { + ['enable_supervised_users==1 and enable_themes==1', { 'sources': [ '<@(chrome_browser_supervised_user_and_themes_sources)' ], }], ['enable_webrtc==1', {
diff --git a/chrome/chrome_browser_chromeos.gypi b/chrome/chrome_browser_chromeos.gypi index 8b594ec6..54d5846 100644 --- a/chrome/chrome_browser_chromeos.gypi +++ b/chrome/chrome_browser_chromeos.gypi
@@ -829,6 +829,7 @@ 'browser/chromeos/preferences.h', 'browser/chromeos/profiles/avatar_menu_actions_chromeos.cc', 'browser/chromeos/profiles/avatar_menu_actions_chromeos.h', + 'browser/chromeos/profiles/avatar_menu_chromeos.cc', 'browser/chromeos/profiles/multiprofiles_intro_dialog.cc', 'browser/chromeos/profiles/multiprofiles_intro_dialog.h', 'browser/chromeos/profiles/multiprofiles_session_aborted_dialog.cc',
diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi index 21f3418..9924102 100644 --- a/chrome/chrome_browser_extensions.gypi +++ b/chrome/chrome_browser_extensions.gypi
@@ -30,6 +30,7 @@ 'browser/extensions/api/terminal/terminal_private_api.h', 'browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc', 'browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.h', + 'browser/extensions/api/vpn_provider/vpn_service_factory.cc', 'browser/extensions/updater/extension_cache_impl.cc', 'browser/extensions/updater/extension_cache_impl.h', 'browser/extensions/updater/local_extension_cache.cc',
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi index 695df5f..e1f9890 100644 --- a/chrome/chrome_browser_ui.gypi +++ b/chrome/chrome_browser_ui.gypi
@@ -1102,6 +1102,8 @@ 'browser/ui/webui/version_ui.cc', 'browser/ui/webui/version_ui.h', 'browser/ui/window_sizer/window_sizer_mac.mm', + 'browser/ui/zoom/chrome_zoom_level_otr_delegate.cc', + 'browser/ui/zoom/chrome_zoom_level_otr_delegate.h', 'browser/ui/zoom/chrome_zoom_level_prefs.cc', 'browser/ui/zoom/chrome_zoom_level_prefs.h', 'browser/ui/zoom/zoom_event_manager.cc', @@ -1881,8 +1883,12 @@ 'browser/ui/views/apps/chrome_native_app_window_views.h', 'browser/ui/views/apps/chrome_native_app_window_views_win.cc', 'browser/ui/views/apps/chrome_native_app_window_views_win.h', + 'browser/ui/views/apps/desktop_keyboard_capture.cc', + 'browser/ui/views/apps/desktop_keyboard_capture.h', 'browser/ui/views/apps/glass_app_window_frame_view_win.cc', 'browser/ui/views/apps/glass_app_window_frame_view_win.h', + 'browser/ui/views/apps/keyboard_hook_handler.h', + 'browser/ui/views/apps/keyboard_hook_handler_win.cc', 'browser/ui/views/apps/shaped_app_window_targeter.cc', 'browser/ui/views/apps/shaped_app_window_targeter.h', 'browser/ui/views/ash/tab_scrubber.cc', @@ -2511,6 +2517,7 @@ 'chrome_browser_ui_linux_sources': [ 'browser/ui/startup/autolaunch_prompt.cc', 'browser/ui/views/apps/chrome_apps_client_views.cc', + 'browser/ui/views/apps/keyboard_hook_handler.cc', 'browser/ui/views/frame/taskbar_decorator.cc', 'browser/ui/webui/certificate_viewer_ui.cc', 'browser/ui/webui/certificate_viewer_ui.h', @@ -3053,7 +3060,7 @@ ['enable_google_now==1 and OS!="android"', { 'sources': [ '<@(chrome_browser_ui_google_now_non_android_sources)' ], }], - ['enable_managed_users==0', { + ['enable_supervised_users==0', { 'sources!': [ 'browser/ui/views/profiles/supervised_user_avatar_label.cc', 'browser/ui/views/profiles/supervised_user_avatar_label.h',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index cf23e0c..16bc2a1 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi
@@ -844,6 +844,7 @@ 'browser/apps/app_shim/app_shim_interactive_uitest_mac.mm', 'browser/apps/app_shim/app_shim_quit_interactive_uitest_mac.mm', 'browser/apps/app_window_interactive_uitest.cc', + 'browser/apps/app_window_intercept_all_keys_uitest.cc', 'browser/apps/web_view_interactive_browsertest.cc', 'browser/autofill/autofill_interactive_uitest.cc', 'browser/browser_keyevents_browsertest.cc', @@ -2340,7 +2341,7 @@ ['exclude', '^browser/ui/webui/app_list/'], ], }], - ['enable_managed_users==0', { + ['enable_supervised_users==0', { 'sources/': [ ['exclude', '^browser/supervised_user/'], ['exclude', '^browser/ui/webui/downloads_ui_supervised_browsertest.cc'], @@ -2753,7 +2754,7 @@ 'browser/sync/test/integration/two_client_app_list_sync_test.cc', ], }], - ['enable_managed_users==0', { + ['enable_supervised_users==0', { 'sources!': [ 'browser/sync/test/integration/single_client_supervised_user_settings_sync_test.cc', ],
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi index dd310ea..c53f766 100644 --- a/chrome/chrome_tests_unit.gypi +++ b/chrome/chrome_tests_unit.gypi
@@ -450,6 +450,7 @@ 'browser/google/google_search_counter_android_unittest.cc', 'browser/google/google_search_counter_unittest.cc', 'browser/google/google_update_settings_unittest.cc', + 'browser/google/google_update_win_unittest.cc', 'browser/history/android/android_cache_database_unittest.cc', 'browser/history/android/android_history_provider_service_unittest.cc', 'browser/history/android/android_provider_backend_unittest.cc', @@ -593,7 +594,6 @@ 'browser/predictors/resource_prefetch_predictor_unittest.cc', 'browser/predictors/resource_prefetch_predictor_tables_unittest.cc', 'browser/predictors/resource_prefetcher_unittest.cc', - 'browser/prefs/browser_ui_prefs_migrator_unittest.cc', 'browser/prefs/chrome_pref_service_unittest.cc', 'browser/prefs/command_line_pref_store_unittest.cc', 'browser/prefs/incognito_mode_prefs_unittest.cc', @@ -1030,6 +1030,7 @@ 'browser/ui/cocoa/extensions/extension_install_view_controller_unittest.mm', 'browser/ui/cocoa/extensions/extension_installed_bubble_controller_unittest.mm', 'browser/ui/cocoa/extensions/media_galleries_dialog_cocoa_unittest.mm', + 'browser/ui/cocoa/extensions/test_toolbar_actions_bar_helper_cocoa.mm', 'browser/ui/cocoa/find_bar/find_bar_bridge_unittest.mm', 'browser/ui/cocoa/find_bar/find_bar_cocoa_controller_unittest.mm', 'browser/ui/cocoa/find_bar/find_bar_text_field_cell_unittest.mm', @@ -1178,8 +1179,10 @@ 'browser/ui/toolbar/recent_tabs_builder_test_helper.cc', 'browser/ui/toolbar/recent_tabs_builder_test_helper.h', 'browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc', + 'browser/ui/toolbar/test_toolbar_actions_bar_helper.h', 'browser/ui/toolbar/test_toolbar_model.cc', 'browser/ui/toolbar/test_toolbar_model.h', + 'browser/ui/toolbar/toolbar_actions_bar_unittest.cc', 'browser/ui/toolbar/toolbar_model_unittest.cc', 'browser/ui/toolbar/wrench_icon_painter_unittest.cc', 'browser/ui/toolbar/wrench_menu_model_unittest.cc', @@ -1221,6 +1224,7 @@ 'browser/ui/views/tabs/tab_strip_unittest.cc', 'browser/ui/views/tabs/tab_unittest.cc', 'browser/ui/views/toolbar/reload_button_unittest.cc', + 'browser/ui/views/toolbar/test_toolbar_actions_bar_helper_views.cc', 'browser/ui/views/translate/translate_bubble_view_unittest.cc', 'browser/ui/views/validation_message_bubble_delegate_unittest.cc', 'browser/ui/website_settings/permission_bubble_manager_unittest.cc', @@ -2664,9 +2668,6 @@ 'browser/safe_browsing/download_protection_service_unittest.cc', 'browser/safe_browsing/two_phase_uploader_unittest.cc', - # Android has no windows that have placement info. - 'browser/prefs/browser_ui_prefs_migrator_unittest.cc', - # Android does not use the Message Center notification system. 'browser/notifications/message_center_notifications_unittest.cc', 'browser/notifications/message_center_settings_controller_unittest.cc', @@ -2744,7 +2745,7 @@ 'common/net/x509_certificate_model_unittest.cc', ], }], - ['enable_managed_users!=1', { + ['enable_supervised_users!=1', { 'sources/': [ ['exclude', '^browser/supervised_user/'], ],
diff --git a/chrome/common/chrome_paths.cc b/chrome/common/chrome_paths.cc index 8a205a6..7c7d90e 100644 --- a/chrome/common/chrome_paths.cc +++ b/chrome/common/chrome_paths.cc
@@ -419,7 +419,7 @@ cur = cur.Append(FILE_PATH_LITERAL("custom_wallpapers")); break; #endif -#if defined(OS_LINUX) && defined(ENABLE_MANAGED_USERS) +#if defined(OS_LINUX) && defined(ENABLE_SUPERVISED_USERS) case chrome::DIR_SUPERVISED_USERS_DEFAULT_APPS: if (!PathService::Get(chrome::DIR_STANDALONE_EXTERNAL_EXTENSIONS, &cur)) return false;
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index 5b1b5b21..31dcf37 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc
@@ -1079,17 +1079,20 @@ // one wishes to use Chrome as an ash server. const char kSilentLaunch[] = "silent-launch"; -// Simulates an update being available. -const char kSimulateUpgrade[] = "simulate-upgrade"; +// Simulates that elevation is needed to recover upgrade channel. +const char kSimulateElevatedRecovery[] = "simulate-elevated-recovery"; // Simulates a critical update being available. const char kSimulateCriticalUpdate[] = "simulate-critical-update"; // Simulates that current version is outdated. -const char kSimulateOutdated[] = "simulate-outdated"; +const char kSimulateOutdated[] = "simulate-outdated"; // Simulates that current version is outdated and auto-update is off. -const char kSimulateOutdatedNoAU[] = "simulate-outdated-no-au"; +const char kSimulateOutdatedNoAU[] = "simulate-outdated-no-au"; + +// Simulates an update being available. +const char kSimulateUpgrade[] = "simulate-upgrade"; // Speculative resource prefetching. const char kSpeculativeResourcePrefetching[] =
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index 9726f3c..814f8ca 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h
@@ -297,6 +297,7 @@ extern const char kShowAppList[]; extern const char kShowIcons[]; extern const char kSigninProcess[]; +extern const char kSimulateElevatedRecovery[]; extern const char kSimulateUpgrade[]; extern const char kSimulateCriticalUpdate[]; extern const char kSimulateOutdated[];
diff --git a/chrome/common/extensions/api/automation.idl b/chrome/common/extensions/api/automation.idl index 865ce597..45b7643a 100644 --- a/chrome/common/extensions/api/automation.idl +++ b/chrome/common/extensions/api/automation.idl
@@ -85,7 +85,6 @@ disclosureTriangle, div, document, - editableText, embeddedObject, figcaption, figure, @@ -93,7 +92,6 @@ form, grid, group, - growArea, heading, iframe, ignored, @@ -149,7 +147,6 @@ sliderThumb, spinButtonPart, spinButton, - splitGroup, splitter, staticText, status, @@ -189,6 +186,7 @@ focusable, focused, haspopup, + horizontal, hovered, indeterminate, invisible,
diff --git a/chrome/common/extensions/api/captive_portal.idl b/chrome/common/extensions/api/captive_portal.idl new file mode 100644 index 0000000..55f86cf --- /dev/null +++ b/chrome/common/extensions/api/captive_portal.idl
@@ -0,0 +1,113 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Use the <code>networking.captivePortal</code> API to authenticate to captive +// portals. +namespace networking.captivePortal { + // Indicator for the type of network. Used in both $(NetworkInfo) and + // $(NetworkFilter). This extension API might be extended to ethernet and + // cellular networks in the future. + enum NetworkType { Wifi }; + + // A dictionary listing properties specific to WiFi networks. Either + // <code>SSID</code> or <code>HexSSID</code> must be set. + dictionary WiFiInfo { + // Unique identifier of the network + DOMString GUID; + + // hex-encoded byte sequence + DOMString? HexSSID; + + // SSID of the network + DOMString? SSID; + }; + + // A dictionary listing properties of the newly connected network on which a + // captive portal has been detected. This information is passed to the + // authenticating extension via the $(onCaptivePortalDetected) event. + dictionary NetworkInfo { + // Currently only WiFi supported, see $(NetworkType). + NetworkType Type; + + // Properties specific to WiFi networks. + WiFiInfo? WiFi; + }; + + // A dictionary which allows to filter networks by SSID. This filter matches a + // Wi-Fi network if the network's SSID equals any of the entries in either + // <code>SSID</code> or <code>HexSSID</code>. + dictionary WiFiFilter { + // List of SSIDs that can be handled by the extension. Note that the entries + // of <code>SSID</code> can only represent Unicode strings. SSID will be + // used in the UTF-8 encoding. For arbitrary byte sequences use + // <code>HexSSID</code>. + DOMString[] SSID; + + // hex encoded byte sequence. + DOMString[] HexSSID; + }; + + // Represents a general network filter. A network matches this filter if it + // matches any of the type-specific subfilters, i.e. $(WiFiFilter). + dictionary NetworkFilter { + // This field stores the filter information for the WiFi networks. + WiFiFilter? WiFi; + }; + + // Argument to $(finishAuthentication) indicating the result of the + // authentication attempt. + enum AuthenticationResult { + // The extension does not handle this network or captive portal (e.g. server + // end-point not found or not compatible). + unhandled, + + // The extension handled this network and authenticated successfully. + success, + + // The extension handled this network, tried to authenticate, however was + // rejected by the server. + rejected, + + // The extension handled this network, tried to authenticate, however failed + // due to an unspecified error. + failed + }; + + interface Functions { + // Allows an extension to define a network filter for the networks it can + // handle. Successive calls to this function will generate a union of the + // supplied filters. + // |networkFilter|: network filter to add + void addNetworkFilter(NetworkFilter networkFilter); + + // Removes all previously added filters. + void removeAllNetworkFilters(); + + // Called by the extension to notify the captive portal API that it finished + // an authentication attempt and hand over the result of the attempt. This + // function must only be called with the GUID of the latest + // $(onCaptivePortalDetected) event. + // |GUID|: unique network identifier obtained from + // $(onCaptivePortalDetected). + // |result|: the result of the authentication attempt + void finishAuthentication(DOMString GUID, AuthenticationResult result); + }; + + interface Events { + // This event fires everytime a captive portal is detected on a network + // matching any of the currently registered network filters and the user + // consents to use the extension for authentication. Network filters may be + // added using the $(addNetworkFilter). $(removeAllNetworkFilters) removes + // all network filters. If no network filters are registered, this event + // does not fires. + // Upon receiving this event the extension should start its authentication + // attempt with the captive portal. When the extension finishes its attempt + // it must call $(finishAuthentication) with the <code>GUID</code> received + // with this event and the appropriate $(AuthenticationResult) to notify + // the captive portal API. + // |networkInfo|: detailed information about the network on which a captive + // portal was detected. + static void onCaptivePortalDetected(NetworkInfo networkInfo); + }; +};
diff --git a/chrome/common/extensions/api/hotword_private.idl b/chrome/common/extensions/api/hotword_private.idl index ee4bd72f..7984fa04 100644 --- a/chrome/common/extensions/api/hotword_private.idl +++ b/chrome/common/extensions/api/hotword_private.idl
@@ -36,6 +36,9 @@ // Whether training mode is enabled. boolean trainingEnabled; + + // Whether the user corresponding to this profile is the active user. + boolean userIsActive; }; dictionary LaunchState {
diff --git a/chrome/common/extensions/docs/examples/extensions/calendar/javascript/background.js b/chrome/common/extensions/docs/examples/extensions/calendar/javascript/background.js index 66b162f..a357a9c7 100644 --- a/chrome/common/extensions/docs/examples/extensions/calendar/javascript/background.js +++ b/chrome/common/extensions/docs/examples/extensions/calendar/javascript/background.js
@@ -30,13 +30,17 @@ var defaultAuthor = ''; var isMultiCalendar = false; +// The Calendar API identifies requests from this extension by the 'extid' get +// parameter, set to this extension's ID. +var API_KEY = 'extid=' + chrome.runtime.id; + //URL for getting feed of individual calendar support. var SINGLE_CALENDAR_SUPPORT_URL = 'https://www.google.com/calendar/feeds' + - '/default/private/embed?toolbar=true&max-results=10'; + '/default/private/embed?toolbar=true&max-results=10&' + API_KEY; //URL for getting feed of multiple calendar support. var MULTIPLE_CALENDAR_SUPPORT_URL = 'https://www.google.com/calendar/feeds' + - '/default/allcalendars/full'; + '/default/allcalendars/full?' + API_KEY; //URL for opening Google Calendar in new tab. var GOOGLE_CALENDAR_URL = 'http://www.google.com/calendar/render'; @@ -63,13 +67,13 @@ } /** - * Gets the JavaScript object at |key| from localStorage. Assumes that the - * value was written by localStorageSet (i.e. stored as JSON). - * If the value is missing or undefined, returns undefined. + * Gets the JavaScript object at |key| from localStorage, defaulting to |deflt| + * if it hasn't been set. Assumes that the value was written by localStorageSet + * (i.e. stored as JSON). */ -function localStorageGet(key) { +function localStorageGet(key, deflt) { var value = localStorage[key]; - return (typeof value == 'undefined') ? undefined : JSON.parse(value); + return (typeof value == 'undefined') ? deflt : JSON.parse(value); } /** @@ -336,7 +340,7 @@ try { xhr.onreadystatechange = CalendarManager.genResponseChangeFunc(xhr); xhr.onerror = function(error) { - console.log('error: ' + error); + console.error('error:', error); localStorageSet('nextEvent', null); canvasAnimation_.drawFinal(); }; @@ -349,7 +353,7 @@ xhr.open('GET', url); xhr.send(null); } catch (e) { - console.log('ex: ' + e); + console.error('ex:', e); localStorageSet('nextEvent', null); canvasAnimation_.drawFinal(); } @@ -421,16 +425,18 @@ xmlhttp.onreadystatechange = CalendarManager.onCalendarResponse(xmlhttp, calendarId); xmlhttp.onerror = function(error) { - console.log('error: ' + error); + console.error('error:', error); localStorageSet('nextEvent', null); canvasAnimation_.drawFinal(); }; - xmlhttp.open('GET', localStorageGet('calendars)[calendarId]')); + // Augment the calendar's URL with the API key. + var calendarUrl = localStorageGet('calendars')[calendarId] + '&' + API_KEY; + xmlhttp.open('GET', calendarUrl); xmlhttp.send(null); } catch (e) { - console.log('ex: ' + e); + console.error('ex:', e); localStorageSet('nextEvent', null); canvasAnimation_.drawFinal(); } @@ -477,7 +483,7 @@ } if (entry_ && entry_.length > 0) { - var eventList = localStorageGet('eventList'); + var eventList = localStorageGet('eventList', []); for (var i = 0, entry; entry = entry_[i]; ++i) { var event_ = CalendarManager.extractEvent(entry, mailId); @@ -497,10 +503,10 @@ calendarId++; //get the next calendar - if (calendarId < localStorageGet('calendars).length')) { + if (calendarId < localStorageGet('calendars', []).length) { CalendarManager.getCalendarFeed(calendarId); } else { - CalendarManager.populateLatestEvent(localStorageGet('eventList)')); + CalendarManager.populateLatestEvent(localStorageGet('eventList', [])); } }; @@ -667,7 +673,7 @@ * Called from options.js page on saving the settings */ function onSettingsChange() { - isMultiCalendar = localStorageGet('multiCalendar'); + isMultiCalendar = localStorageGet('multiCalendar', false); badgeAnimation_.start(); CalendarManager.pollServer(); }; @@ -733,7 +739,7 @@ */ badgeAnimation_ = new BadgeAnimation(); canvasAnimation_ = new CanvasAnimation(); -isMultiCalendar = localStorageGet('multiCalendar || false'); +isMultiCalendar = localStorageGet('multiCalendar', false); chrome.browserAction.setIcon({path: '../images/icon-16.gif'}); chrome.runtime.onInstalled.addListener(onInstalled); chrome.alarms.onAlarm.addListener(redraw)
diff --git a/chrome/common/extensions/docs/examples/extensions/calendar/manifest.json b/chrome/common/extensions/docs/examples/extensions/calendar/manifest.json index cb4f8cf..8274830 100644 --- a/chrome/common/extensions/docs/examples/extensions/calendar/manifest.json +++ b/chrome/common/extensions/docs/examples/extensions/calendar/manifest.json
@@ -4,7 +4,7 @@ "manifest_version": 2, "default_locale":"en", "options_page": "views/options.html", - "version": "1.4.0", + "version": "1.5.0", "background": { "page": "views/background.html", "persistent": false
diff --git a/chrome/common/extensions/permissions/chrome_api_permissions.cc b/chrome/common/extensions/permissions/chrome_api_permissions.cc index d17bd96..02ba7b4 100644 --- a/chrome/common/extensions/permissions/chrome_api_permissions.cc +++ b/chrome/common/extensions/permissions/chrome_api_permissions.cc
@@ -118,8 +118,10 @@ IDS_EXTENSION_PROMPT_WARNING_COPRESENCE, PermissionMessage::kCopresence}, {APIPermission::kCopresencePrivate, "copresencePrivate"}, - {APIPermission::kDocumentScan, "documentScan", - APIPermissionInfo::kFlagNone, IDS_EXTENSION_PROMPT_WARNING_DOCUMENT_SCAN, + {APIPermission::kDocumentScan, + "documentScan", + APIPermissionInfo::kFlagNone, + IDS_EXTENSION_PROMPT_WARNING_DOCUMENT_SCAN, PermissionMessage::kDocumentScan}, {APIPermission::kEnterprisePlatformKeys, "enterprise.platformKeys"}, {APIPermission::kFileBrowserHandler, @@ -414,6 +416,11 @@ {APIPermission::kAudio, "audio"}, {APIPermission::kCastStreaming, "cast.streaming"}, {APIPermission::kBrowser, "browser"}, + {APIPermission::kInterceptAllKeys, + "app.window.interceptAllKeys", + APIPermissionInfo::kFlagNone, + IDS_EXTENSION_PROMPT_WARNING_INTERCEPT_ALL_KEYS, + PermissionMessage::kInterceptAllKeys}, // Settings override permissions. {APIPermission::kHomepage,
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index 8db6b07..f2aa091 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc
@@ -880,9 +880,18 @@ // permitted. const char kAllowDeletingBrowserHistory[] = "history.deleting_enabled"; -// Boolean controlling whether SafeSearch is mandatory for Google Web Searches. +// Boolean controlling whether SafeSearch is mandatory for Google Web Searches +// and also whether Safety Mode is mandatory on YouTube. +// DEPRECATED: This is replaced by kForceGoogleSafeSearch and +// kForceYouTubeSafetyMode, and still exists for legacy reasons only. const char kForceSafeSearch[] = "settings.force_safesearch"; +// Boolean controlling whether SafeSearch is mandatory for Google Web Searches. +const char kForceGoogleSafeSearch[] = "settings.force_google_safesearch"; + +// Boolean controlling whether Safety Mode is mandatory on YouTube. +const char kForceYouTubeSafetyMode[] = "settings.force_youtube_safety_mode"; + // Boolean controlling whether History is recorded and synced for // supervised users. const char kRecordHistory[] = "settings.history_recorded"; @@ -1403,10 +1412,6 @@ // restore on startup. const char kAppWindowPlacement[] = "browser.app_window_placement"; -// An integer specifying the total number of bytes to be used by the -// renderer's in-memory cache of objects. -const char kMemoryCacheSize[] = "renderer.memory_cache.size"; - // String which specifies where to download files to by default. const char kDownloadDefaultDirectory[] = "download.default_directory"; @@ -1778,6 +1783,11 @@ // trigger from any screen. const char kHotwordAlwaysOnSearchEnabled[] = "hotword.always_on_search_enabled"; +// A boolean pref that indicates whether the hotword always-on notification +// has been seen already. +const char kHotwordAlwaysOnNotificationSeen[] = + "hotword.always_on_notification_seen"; + // A boolean pref that controls whether the sound of "Ok, Google" plus a few // seconds of audio data before is sent back to improve voice search. const char kHotwordAudioLoggingEnabled[] = "hotword.audio_logging_enabled"; @@ -2281,4 +2291,8 @@ // Last user's interaction with the password bubble. const char kPasswordBubbleLastInteractions[] = "password_bubble.interactions"; +// Boolean that indicates whether elevation is needed to recover Chrome upgrade. +const char kRecoveryComponentNeedsElevation[] = + "recovery_component.needs_elevation"; + } // namespace prefs
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index da49470..482b814 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h
@@ -288,6 +288,8 @@ extern const char kSavingBrowserHistoryDisabled[]; extern const char kAllowDeletingBrowserHistory[]; extern const char kForceSafeSearch[]; +extern const char kForceGoogleSafeSearch[]; +extern const char kForceYouTubeSafetyMode[]; extern const char kRecordHistory[]; extern const char kDeleteTimePeriod[]; extern const char kLastClearBrowsingDataTime[]; @@ -479,7 +481,6 @@ extern const char kBrowserWindowPlacementPopup[]; extern const char kTaskManagerWindowPlacement[]; extern const char kAppWindowPlacement[]; -extern const char kMemoryCacheSize[]; extern const char kDownloadDefaultDirectory[]; extern const char kDownloadExtensionsToOpen[]; @@ -628,6 +629,7 @@ extern const char kHotwordSearchEnabled[]; extern const char kHotwordAlwaysOnSearchEnabled[]; +extern const char kHotwordAlwaysOnNotificationSeen[]; extern const char kHotwordAudioLoggingEnabled[]; extern const char kHotwordAudioHistoryEnabled[]; extern const char kHotwordPreviousLanguage[]; @@ -808,6 +810,8 @@ extern const char kPasswordBubbleNopesCount[]; extern const char kPasswordBubbleLastInteractions[]; +extern const char kRecoveryComponentNeedsElevation[]; + } // namespace prefs #endif // CHROME_COMMON_PREF_NAMES_H_
diff --git a/chrome/installer/util/google_update_util.cc b/chrome/installer/util/google_update_util.cc index 1b8c74d4..68e4675 100644 --- a/chrome/installer/util/google_update_util.cc +++ b/chrome/installer/util/google_update_util.cc
@@ -182,7 +182,7 @@ if (base::win::GetVersion() >= base::win::VERSION_VISTA && base::win::UserAccountControlIsEnabled()) { - base::LaunchElevatedProcess(cmd, launch_options, NULL); + base::LaunchElevatedProcess(cmd, launch_options); } else { base::LaunchProcess(cmd, launch_options, NULL); }
diff --git a/chrome/interactive_ui_tests.isolate b/chrome/interactive_ui_tests.isolate index 6a29163..bef04953 100644 --- a/chrome/interactive_ui_tests.isolate +++ b/chrome/interactive_ui_tests.isolate
@@ -18,7 +18,7 @@ '<(PRODUCT_DIR)/libffmpegsumo.so', '<(PRODUCT_DIR)/libosmesa.so', '<(PRODUCT_DIR)/libppapi_tests.so', - '<(PRODUCT_DIR)/pyproto/', + '<(PRODUCT_DIR)/pyproto/google/', ], }, }],
diff --git a/chrome/renderer/autofill/autofill_renderer_browsertest.cc b/chrome/renderer/autofill/autofill_renderer_browsertest.cc index af756abb..c38f78d 100644 --- a/chrome/renderer/autofill/autofill_renderer_browsertest.cc +++ b/chrome/renderer/autofill/autofill_renderer_browsertest.cc
@@ -11,6 +11,7 @@ #include "components/autofill/core/common/form_data.h" #include "components/autofill/core/common/form_field_data.h" #include "content/public/common/content_switches.h" +#include "content/public/renderer/render_frame.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/WebKit/public/platform/WebString.h" #include "third_party/WebKit/public/platform/WebURLRequest.h" @@ -55,11 +56,11 @@ } void SimulateRequestAutocompleteResult( + blink::WebFrame* invoking_frame, const blink::WebFormElement::AutocompleteResult& result, const base::string16& message) { AutofillMsg_RequestAutocompleteResult msg(0, result, message, FormData()); - static_cast<content::RenderViewObserver*>(autofill_agent_) - ->OnMessageReceived(msg); + content::RenderFrame::FromWebFrame(invoking_frame)->OnMessageReceived(msg); } private: @@ -287,8 +288,7 @@ render_thread_->sink().ClearMessages(); // Invoke requestAutocomplete to show the dialog. - static_cast<blink::WebAutofillClient*>(autofill_agent_) - ->didRequestAutocomplete(invoking_form()); + invoking_frame_->autofillClient()->didRequestAutocomplete(invoking_form()); ASSERT_TRUE(render_thread_->sink().GetFirstMessageMatching( AutofillHostMsg_RequestAutocomplete::ID)); @@ -309,11 +309,12 @@ WebLocalFrame* invoking_frame() { return invoking_frame_; } WebFrame* sibling_frame() { return sibling_frame_; } - private: + protected: WebFormElement invoking_form_; WebLocalFrame* invoking_frame_; WebFrame* sibling_frame_; + private: DISALLOW_COPY_AND_ASSIGN(RequestAutocompleteRendererTest); }; @@ -341,7 +342,7 @@ TEST_F(RequestAutocompleteRendererTest, NoCancelOnSubframeNavigateAfterDone) { // Pretend that the dialog was cancelled. SimulateRequestAutocompleteResult( - WebFormElement::AutocompleteResultErrorCancel, + invoking_frame_, WebFormElement::AutocompleteResultErrorCancel, base::ASCIIToUTF16("Print me to the console")); // Additional navigations should not crash nor send cancels. @@ -353,7 +354,7 @@ TEST_F(RequestAutocompleteRendererTest, NoCancelOnMainFrameNavigateAfterDone) { // Pretend that the dialog was cancelled. SimulateRequestAutocompleteResult( - WebFormElement::AutocompleteResultErrorCancel, + invoking_frame_, WebFormElement::AutocompleteResultErrorCancel, base::ASCIIToUTF16("Print me to the console")); // Additional navigations should not crash nor send cancels. @@ -364,8 +365,7 @@ TEST_F(RequestAutocompleteRendererTest, InvokingTwiceOnlyShowsOnce) { // Attempting to show the requestAutocomplete dialog again should be ignored. - static_cast<blink::WebAutofillClient*>(autofill_agent_) - ->didRequestAutocomplete(invoking_form()); + invoking_frame_->autofillClient()->didRequestAutocomplete(invoking_form()); EXPECT_FALSE(render_thread_->sink().GetFirstMessageMatching( AutofillHostMsg_RequestAutocomplete::ID)); }
diff --git a/chrome/renderer/autofill/form_autofill_browsertest.cc b/chrome/renderer/autofill/form_autofill_browsertest.cc index 8816786f..762f1a15 100644 --- a/chrome/renderer/autofill/form_autofill_browsertest.cc +++ b/chrome/renderer/autofill/form_autofill_browsertest.cc
@@ -19,22 +19,20 @@ #include "third_party/WebKit/public/platform/WebVector.h" #include "third_party/WebKit/public/web/WebDocument.h" #include "third_party/WebKit/public/web/WebElement.h" +#include "third_party/WebKit/public/web/WebElementCollection.h" #include "third_party/WebKit/public/web/WebFormControlElement.h" #include "third_party/WebKit/public/web/WebFormElement.h" #include "third_party/WebKit/public/web/WebInputElement.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" -#include "third_party/WebKit/public/web/WebNode.h" #include "third_party/WebKit/public/web/WebSelectElement.h" #include "third_party/WebKit/public/web/WebTextAreaElement.h" using base::ASCIIToUTF16; -using blink::WebDocument; using blink::WebElement; using blink::WebFormControlElement; using blink::WebFormElement; using blink::WebFrame; using blink::WebInputElement; -using blink::WebNode; using blink::WebSelectElement; using blink::WebString; using blink::WebTextAreaElement; @@ -115,7 +113,7 @@ LoadHTML(html); WebFrame* web_frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), web_frame); + ASSERT_NE(nullptr, web_frame); FormCache form_cache; std::vector<FormData> forms = form_cache.ExtractNewForms(*web_frame); @@ -174,7 +172,7 @@ LoadHTML(html); WebFrame* web_frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), web_frame); + ASSERT_NE(nullptr, web_frame); FormCache form_cache; std::vector<FormData> forms = form_cache.ExtractNewForms(*web_frame); @@ -290,7 +288,7 @@ LoadHTML("<INPUT type='text' id='element' value='value'/>"); WebFrame* frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), frame); + ASSERT_NE(nullptr, frame); WebElement web_element = frame->document().getElementById("element"); WebFormControlElement element = web_element.to<WebFormControlElement>(); @@ -319,7 +317,7 @@ " autocomplete='off'/>"); WebFrame* frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), frame); + ASSERT_NE(nullptr, frame); WebElement web_element = frame->document().getElementById("element"); WebFormControlElement element = web_element.to<WebFormControlElement>(); @@ -341,7 +339,7 @@ " maxlength='5'/>"); WebFrame* frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), frame); + ASSERT_NE(nullptr, frame); WebElement web_element = frame->document().getElementById("element"); WebFormControlElement element = web_element.to<WebFormControlElement>(); @@ -361,7 +359,7 @@ LoadHTML("<INPUT type='text' id='element' value='value'/>"); WebFrame* frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), frame); + ASSERT_NE(nullptr, frame); WebElement web_element = frame->document().getElementById("element"); WebInputElement element = web_element.to<WebInputElement>(); @@ -385,7 +383,7 @@ "<INPUT type='radio' id='radio' value='male'/>"); WebFrame* frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), frame); + ASSERT_NE(nullptr, frame); WebElement web_element = frame->document().getElementById("checkbox"); WebInputElement element = web_element.to<WebInputElement>(); @@ -423,7 +421,7 @@ "</SELECT>"); WebFrame* frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), frame); + ASSERT_NE(nullptr, frame); WebElement web_element = frame->document().getElementById("element"); WebFormControlElement element = web_element.to<WebFormControlElement>(); @@ -492,7 +490,7 @@ "</TEXTAREA>"); WebFrame* frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), frame); + ASSERT_NE(nullptr, frame); WebElement web_element = frame->document().getElementById("element"); WebFormControlElement element = web_element.to<WebFormControlElement>(); @@ -519,7 +517,7 @@ LoadHTML("<INPUT type='month' id='element' value='2011-12'>"); WebFrame* frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), frame); + ASSERT_NE(nullptr, frame); WebElement web_element = frame->document().getElementById("element"); WebFormControlElement element = web_element.to<WebFormControlElement>(); @@ -548,7 +546,7 @@ "</FORM>"); WebFrame* frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), frame); + ASSERT_NE(nullptr, frame); WebElement web_element = frame->document().getElementById("hidden"); WebFormControlElement element = web_element.to<WebFormControlElement>(); @@ -577,7 +575,7 @@ "</FORM>"); WebFrame* frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), frame); + ASSERT_NE(nullptr, frame); WebElement web_element = frame->document().getElementById("password"); WebFormControlElement element = web_element.to<WebFormControlElement>(); @@ -617,7 +615,7 @@ LoadHTML(html.c_str()); WebFrame* frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), frame); + ASSERT_NE(nullptr, frame); struct TestCase { const std::string element_id; @@ -680,7 +678,7 @@ "</FORM>"); WebFrame* frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), frame); + ASSERT_NE(nullptr, frame); WebElement web_element = frame->document().getElementById("element"); WebFormControlElement element = web_element.to<WebFormControlElement>(); @@ -696,7 +694,7 @@ "</FORM>"); WebFrame* frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), frame); + ASSERT_NE(nullptr, frame); WebElement web_element = frame->document().getElementById("element"); WebFormControlElement element = web_element.to<WebFormControlElement>(); @@ -713,7 +711,7 @@ "</FORM>"); WebFrame* frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), frame); + ASSERT_NE(nullptr, frame); WebElement web_element = frame->document().getElementById("element"); WebFormControlElement element = web_element.to<WebFormControlElement>(); @@ -729,7 +727,7 @@ "</FORM>"); WebFrame* frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), frame); + ASSERT_NE(nullptr, frame); WebElement web_element = frame->document().getElementById("element"); WebFormControlElement element = web_element.to<WebFormControlElement>(); @@ -746,7 +744,7 @@ "</FORM>"); WebFrame* frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), frame); + ASSERT_NE(nullptr, frame); WebElement web_element = frame->document().getElementById("element"); WebFormControlElement element = web_element.to<WebFormControlElement>(); @@ -764,7 +762,7 @@ "</FORM>"); WebFrame* frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), frame); + ASSERT_NE(nullptr, frame); WebElement web_element = frame->document().getElementById("element"); WebFormControlElement element = web_element.to<WebFormControlElement>(); @@ -782,7 +780,7 @@ "</FORM>"); WebFrame* frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), frame); + ASSERT_NE(nullptr, frame); WebElement web_element = frame->document().getElementById("element"); WebFormControlElement element = web_element.to<WebFormControlElement>(); @@ -819,7 +817,7 @@ "</FORM>"); WebFrame* frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), frame); + ASSERT_NE(nullptr, frame); WebVector<WebFormElement> forms; frame->document().forms(forms); @@ -898,7 +896,7 @@ LoadHTML(html.c_str()); WebFrame* frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), frame); + ASSERT_NE(nullptr, frame); WebVector<WebFormElement> forms; frame->document().forms(forms); @@ -942,7 +940,7 @@ "</FORM>"); WebFrame* web_frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), web_frame); + ASSERT_NE(nullptr, web_frame); FormCache form_cache; std::vector<FormData> forms = form_cache.ExtractNewForms(*web_frame); @@ -1005,7 +1003,7 @@ "</FORM>"); WebFrame* web_frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), web_frame); + ASSERT_NE(nullptr, web_frame); FormCache form_cache; std::vector<FormData> forms = form_cache.ExtractNewForms(*web_frame); @@ -1105,7 +1103,7 @@ "</FORM>"); WebFrame* web_frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), web_frame); + ASSERT_NE(nullptr, web_frame); FormCache form_cache; std::vector<FormData> forms = form_cache.ExtractNewForms(*web_frame); @@ -1120,7 +1118,7 @@ "</FORM>"); WebFrame* web_frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), web_frame); + ASSERT_NE(nullptr, web_frame); FormCache form_cache; std::vector<FormData> forms = form_cache.ExtractNewForms(*web_frame); @@ -1133,7 +1131,7 @@ "</FORM>"); WebFrame* web_frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), web_frame); + ASSERT_NE(nullptr, web_frame); FormCache form_cache; std::vector<FormData> forms = form_cache.ExtractNewForms(*web_frame); @@ -1152,7 +1150,7 @@ "</FORM>"); WebFrame* web_frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), web_frame); + ASSERT_NE(nullptr, web_frame); FormCache form_cache; std::vector<FormData> forms = form_cache.ExtractNewForms(*web_frame); @@ -1171,7 +1169,7 @@ "</FORM>"); WebFrame* web_frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), web_frame); + ASSERT_NE(nullptr, web_frame); WebVector<WebFormElement> web_forms; web_frame->document().forms(web_forms); @@ -1200,7 +1198,7 @@ "</FORM>"); WebFrame* web_frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), web_frame); + ASSERT_NE(nullptr, web_frame); WebVector<WebFormElement> web_forms; web_frame->document().forms(web_forms); @@ -1248,7 +1246,7 @@ "</FORM>"); WebFrame* web_frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), web_frame); + ASSERT_NE(nullptr, web_frame); FormCache form_cache; std::vector<FormData> forms = form_cache.ExtractNewForms(*web_frame); @@ -1341,7 +1339,7 @@ "</FORM>"); WebFrame* web_frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), web_frame); + ASSERT_NE(nullptr, web_frame); FormCache form_cache; std::vector<FormData> forms = form_cache.ExtractNewForms(*web_frame); @@ -2527,7 +2525,7 @@ "</FORM>"); WebFrame* web_frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), web_frame); + ASSERT_NE(nullptr, web_frame); FormCache form_cache; std::vector<FormData> forms = form_cache.ExtractNewForms(*web_frame); @@ -2626,7 +2624,7 @@ "</FORM>"); WebFrame* web_frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), web_frame); + ASSERT_NE(nullptr, web_frame); FormCache form_cache; std::vector<FormData> forms = form_cache.ExtractNewForms(*web_frame); @@ -2706,7 +2704,7 @@ "</FORM>"); WebFrame* web_frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), web_frame); + ASSERT_NE(nullptr, web_frame); FormCache form_cache; std::vector<FormData> forms = form_cache.ExtractNewForms(*web_frame); @@ -2795,7 +2793,7 @@ "</FORM>"); WebFrame* web_frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), web_frame); + ASSERT_NE(nullptr, web_frame); FormCache form_cache; std::vector<FormData> forms = form_cache.ExtractNewForms(*web_frame); @@ -2890,7 +2888,7 @@ WebFrame* frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), frame); + ASSERT_NE(nullptr, frame); WebVector<WebFormElement> forms; frame->document().forms(forms); @@ -2949,7 +2947,7 @@ "</FORM>"); WebFrame* frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), frame); + ASSERT_NE(nullptr, frame); WebVector<WebFormElement> forms; frame->document().forms(forms); @@ -3017,7 +3015,7 @@ "</FORM>"); WebFrame* web_frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), web_frame); + ASSERT_NE(nullptr, web_frame); FormCache form_cache; std::vector<FormData> forms = form_cache.ExtractNewForms(*web_frame); @@ -3131,7 +3129,7 @@ "</FORM>"); WebFrame* web_frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), web_frame); + ASSERT_NE(nullptr, web_frame); FormCache form_cache; std::vector<FormData> forms = form_cache.ExtractNewForms(*web_frame); @@ -3243,7 +3241,7 @@ "</FORM>"); WebFrame* web_frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), web_frame); + ASSERT_NE(nullptr, web_frame); FormCache form_cache; std::vector<FormData> forms = form_cache.ExtractNewForms(*web_frame); @@ -3319,7 +3317,7 @@ "</FORM>"); WebFrame* web_frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), web_frame); + ASSERT_NE(nullptr, web_frame); FormCache form_cache; std::vector<FormData> forms = form_cache.ExtractNewForms(*web_frame); @@ -3386,7 +3384,7 @@ "</FORM>"); WebFrame* web_frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), web_frame); + ASSERT_NE(nullptr, web_frame); FormCache form_cache; std::vector<FormData> forms = form_cache.ExtractNewForms(*web_frame); @@ -3453,7 +3451,7 @@ "</FORM>"); WebFrame* web_frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), web_frame); + ASSERT_NE(nullptr, web_frame); FormCache form_cache; std::vector<FormData> forms = form_cache.ExtractNewForms(*web_frame); @@ -3521,7 +3519,7 @@ "</FORM>"); WebFrame* web_frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), web_frame); + ASSERT_NE(nullptr, web_frame); FormCache form_cache; std::vector<FormData> forms = form_cache.ExtractNewForms(*web_frame); @@ -3595,7 +3593,7 @@ LoadHTML("<BUTTON id='link'>Button</BUTTON>" "<BUTTON name='button'>Button</BUTTON>"); WebFrame* frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), frame); + ASSERT_NE(nullptr, frame); // Successful retrieval by id. autofill::WebElementDescriptor clicker; @@ -3630,7 +3628,7 @@ "</FORM>"); WebFrame* frame = GetMainFrame(); - ASSERT_NE(static_cast<WebFrame*>(NULL), frame); + ASSERT_NE(nullptr, frame); // Set the value of the select-one. WebSelectElement select_element = @@ -3709,4 +3707,147 @@ EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[2]); } +TEST_F(FormAutofillTest, + UnownedFormElementsAndFieldSetsToFormDataFieldsets) { + std::vector<WebElement> fieldsets; + std::vector<WebFormControlElement> control_elements; + + const ExtractMask extract_mask = + static_cast<ExtractMask>(EXTRACT_VALUE | EXTRACT_OPTIONS); + const GURL dummy_origin("http://www.example.com"); + + LoadHTML("<DIV>" + " <FIELDSET>" + " <LABEL for='firstname'>First name:</LABEL>" + " <LABEL for='lastname'>Last name:</LABEL>" + " <INPUT type='text' id='firstname' value='John'/>" + " <INPUT type='text' id='lastname' value='Smith'/>" + " </FIELDSET>" + " <FIELDSET>" + " <LABEL for='email'>Email:</LABEL>" + " <INPUT type='text' id='email' value='john@example.com'/>" + " </FIELDSET>" + "</DIV>"); + + WebFrame* frame = GetMainFrame(); + ASSERT_NE(nullptr, frame); + + control_elements = FormCache::GetUnownedAutofillableFormFieldElements( + frame->document().all(), &fieldsets); + ASSERT_EQ(3U, control_elements.size()); + ASSERT_EQ(2U, fieldsets.size()); + + FormData form; + EXPECT_TRUE(UnownedFormElementsAndFieldSetsToFormData( + fieldsets, control_elements, dummy_origin, extract_mask, &form)); + + EXPECT_TRUE(form.name.empty()); + EXPECT_EQ(dummy_origin, form.origin); + EXPECT_FALSE(form.action.is_valid()); + + const std::vector<FormFieldData>& fields = form.fields; + ASSERT_EQ(3U, fields.size()); + + FormFieldData expected; + expected.form_control_type = "text"; + expected.max_length = WebInputElement::defaultMaxLength(); + + expected.name = ASCIIToUTF16("firstname"); + expected.value = ASCIIToUTF16("John"); + expected.label = ASCIIToUTF16("First name:"); + EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[0]); + + expected.name = ASCIIToUTF16("lastname"); + expected.value = ASCIIToUTF16("Smith"); + expected.label = ASCIIToUTF16("Last name:"); + EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[1]); + + expected.name = ASCIIToUTF16("email"); + expected.value = ASCIIToUTF16("john@example.com"); + expected.label = ASCIIToUTF16("Email:"); + EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[2]); +} + +TEST_F(FormAutofillTest, + UnownedFormElementsAndFieldSetsToFormDataControlOutsideOfFieldset) { + std::vector<WebElement> fieldsets; + std::vector<WebFormControlElement> control_elements; + + const ExtractMask extract_mask = + static_cast<ExtractMask>(EXTRACT_VALUE | EXTRACT_OPTIONS); + const GURL dummy_origin("http://www.example.com"); + + LoadHTML("<DIV>" + " <FIELDSET>" + " <LABEL for='firstname'>First name:</LABEL>" + " <LABEL for='lastname'>Last name:</LABEL>" + " <INPUT type='text' id='firstname' value='John'/>" + " <INPUT type='text' id='lastname' value='Smith'/>" + " <LABEL for='email'>Email:</LABEL>" + " </FIELDSET>" + " <INPUT type='text' id='email' value='john@example.com'/>" + "</DIV>"); + + WebFrame* frame = GetMainFrame(); + ASSERT_NE(nullptr, frame); + + control_elements = FormCache::GetUnownedAutofillableFormFieldElements( + frame->document().all(), &fieldsets); + ASSERT_EQ(3U, control_elements.size()); + ASSERT_EQ(1U, fieldsets.size()); + + FormData form; + EXPECT_TRUE(UnownedFormElementsAndFieldSetsToFormData( + fieldsets, control_elements, dummy_origin, extract_mask, &form)); + + EXPECT_TRUE(form.name.empty()); + EXPECT_EQ(dummy_origin, form.origin); + EXPECT_FALSE(form.action.is_valid()); + + const std::vector<FormFieldData>& fields = form.fields; + ASSERT_EQ(3U, fields.size()); + + FormFieldData expected; + expected.form_control_type = "text"; + expected.max_length = WebInputElement::defaultMaxLength(); + + expected.name = ASCIIToUTF16("firstname"); + expected.value = ASCIIToUTF16("John"); + expected.label = ASCIIToUTF16("First name:"); + EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[0]); + + expected.name = ASCIIToUTF16("lastname"); + expected.value = ASCIIToUTF16("Smith"); + expected.label = ASCIIToUTF16("Last name:"); + EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[1]); + + expected.name = ASCIIToUTF16("email"); + expected.value = ASCIIToUTF16("john@example.com"); + expected.label = ASCIIToUTF16("Email:"); + EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[2]); +} + +TEST_F(FormAutofillTest, UnownedFormElementsAndFieldSetsToFormDataWithForm) { + std::vector<WebElement> fieldsets; + std::vector<WebFormControlElement> control_elements; + + const ExtractMask extract_mask = + static_cast<ExtractMask>(EXTRACT_VALUE | EXTRACT_OPTIONS); + const GURL dummy_origin("http://www.example.com"); + + LoadHTML(kFormHtml); + + WebFrame* frame = GetMainFrame(); + ASSERT_NE(nullptr, frame); + + control_elements = FormCache::GetUnownedAutofillableFormFieldElements( + frame->document().all(), &fieldsets); + ASSERT_EQ(0U, control_elements.size()); + ASSERT_EQ(0U, fieldsets.size()); + + FormData form; + EXPECT_FALSE(UnownedFormElementsAndFieldSetsToFormData( + fieldsets, control_elements, dummy_origin, extract_mask, &form)); +} + } // namespace autofill
diff --git a/chrome/renderer/autofill/password_autofill_agent_browsertest.cc b/chrome/renderer/autofill/password_autofill_agent_browsertest.cc index 29321901..36e0496 100644 --- a/chrome/renderer/autofill/password_autofill_agent_browsertest.cc +++ b/chrome/renderer/autofill/password_autofill_agent_browsertest.cc
@@ -12,6 +12,7 @@ #include "components/autofill/content/renderer/test_password_autofill_agent.h" #include "components/autofill/core/common/form_data.h" #include "components/autofill/core/common/form_field_data.h" +#include "content/public/renderer/render_frame.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/WebKit/public/platform/WebString.h" #include "third_party/WebKit/public/platform/WebVector.h" @@ -178,13 +179,21 @@ void SimulateOnFillPasswordForm( const PasswordFormFillData& fill_data) { AutofillMsg_FillPasswordForm msg(0, kPasswordFillFormDataId, fill_data); - static_cast<content::RenderViewObserver*>(password_autofill_agent_) + static_cast<content::RenderFrameObserver*>(password_autofill_agent_) ->OnMessageReceived(msg); } + // As above, but fills for an iframe. + void SimulateOnFillPasswordFormForFrame( + WebFrame* frame, + const PasswordFormFillData& fill_data) { + AutofillMsg_FillPasswordForm msg(0, kPasswordFillFormDataId, fill_data); + content::RenderFrame::FromWebFrame(frame)->OnMessageReceived(msg); + } + void SendVisiblePasswordForms() { - static_cast<content::RenderViewObserver*>(password_autofill_agent_) - ->DidFinishLoad(GetMainFrame()); + static_cast<content::RenderFrameObserver*>(password_autofill_agent_) + ->DidFinishLoad(); } void SetUp() override { @@ -280,10 +289,15 @@ input_frame->document().frame()->view()->advanceFocus(false); if (move_caret_to_end) input.setSelectionRange(new_value.length(), new_value.length()); - if (is_user_input) - password_autofill_agent_->FirstUserGestureObserved(); - static_cast<blink::WebAutofillClient*>(autofill_agent_) - ->textFieldDidChange(input); + if (is_user_input) { + AutofillMsg_FirstUserGestureObservedInTab msg(0); + content::RenderFrame::FromWebFrame(input_frame)->OnMessageReceived(msg); + + // Also pass the message to the testing object. + if (input_frame == GetMainFrame()) + password_autofill_agent_->FirstUserGestureObserved(); + } + input_frame->toWebLocalFrame()->autofillClient()->textFieldDidChange(input); // Processing is delayed because of a Blink bug: // https://bugs.webkit.org/show_bug.cgi?id=16976 // See PasswordAutofillAgent::TextDidChangeInTextField() for details. @@ -308,7 +322,7 @@ ->FormControlElementClicked(username_input, false); AutofillMsg_FillPasswordSuggestion msg(0, username, password); - static_cast<content::RenderViewObserver*>(autofill_agent_) + static_cast<content::RenderFrameObserver*>(autofill_agent_) ->OnMessageReceived(msg); } @@ -855,12 +869,13 @@ fill_data_.origin = GURL(origin); fill_data_.action = GURL(origin); - SimulateOnFillPasswordForm(fill_data_); - // Retrieve the input elements from the iframe since that is where we want to // test the autofill. WebFrame* iframe = GetMainFrame()->findChildByName(kIframeName); ASSERT_TRUE(iframe); + + SimulateOnFillPasswordFormForFrame(iframe, fill_data_); + WebDocument document = iframe->document(); WebElement username_element = document.getElementById(kUsernameName); @@ -1408,7 +1423,7 @@ // site's JavaScript before submit. username_element_.setValue(WebString()); password_element_.setValue(WebString()); - static_cast<content::RenderViewObserver*>(password_autofill_agent_) + static_cast<content::RenderViewObserver*>(&password_autofill_agent_->legacy_) ->WillSubmitForm(GetMainFrame(), username_element_.form()); // Observe that the PasswordAutofillAgent still remembered the last non-empty @@ -1432,7 +1447,7 @@ true); SimulateInputChangeForElement( "", true, GetMainFrame(), password_element_, true); - static_cast<content::RenderViewObserver*>(password_autofill_agent_) + static_cast<content::RenderViewObserver*>(&password_autofill_agent_->legacy_) ->WillSubmitForm(GetMainFrame(), username_element_.form()); // Observe that the PasswordAutofillAgent respects the user having cleared the @@ -1462,7 +1477,7 @@ // the site's JavaScript before submit. username_element_.setValue(WebString()); password_element_.setValue(WebString()); - static_cast<content::RenderViewObserver*>(password_autofill_agent_) + static_cast<content::RenderViewObserver*>(&password_autofill_agent_->legacy_) ->WillSubmitForm(GetMainFrame(), username_element_.form()); // Observe that the PasswordAutofillAgent still remembered the last non-empty
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc index c2506e8d..62fc9409 100644 --- a/chrome/renderer/chrome_content_renderer_client.cc +++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -72,6 +72,7 @@ #include "components/visitedlink/renderer/visitedlink_slave.h" #include "components/web_cache/renderer/web_cache_render_process_observer.h" #include "content/public/common/content_constants.h" +#include "content/public/renderer/plugin_power_saver_helper.h" #include "content/public/renderer/render_frame.h" #include "content/public/renderer/render_thread.h" #include "content/public/renderer/render_view.h" @@ -184,10 +185,10 @@ }; #endif -static void AppendParams(const std::vector<base::string16>& additional_names, - const std::vector<base::string16>& additional_values, - WebVector<WebString>* existing_names, - WebVector<WebString>* existing_values) { +void AppendParams(const std::vector<base::string16>& additional_names, + const std::vector<base::string16>& additional_values, + WebVector<WebString>* existing_names, + WebVector<WebString>* existing_values) { DCHECK(additional_names.size() == additional_values.size()); DCHECK(existing_names->size() == existing_values->size()); @@ -486,6 +487,13 @@ new NetErrorHelper(render_frame); new prefetch::PrefetchHelper(render_frame); } + + PasswordGenerationAgent* password_generation_agent = + new PasswordGenerationAgent(render_frame); + PasswordAutofillAgent* password_autofill_agent = + new PasswordAutofillAgent(render_frame); + new AutofillAgent(render_frame, password_autofill_agent, + password_generation_agent); } void ChromeContentRendererClient::RenderViewCreated( @@ -506,14 +514,6 @@ safe_browsing::MalwareDOMDetails::Create(render_view); #endif - PasswordGenerationAgent* password_generation_agent = - new PasswordGenerationAgent(render_view); - PasswordAutofillAgent* password_autofill_agent = - new PasswordAutofillAgent(render_view); - new AutofillAgent(render_view, - password_autofill_agent, - password_generation_agent); - CommandLine* command_line = CommandLine::ForCurrentProcess(); if (command_line->HasSwitch(switches::kInstantProcess)) new SearchBox(render_view); @@ -709,6 +709,14 @@ } #endif + auto create_blocked_plugin = + [&render_frame, &frame, ¶ms, &plugin, &identifier, &group_name]( + int template_id, const base::string16& message, + const GURL& poster_url) { + return ChromePluginPlaceholder::CreateBlockedPlugin( + render_frame, frame, params, plugin, identifier, group_name, + template_id, message, poster_url); + }; switch (status_value) { case ChromeViewHostMsg_GetPluginInfo_Status::kNotFound: { NOTREACHED(); @@ -764,39 +772,45 @@ frame->addMessageToConsole( WebConsoleMessage(WebConsoleMessage::LevelError, error_message)); - placeholder = ChromePluginPlaceholder::CreateBlockedPlugin( - render_frame, - frame, - params, - plugin, - identifier, - group_name, + placeholder = create_blocked_plugin( IDR_BLOCKED_PLUGIN_HTML, #if defined(OS_CHROMEOS) - l10n_util::GetStringUTF16(IDS_NACL_PLUGIN_BLOCKED)); + l10n_util::GetStringUTF16(IDS_NACL_PLUGIN_BLOCKED), #else - l10n_util::GetStringFUTF16(IDS_PLUGIN_BLOCKED, group_name)); + l10n_util::GetStringFUTF16(IDS_PLUGIN_BLOCKED, group_name), #endif + GURL()); break; } } #endif // !defined(DISABLE_NACL) && defined(ENABLE_EXTENSIONS) - GURL poster_url = ChromePluginPlaceholder::GetPluginInstancePosterImage( + bool show_poster = false; + GURL poster_url; + +#if defined(ENABLE_PLUGINS) + content::PluginPowerSaverHelper* power_saver_helper = + render_frame->GetPluginPowerSaverHelper(); + poster_url = power_saver_helper->GetPluginInstancePosterImage( params, frame->document().url()); + show_poster = poster_url.is_valid() && + base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnablePluginPowerSaver); +#endif // Delay loading plugins if prerendering. // TODO(mmenke): In the case of prerendering, feed into // ChromeContentRendererClient::CreatePlugin instead, to // reduce the chance of future regressions. - if (prerender::PrerenderHelper::IsPrerendering(render_frame) || - poster_url.is_valid()) { - placeholder = ChromePluginPlaceholder::CreateBlockedPlugin( - render_frame, frame, params, plugin, identifier, group_name, - poster_url.is_valid() ? IDR_PLUGIN_POSTER_HTML - : IDR_CLICK_TO_PLAY_PLUGIN_HTML, - l10n_util::GetStringFUTF16(IDS_PLUGIN_LOAD, group_name)); - placeholder->set_blocked_for_prerendering(true); + bool is_prerendering = + prerender::PrerenderHelper::IsPrerendering(render_frame); + if (is_prerendering || show_poster) { + placeholder = create_blocked_plugin( + show_poster ? IDR_PLUGIN_POSTER_HTML + : IDR_CLICK_TO_PLAY_PLUGIN_HTML, + l10n_util::GetStringFUTF16(IDS_PLUGIN_LOAD, group_name), + poster_url); + placeholder->set_blocked_for_prerendering(is_prerendering); placeholder->set_allow_loading(true); break; } @@ -808,15 +822,9 @@ case ChromeViewHostMsg_GetPluginInfo_Status::kNPAPINotSupported: { RenderThread::Get()->RecordAction( UserMetricsAction("Plugin_NPAPINotSupported")); - placeholder = ChromePluginPlaceholder::CreateBlockedPlugin( - render_frame, - frame, - params, - plugin, - identifier, - group_name, + placeholder = create_blocked_plugin( IDR_BLOCKED_PLUGIN_HTML, - l10n_util::GetStringUTF16(IDS_PLUGIN_NOT_SUPPORTED_METRO)); + l10n_util::GetStringUTF16(IDS_PLUGIN_NOT_SUPPORTED_METRO), GURL()); render_frame->Send(new ChromeViewHostMsg_NPAPINotSupported( render_frame->GetRoutingID(), identifier)); break; @@ -824,28 +832,18 @@ case ChromeViewHostMsg_GetPluginInfo_Status::kDisabled: { PluginUMAReporter::GetInstance()->ReportPluginDisabled(orig_mime_type, url); - placeholder = ChromePluginPlaceholder::CreateBlockedPlugin( - render_frame, - frame, - params, - plugin, - identifier, - group_name, + placeholder = create_blocked_plugin( IDR_DISABLED_PLUGIN_HTML, - l10n_util::GetStringFUTF16(IDS_PLUGIN_DISABLED, group_name)); + l10n_util::GetStringFUTF16(IDS_PLUGIN_DISABLED, group_name), + GURL()); break; } case ChromeViewHostMsg_GetPluginInfo_Status::kOutdatedBlocked: { #if defined(ENABLE_PLUGIN_INSTALLATION) - placeholder = ChromePluginPlaceholder::CreateBlockedPlugin( - render_frame, - frame, - params, - plugin, - identifier, - group_name, + placeholder = create_blocked_plugin( IDR_BLOCKED_PLUGIN_HTML, - l10n_util::GetStringFUTF16(IDS_PLUGIN_OUTDATED, group_name)); + l10n_util::GetStringFUTF16(IDS_PLUGIN_OUTDATED, group_name), + GURL()); placeholder->set_allow_loading(true); render_frame->Send(new ChromeViewHostMsg_BlockedOutdatedPlugin( render_frame->GetRoutingID(), placeholder->CreateRoutingId(), @@ -856,27 +854,17 @@ break; } case ChromeViewHostMsg_GetPluginInfo_Status::kOutdatedDisallowed: { - placeholder = ChromePluginPlaceholder::CreateBlockedPlugin( - render_frame, - frame, - params, - plugin, - identifier, - group_name, + placeholder = create_blocked_plugin( IDR_BLOCKED_PLUGIN_HTML, - l10n_util::GetStringFUTF16(IDS_PLUGIN_OUTDATED, group_name)); + l10n_util::GetStringFUTF16(IDS_PLUGIN_OUTDATED, group_name), + GURL()); break; } case ChromeViewHostMsg_GetPluginInfo_Status::kUnauthorized: { - placeholder = ChromePluginPlaceholder::CreateBlockedPlugin( - render_frame, - frame, - params, - plugin, - identifier, - group_name, + placeholder = create_blocked_plugin( IDR_BLOCKED_PLUGIN_HTML, - l10n_util::GetStringFUTF16(IDS_PLUGIN_NOT_AUTHORIZED, group_name)); + l10n_util::GetStringFUTF16(IDS_PLUGIN_NOT_AUTHORIZED, group_name), + GURL()); placeholder->set_allow_loading(true); // Check to see if old infobar should be displayed. std::string trial_group = @@ -894,15 +882,9 @@ break; } case ChromeViewHostMsg_GetPluginInfo_Status::kClickToPlay: { - placeholder = ChromePluginPlaceholder::CreateBlockedPlugin( - render_frame, - frame, - params, - plugin, - identifier, - group_name, + placeholder = create_blocked_plugin( IDR_CLICK_TO_PLAY_PLUGIN_HTML, - l10n_util::GetStringFUTF16(IDS_PLUGIN_LOAD, group_name)); + l10n_util::GetStringFUTF16(IDS_PLUGIN_LOAD, group_name), GURL()); placeholder->set_allow_loading(true); RenderThread::Get()->RecordAction( UserMetricsAction("Plugin_ClickToPlay")); @@ -910,30 +892,18 @@ break; } case ChromeViewHostMsg_GetPluginInfo_Status::kBlocked: { - placeholder = ChromePluginPlaceholder::CreateBlockedPlugin( - render_frame, - frame, - params, - plugin, - identifier, - group_name, + placeholder = create_blocked_plugin( IDR_BLOCKED_PLUGIN_HTML, - l10n_util::GetStringFUTF16(IDS_PLUGIN_BLOCKED, group_name)); + l10n_util::GetStringFUTF16(IDS_PLUGIN_BLOCKED, group_name), GURL()); placeholder->set_allow_loading(true); RenderThread::Get()->RecordAction(UserMetricsAction("Plugin_Blocked")); observer->DidBlockContentType(content_type); break; } case ChromeViewHostMsg_GetPluginInfo_Status::kBlockedByPolicy: { - placeholder = ChromePluginPlaceholder::CreateBlockedPlugin( - render_frame, - frame, - params, - plugin, - identifier, - group_name, + placeholder = create_blocked_plugin( IDR_BLOCKED_PLUGIN_HTML, - l10n_util::GetStringFUTF16(IDS_PLUGIN_BLOCKED, group_name)); + l10n_util::GetStringFUTF16(IDS_PLUGIN_BLOCKED, group_name), GURL()); placeholder->set_allow_loading(false); RenderThread::Get()->RecordAction( UserMetricsAction("Plugin_BlockedByPolicy"));
diff --git a/chrome/renderer/media/cast_rtp_stream.cc b/chrome/renderer/media/cast_rtp_stream.cc index 1126df2b..00783b2 100644 --- a/chrome/renderer/media/cast_rtp_stream.cc +++ b/chrome/renderer/media/cast_rtp_stream.cc
@@ -20,9 +20,9 @@ #include "content/public/renderer/video_encode_accelerator.h" #include "media/audio/audio_parameters.h" #include "media/base/audio_bus.h" +#include "media/base/audio_converter.h" #include "media/base/audio_fifo.h" #include "media/base/bind_to_current_loop.h" -#include "media/base/multi_channel_resampler.h" #include "media/base/video_frame.h" #include "media/cast/cast_config.h" #include "media/cast/cast_defines.h" @@ -43,13 +43,6 @@ // To convert from kilobits per second to bits to per second. const int kBitrateMultiplier = 1000; -// This constant defines the number of sets of audio data to buffer -// in the FIFO. If input audio and output data have different resampling -// rates then buffer is necessary to avoid audio glitches. -// See CastAudioSink::ResampleData() and CastAudioSink::OnSetFormat() -// for more defaults. -const int kBufferAudioData = 2; - CastRtpPayloadParams DefaultOpusPayload() { CastRtpPayloadParams payload; payload.payload_type = 127; @@ -347,111 +340,31 @@ // Note that RemoveFromAudioTrack() is synchronous and we have // gurantee that there will be no more audio data after calling it. class CastAudioSink : public base::SupportsWeakPtr<CastAudioSink>, - public content::MediaStreamAudioSink { + public content::MediaStreamAudioSink, + public media::AudioConverter::InputCallback { public: // |track| provides data for this sink. // |error_callback| is called if audio formats don't match. CastAudioSink(const blink::WebMediaStreamTrack& track, - const CastRtpStream::ErrorCallback& error_callback, int output_channels, int output_sample_rate) : track_(track), - sink_added_(false), - error_callback_(error_callback), - weak_factory_(this), output_channels_(output_channels), output_sample_rate_(output_sample_rate), - input_preroll_(0) {} + sample_frames_in_(0), + sample_frames_out_(0) {} ~CastAudioSink() override { - if (sink_added_) + if (frame_input_.get()) RemoveFromAudioTrack(this, track_); } - // Called on real-time audio thread. - // content::MediaStreamAudioSink implementation. - void OnData(const int16* audio_data, - int sample_rate, - int number_of_channels, - int number_of_frames) override { - scoped_ptr<media::AudioBus> input_bus; - if (resampler_) { - input_bus = ResampleData( - audio_data, sample_rate, number_of_channels, number_of_frames); - if (!input_bus) - return; - } else { - input_bus = media::AudioBus::Create( - number_of_channels, number_of_frames); - input_bus->FromInterleaved( - audio_data, number_of_frames, number_of_channels); - } - - // TODO(hclam): Pass in the accurate capture time to have good - // audio / video sync. - frame_input_->InsertAudio(input_bus.Pass(), base::TimeTicks::Now()); - } - - // Return a resampled audio data from input. This is called when the - // input sample rate doesn't match the output. - // The flow of data is as follows: - // |audio_data| -> - // AudioFifo |fifo_| -> - // MultiChannelResampler |resampler|. - // - // The resampler pulls data out of the FIFO and resample the data in - // frequency domain. It might call |fifo_| for more than once. But no more - // than |kBufferAudioData| times. We preroll audio data into the FIFO to - // make sure there's enough data for resampling. - scoped_ptr<media::AudioBus> ResampleData( - const int16* audio_data, - int sample_rate, - int number_of_channels, - int number_of_frames) { - DCHECK_EQ(number_of_channels, output_channels_); - fifo_input_bus_->FromInterleaved( - audio_data, number_of_frames, number_of_channels); - fifo_->Push(fifo_input_bus_.get()); - - if (input_preroll_ < kBufferAudioData - 1) { - ++input_preroll_; - return scoped_ptr<media::AudioBus>(); - } - - scoped_ptr<media::AudioBus> output_bus( - media::AudioBus::Create( - output_channels_, - output_sample_rate_ * fifo_input_bus_->frames() / sample_rate)); - - // Resampler will then call ProvideData() below to fetch data from - // |input_data_|. - resampler_->Resample(output_bus->frames(), output_bus.get()); - return output_bus.Pass(); - } - - // Called on real-time audio thread. - void OnSetFormat(const media::AudioParameters& params) override { - if (params.sample_rate() == output_sample_rate_) - return; - fifo_.reset(new media::AudioFifo( - output_channels_, - kBufferAudioData * params.frames_per_buffer())); - fifo_input_bus_ = media::AudioBus::Create( - params.channels(), params.frames_per_buffer()); - resampler_.reset(new media::MultiChannelResampler( - output_channels_, - static_cast<double>(params.sample_rate()) / output_sample_rate_, - params.frames_per_buffer(), - base::Bind(&CastAudioSink::ProvideData, base::Unretained(this)))); - } - // Add this sink to the track. Data received from the track will be // submitted to |frame_input|. void AddToTrack( const scoped_refptr<media::cast::AudioFrameInput>& frame_input) { - DCHECK(!sink_added_); - sink_added_ = true; - + DCHECK(frame_input.get()); + DCHECK(!frame_input_.get()); // This member is written here and then accessed on the IO thread // We will not get data until AddToAudioTrack is called so it is // safe to access this member now. @@ -459,25 +372,134 @@ AddToAudioTrack(this, track_); } - void ProvideData(int frame_delay, media::AudioBus* output_bus) { - fifo_->Consume(output_bus, 0, output_bus->frames()); + protected: + // Called on real-time audio thread. + // TODO(miu): This interface is horrible: The first arg should be an AudioBus, + // while the remaining three are redundant as they are provided in the call to + // OnSetFormat(). http://crbug.com/437064 + void OnData(const int16* audio_data, + int sample_rate, + int number_of_channels, + int number_of_sample_frames) override { + DCHECK(audio_data); + DCHECK_EQ(sample_rate, input_params_.sample_rate()); + DCHECK_EQ(number_of_channels, input_params_.channels()); + DCHECK_EQ(number_of_sample_frames, input_params_.frames_per_buffer()); + + // TODO(miu): Plumbing is needed to determine the actual reference timestamp + // of the audio for proper audio/video sync. http://crbug.com/335335 + base::TimeTicks reference_time = base::TimeTicks::Now(); + + if (converter_) { + // Make an adjustment to the |reference_time| to account for the portion + // of the audio signal enqueued within |fifo_| and |converter_|. + const base::TimeDelta signal_duration_already_buffered = + (sample_frames_in_ * base::TimeDelta::FromSeconds(1) / + input_params_.sample_rate()) - + (sample_frames_out_ * base::TimeDelta::FromSeconds(1) / + output_sample_rate_); + DVLOG(2) << "Audio reference time adjustment: -(" + << signal_duration_already_buffered.InMicroseconds() << " us)"; + reference_time -= signal_duration_already_buffered; + + // TODO(miu): Eliminate need for extra copying of samples to do + // resampling. This will require AudioConverter changes. + fifo_input_bus_->FromInterleaved( + audio_data, input_params_.frames_per_buffer(), sizeof(audio_data[0])); + const int fifo_frames_remaining = fifo_->max_frames() - fifo_->frames(); + if (fifo_frames_remaining < input_params_.frames_per_buffer()) { + NOTREACHED() + << "Audio FIFO overrun: " << input_params_.frames_per_buffer() + << " > " << fifo_frames_remaining; + sample_frames_in_ -= fifo_->frames(); + fifo_->Clear(); + } + fifo_->Push(fifo_input_bus_.get()); + sample_frames_in_ += input_params_.frames_per_buffer(); + + const int sample_frames_out_per_chunk = + output_sample_rate_ * input_params_.frames_per_buffer() / + input_params_.sample_rate(); + while (fifo_->frames() >= converter_->ChunkSize()) { + scoped_ptr<media::AudioBus> audio_bus = media::AudioBus::Create( + output_channels_, sample_frames_out_per_chunk); + // AudioConverter will call ProvideInput() to fetch data from |fifo_|. + converter_->Convert(audio_bus.get()); + sample_frames_out_ += sample_frames_out_per_chunk; + frame_input_->InsertAudio(audio_bus.Pass(), reference_time); + reference_time += + sample_frames_out_per_chunk * base::TimeDelta::FromSeconds(1) / + output_sample_rate_; + } + } else { + scoped_ptr<media::AudioBus> audio_bus = media::AudioBus::Create( + input_params_.channels(), input_params_.frames_per_buffer()); + audio_bus->FromInterleaved( + audio_data, input_params_.frames_per_buffer(), sizeof(audio_data[0])); + frame_input_->InsertAudio(audio_bus.Pass(), reference_time); + } + } + + // Called on real-time audio thread. + void OnSetFormat(const media::AudioParameters& params) override { + if (input_params_.Equals(params)) + return; + input_params_ = params; + + if (input_params_.channels() == output_channels_ && + input_params_.sample_rate() == output_sample_rate_) { + DVLOG(1) << "No audio resampling is needed."; + converter_.reset(); + fifo_input_bus_.reset(); + fifo_.reset(); + } else { + DVLOG(1) << "Setting up audio resampling: {" + << input_params_.channels() << " channels, " + << input_params_.sample_rate() << " Hz} --> {" + << output_channels_ << " channels, " + << output_sample_rate_ << " Hz}"; + const media::AudioParameters output_params( + media::AudioParameters::AUDIO_PCM_LOW_LATENCY, + media::GuessChannelLayout(output_channels_), + output_sample_rate_, 32, + output_sample_rate_ * input_params_.frames_per_buffer() / + input_params_.sample_rate()); + converter_.reset( + new media::AudioConverter(input_params_, output_params, false)); + converter_->AddInput(this); + fifo_input_bus_ = media::AudioBus::Create( + input_params_.channels(), input_params_.frames_per_buffer()); + fifo_.reset(new media::AudioFifo( + input_params_.channels(), + converter_->ChunkSize() + input_params_.frames_per_buffer())); + sample_frames_in_ = 0; + sample_frames_out_ = 0; + } + } + + // Called on real-time audio thread. + double ProvideInput(media::AudioBus* audio_bus, + base::TimeDelta buffer_delay) override { + fifo_->Consume(audio_bus, 0, audio_bus->frames()); + return 1.0; } private: - blink::WebMediaStreamTrack track_; - bool sink_added_; - CastRtpStream::ErrorCallback error_callback_; - base::WeakPtrFactory<CastAudioSink> weak_factory_; - + const blink::WebMediaStreamTrack track_; const int output_channels_; const int output_sample_rate_; - // These member are accessed on the real-time audio time only. + // This must be set before the real-time audio thread starts calling OnData(), + // and remain unchanged until after the thread will stop calling OnData(). scoped_refptr<media::cast::AudioFrameInput> frame_input_; - scoped_ptr<media::MultiChannelResampler> resampler_; - scoped_ptr<media::AudioFifo> fifo_; + + // These members are accessed on the real-time audio time only. + media::AudioParameters input_params_; + scoped_ptr<media::AudioConverter> converter_; scoped_ptr<media::AudioBus> fifo_input_bus_; - int input_preroll_; + scoped_ptr<media::AudioFifo> fifo_; + int64 sample_frames_in_; + int64 sample_frames_out_; DISALLOW_COPY_AND_ASSIGN(CastAudioSink); }; @@ -543,8 +565,6 @@ // the streaming after reporting the error. audio_sink_.reset(new CastAudioSink( track_, - media::BindToCurrentLoop(base::Bind(&CastRtpStream::DidEncounterError, - weak_factory_.GetWeakPtr())), params.payload.channels, params.payload.clock_rate)); cast_session_->StartAudio(
diff --git a/chrome/renderer/plugins/chrome_plugin_placeholder.cc b/chrome/renderer/plugins/chrome_plugin_placeholder.cc index fdcb395b..9aebe52 100644 --- a/chrome/renderer/plugins/chrome_plugin_placeholder.cc +++ b/chrome/renderer/plugins/chrome_plugin_placeholder.cc
@@ -44,8 +44,6 @@ namespace { const plugins::PluginPlaceholder* g_last_active_menu = NULL; - -const char kPosterParamName[] = "poster"; } // namespace // The placeholder is loaded in normal web renderer processes, so it should not @@ -91,19 +89,6 @@ } // static -GURL ChromePluginPlaceholder::GetPluginInstancePosterImage( - const blink::WebPluginParams& params, - const GURL& base_url) { - DCHECK_EQ(params.attributeNames.size(), params.attributeValues.size()); - for (size_t i = 0; i < params.attributeNames.size(); ++i) { - if (params.attributeNames[i] == kPosterParamName) { - return base_url.Resolve(params.attributeValues[i].utf8()); - } - } - return GURL(); -} - -// static ChromePluginPlaceholder* ChromePluginPlaceholder::CreateMissingPlugin( content::RenderFrame* render_frame, WebLocalFrame* frame, @@ -167,14 +152,13 @@ const std::string& identifier, const base::string16& name, int template_id, - const base::string16& message) { + const base::string16& message, + const GURL& poster_url) { base::DictionaryValue values; values.SetString("message", message); values.SetString("name", name); values.SetString("hide", l10n_util::GetStringUTF8(IDS_PLUGIN_HIDE)); - GURL poster_url = - GetPluginInstancePosterImage(params, frame->document().url()); if (poster_url.is_valid()) values.SetString("background", "url('" + poster_url.spec() + "')"); @@ -188,6 +172,11 @@ // |blocked_plugin| will destroy itself when its WebViewPlugin is going away. ChromePluginPlaceholder* blocked_plugin = new ChromePluginPlaceholder( render_frame, frame, params, html_data, name); + +#if defined(ENABLE_PLUGINS) + if (poster_url.is_valid()) + blocked_plugin->BlockForPowerSaver(); +#endif blocked_plugin->SetPluginInfo(plugin); blocked_plugin->SetIdentifier(identifier); return blocked_plugin; @@ -322,7 +311,7 @@ switch (action) { case chrome::MENU_COMMAND_PLUGIN_RUN: { RenderThread::Get()->RecordAction(UserMetricsAction("Plugin_Load_Menu")); - LoadPlugin(); + LoadPlugin(content::RenderFrame::CREATE_PLUGIN_GESTURE_HAS_USER_GESTURE); break; } case chrome::MENU_COMMAND_PLUGIN_HIDE: {
diff --git a/chrome/renderer/plugins/chrome_plugin_placeholder.h b/chrome/renderer/plugins/chrome_plugin_placeholder.h index 617a83e..c9fa1ef6 100644 --- a/chrome/renderer/plugins/chrome_plugin_placeholder.h +++ b/chrome/renderer/plugins/chrome_plugin_placeholder.h
@@ -15,11 +15,6 @@ public: static const char kPluginPlaceholderDataURL[]; - // Returns the absolute (resolved) URL of the poster image. - // Returns an empty GURL if there is no poster image parameter. - static GURL GetPluginInstancePosterImage(const blink::WebPluginParams& params, - const GURL& base_url); - static ChromePluginPlaceholder* CreateBlockedPlugin( content::RenderFrame* render_frame, blink::WebLocalFrame* frame, @@ -28,7 +23,8 @@ const std::string& identifier, const base::string16& name, int resource_id, - const base::string16& message); + const base::string16& message, + const GURL& poster_url); // Creates a new WebViewPlugin with a MissingPlugin as a delegate. static ChromePluginPlaceholder* CreateMissingPlugin(
diff --git a/chrome/renderer/resources/extensions/automation/automation_node.js b/chrome/renderer/resources/extensions/automation/automation_node.js index c425244..9dcf6261 100644 --- a/chrome/renderer/resources/extensions/automation/automation_node.js +++ b/chrome/renderer/resources/extensions/automation/automation_node.js
@@ -773,8 +773,7 @@ } // If this is an editable text area, set editable text attributes. - if (nodeData.role == schema.RoleType.editableText || - nodeData.role == schema.RoleType.textField || + if (nodeData.role == schema.RoleType.textField || nodeData.role == schema.RoleType.textArea) { this.mixinAttributes_(nodeImpl, EditableTextMixinAttributes, nodeData); }
diff --git a/chrome/renderer/resources/extensions/extension_options.js b/chrome/renderer/resources/extensions/extension_options.js index 32221a6b..e518e29 100644 --- a/chrome/renderer/resources/extensions/extension_options.js +++ b/chrome/renderer/resources/extensions/extension_options.js
@@ -5,12 +5,12 @@ var DocumentNatives = requireNative('document_natives'); var ExtensionOptionsEvents = require('extensionOptionsEvents').ExtensionOptionsEvents; +var GuestView = require('guestView').GuestView; var GuestViewContainer = require('guestViewContainer').GuestViewContainer; var GuestViewInternal = require('binding').Binding.create('guestViewInternal').generate(); var IdGenerator = requireNative('id_generator'); var utils = require('utils'); -var guestViewInternalNatives = requireNative('guest_view_internal'); // Mapping of the autosize attribute names to default values var AUTO_SIZE_ATTRIBUTES = { @@ -24,10 +24,8 @@ function ExtensionOptionsImpl(extensionoptionsElement) { GuestViewContainer.call(this, extensionoptionsElement) + this.guest = new GuestView('extensionoptions'); this.viewInstanceId = IdGenerator.GetNextId(); - this.guestInstanceId = 0; - this.pendingGuestCreation = false; - this.autosizeDeferred = false; // on* Event handlers. @@ -41,7 +39,6 @@ new ExtensionOptionsEvents(this, this.viewInstanceId); this.setupElementProperties(); - this.parseExtensionAttribute(); // Once the browser plugin has been created, the guest view will be created @@ -66,59 +63,53 @@ } ExtensionOptionsImpl.prototype.onElementDetached = function() { - if (this.guestInstanceId) { - GuestViewInternal.destroyGuest(this.guestInstanceId); - this.guestInstanceId = undefined; - } + this.guest.destroy(); +}; + +ExtensionOptionsImpl.prototype.buildAttachParams = function() { + var params = { + 'autosize': this.element.hasAttribute('autosize'), + 'instanceId': this.viewInstanceId, + 'maxheight': parseInt(this.maxheight || 0), + 'maxwidth': parseInt(this.maxwidth || 0), + 'minheight': parseInt(this.minheight || 0), + 'minwidth': parseInt(this.minwidth || 0) + }; + return params; }; ExtensionOptionsImpl.prototype.attachWindow = function() { - return guestViewInternalNatives.AttachGuest( - this.internalInstanceId, - this.guestInstanceId, - { - 'autosize': this.element.hasAttribute('autosize'), - 'instanceId': this.viewInstanceId, - 'maxheight': parseInt(this.maxheight || 0), - 'maxwidth': parseInt(this.maxwidth || 0), - 'minheight': parseInt(this.minheight || 0), - 'minwidth': parseInt(this.minwidth || 0) - }); + if (!this.internalInstanceId) { + return true; + } + + this.guest.attach(this.internalInstanceId, this.buildAttachParams()); + return true; }; ExtensionOptionsImpl.prototype.createGuestIfNecessary = function() { - if (!this.elementAttached || this.pendingGuestCreation) { + if (!this.elementAttached) { return; } - if (this.guestInstanceId != 0) { + if (this.guest.getId() != 0) { this.attachWindow(); return; } var params = { 'extensionId': this.extensionId, }; - GuestViewInternal.createGuest( - 'extensionoptions', - params, - function(guestInstanceId) { - this.pendingGuestCreation = false; - if (guestInstanceId && !this.elementAttached) { - GuestViewInternal.destroyGuest(guestInstanceId); - guestInstanceId = 0; - } - if (guestInstanceId == 0) { - // Fire a createfailed event here rather than in ExtensionOptionsGuest - // because the guest will not be created, and cannot fire an event. - this.initCalled = false; - var createFailedEvent = new Event('createfailed', { bubbles: true }); - this.dispatchEvent(createFailedEvent); - } else { - this.guestInstanceId = guestInstanceId; - this.attachWindow(); - } - }.bind(this) - ); - this.pendingGuestCreation = true; + + this.guest.create(params, function() { + if (!this.guest.getId()) { + // Fire a createfailed event here rather than in ExtensionOptionsGuest + // because the guest will not be created, and cannot fire an event. + this.initCalled = false; + var createFailedEvent = new Event('createfailed', { bubbles: true }); + this.dispatchEvent(createFailedEvent); + } else { + this.attachWindow(); + } + }.bind(this)); }; ExtensionOptionsImpl.prototype.dispatchEvent = @@ -144,7 +135,7 @@ return; // If a guest view does not exist then create one. - if (!this.guestInstanceId) { + if (!this.guest.getId()) { this.createGuestIfNecessary(); return; } @@ -154,10 +145,10 @@ this[name] = newValue; this.resetSizeConstraintsIfInvalid(); - if (!this.guestInstanceId) + if (!this.guest.getId()) return; - GuestViewInternal.setAutoSize(this.guestInstanceId, { + GuestViewInternal.setAutoSize(this.guest.getId(), { 'enableAutoSize': this.element.hasAttribute('autosize'), 'min': { 'width': parseInt(this.minwidth || 0), @@ -217,7 +208,7 @@ if (newHeight > this.minheight) this.minheight = newHeight; - GuestViewInternal.setAutoSize(this.guestInstanceId, { + GuestViewInternal.setAutoSize(this.guest.getId(), { 'enableAutoSize': this.element.hasAttribute('autosize'), 'min': { 'width': parseInt(this.minwidth || 0),
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index a853981..a06621d4 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -326,7 +326,7 @@ "../browser/sync/test/integration/two_client_app_list_sync_test.cc", ] } - if (!enable_managed_users) { + if (!enable_supervised_users) { sources -= [ "../browser/sync/test/integration/single_client_supervised_user_settings_sync_test.cc", ]
diff --git a/chrome/test/base/chrome_render_view_test.cc b/chrome/test/base/chrome_render_view_test.cc index da8e1458..4f47f69 100644 --- a/chrome/test/base/chrome_render_view_test.cc +++ b/chrome/test/base/chrome_render_view_test.cc
@@ -64,13 +64,16 @@ content::RenderViewTest::SetUp(); - // RenderView doesn't expose its Agent objects, because it has no need to - // store them directly (they're stored as RenderViewObserver*). So just + // RenderFrame doesn't expose its Agent objects, because it has no need to + // store them directly (they're stored as RenderFrameObserver*). So just // create another set. - password_autofill_agent_ = new autofill::TestPasswordAutofillAgent(view_); - password_generation_ = new autofill::TestPasswordGenerationAgent(view_); + password_autofill_agent_ = + new autofill::TestPasswordAutofillAgent(view_->GetMainRenderFrame()); + password_generation_ = + new autofill::TestPasswordGenerationAgent(view_->GetMainRenderFrame()); autofill_agent_ = - new AutofillAgent(view_, password_autofill_agent_, password_generation_); + new AutofillAgent(view_->GetMainRenderFrame(), password_autofill_agent_, + password_generation_); } void ChromeRenderViewTest::TearDown() {
diff --git a/chrome/test/base/testing_profile.cc b/chrome/test/base/testing_profile.cc index b9c45d3..c367e86 100644 --- a/chrome/test/base/testing_profile.cc +++ b/chrome/test/base/testing_profile.cc
@@ -94,7 +94,7 @@ #include "chrome/browser/signin/android_profile_oauth2_token_service.h" #endif -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) #include "chrome/browser/supervised_user/supervised_user_settings_service.h" #include "chrome/browser/supervised_user/supervised_user_settings_service_factory.h" #endif @@ -393,7 +393,7 @@ this, CreateTestDesktopNotificationService); #endif -#if defined(ENABLE_MANAGED_USERS) +#if defined(ENABLE_SUPERVISED_USERS) if (!IsOffTheRecord()) { SupervisedUserSettingsService* settings_service = SupervisedUserSettingsServiceFactory::GetForProfile(this);
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py index 9c00f53..2f9b0830 100755 --- a/chrome/test/chromedriver/test/run_py_tests.py +++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -50,6 +50,8 @@ # This test is flaky since it uses setTimeout. # Re-enable once crbug.com/177511 is fixed and we can remove setTimeout. 'ChromeDriverTest.testAlert', + # https://code.google.com/p/chromedriver/issues/detail?id=980 + 'ChromeDriverTest.testGoBackAndGoForward', ] _VERSION_SPECIFIC_FILTER = {} @@ -83,8 +85,6 @@ 'ChromeDriverTest.testWindowSize', ] _OS_SPECIFIC_FILTER['mac'] = [ - # https://code.google.com/p/chromedriver/issues/detail?id=304 - 'ChromeDriverTest.testGoBackAndGoForward', ] _DESKTOP_NEGATIVE_FILTER = [
diff --git a/chrome/test/data/autofill/heuristics/input/24_checkout_harryanddavid.com.html b/chrome/test/data/autofill/heuristics/input/24_checkout_harryanddavid.com.html new file mode 100644 index 0000000..a5efb99 --- /dev/null +++ b/chrome/test/data/autofill/heuristics/input/24_checkout_harryanddavid.com.html
@@ -0,0 +1,370 @@ +<form id="editAddressForm_45381448" name="editAddressForm" > + <input type="hidden" name="idx" value="45381448"> + + <input type="hidden" name="orderItemId" value="45381448"> + + <input type="hidden" name="countryOptIn" id="countryOptIn2" value="US"> + + <input type="hidden" name="orderId" value="14146734"> + + <div id="addressSection1_45381448" > + <div > + +<div > + <div ></div> + <div > + <input type="checkbox" id="chkBusinessAddress_45381448" name="typeOfAddress" value="H" onclick="addressHelper.addressTypeSelected('45381448');"><label for="chkBusinessAddress_45381448">Business address</label> + </div> +</div> + + <div >Required field <span >*</span></div> + </div> + + <div > + + <div id="title_45381448" > + +<div > + <div >Title</div> + <div > + <select id="personTitle_45381448" name="personTitle" dojoattachpoint="focusNode,valueNode,textbox,comboNode,containerNode" dojoattachevent="onchange: _selectOption" autocomplete="off" tabindex="0" widgetid="personTitle_45381448"><option value="" id="personTitle_45381448ph" >- Select Title -</option> + + <option value="MR/MRS">MR/MRS</option> + + <option value="MR/MS">MR/MS</option> + + <option value="MRS">MRS</option> + + <option value="MR">MR</option> + + <option value="DR">DR</option> + + <option value="MS">MS</option> + + <option value="DR/MR">DR/MR</option> + + <option value="DR/MRS">DR/MRS</option> + + <option value="MISS">MISS</option> + + </select> + </div> +</div> + + </div> + + + <div dojotype="dojo.data.ItemFileReadStore" id="relationStore_45381448" jsid="relationStore_45381448" clearonclose="true" url="/gifts/store/BECAjaxIncludeView?storeId=10455&includePage=Snippets/LookupDataJSON.jsp&lookupIdentifier=lookup-relationship"></div> + + +<div > + <div >Relationship</div> + <div > + <select id="recipientRelation_45381448" name="recipientRelation" dojoattachpoint="focusNode,valueNode,textbox,comboNode,containerNode" dojoattachevent="onchange: _selectOption" autocomplete="off" tabindex="0" widgetid="recipientRelation_45381448"><option value="0" id="recipientRelation_45381448ph" >- Select Relationship -</option><option value="MOM">Mom</option><option value="DAD">Dad</option><option value="SIS">Sister</option><option value="BRO">Brother</option><option value="HUS">Husband</option><option value="WIF">Wife</option><option value="GPT">Grandparent</option><option value="DAU">Daughter</option><option value="SON">Son</option><option value="ORE">Other Relative</option><option value="SEL">Myself</option><option value="FND">Friend</option><option value="BFD">Boyfriend</option><option value="GFD">Girlfriend</option><option value="CWK">Co-worker</option><option value="CLI">Client</option><option value="PTR">Partner</option><option value="OTR">Other</option></select> + </div> +</div> + + </div> + + <div id="businessAddressArea_45381448" > + +<div > + <div >Company name<span >*</span></div> + <div > + <div id="widget_organizationName_45381448" role="presentation" widgetid="organizationName_45381448"><div ><input value="Χ " type="text" tabindex="-1" readonly="readonly" role="presentation"></div><div ><input data-dojo-attach-point="textbox,focusNode" autocomplete="on" name="organizationName" type="text" tabindex="0" id="organizationName_45381448" maxlength="24" size="30" aria-invalid="true" aria-required="true" value=""></div></div> + </div> +</div> + +<div > + <div >Attn. Line<span >*</span></div> + <div > + <div id="widget_businessTitle_45381448" role="presentation" widgetid="businessTitle_45381448"><div ><input value="Χ " type="text" tabindex="-1" readonly="readonly" role="presentation"></div><div ><input data-dojo-attach-point="textbox,focusNode" autocomplete="on" name="businessTitle" type="text" tabindex="0" id="businessTitle_45381448" maxlength="30" size="31" aria-invalid="true" aria-required="true" value=""></div></div> + </div> +</div> + + <input type="hidden" name="organizationNameSave" value=""> + <input type="hidden" name="businessTitleSave" value=""> + </div> + + <div id="homeAddressArea_45381448" > + +<div > + <div >First Name<span >*</span></div> + <div > + <div id="widget_firstName_45381448" role="presentation" widgetid="firstName_45381448"><div ><input value="Χ " type="text" tabindex="-1" readonly="readonly" role="presentation"></div><div ><input data-dojo-attach-point="textbox,focusNode" autocomplete="on" name="firstName" type="text" tabindex="0" maxlength="15" id="firstName_45381448" aria-invalid="true" aria-required="true" value=""></div></div> + </div> +</div> + +<div > + <div >Last Name<span >*</span></div> + <div > + <div id="widget_lastName_45381448" role="presentation" widgetid="lastName_45381448"><div ><input value="Χ " type="text" tabindex="-1" readonly="readonly" role="presentation"></div><div ><input data-dojo-attach-point="textbox,focusNode" autocomplete="on" name="lastName" type="text" tabindex="0" maxlength="24" id="lastName_45381448" aria-invalid="true" aria-required="true" value=""></div></div> + </div> +</div> + + <input type="hidden" name="firstNameSave" value=""> + <input type="hidden" name="lastNameSave" value=""> + + +<div > + <div >Additional info</div> + <div > + <div id="widget_additionalName_45381448" role="presentation" widgetid="additionalName_45381448"><div ><input value="Χ " type="text" tabindex="-1" readonly="readonly" role="presentation"></div><div ><input data-dojo-attach-point="textbox,focusNode" autocomplete="on" name="middleName" type="text" tabindex="0" id="additionalName_45381448" maxlength="30" value=""><span >e.g., and Family</span></div></div> + </div> +</div> + + </div> + + <div ></div> + + <div > + +<div > + <div >Street address<span >*</span></div> + <div > + <div id="widget_address1_45381448" role="presentation" widgetid="address1_45381448"><div ><input value="Χ " type="text" tabindex="-1" readonly="readonly" role="presentation"></div><div ><input data-dojo-attach-point="textbox,focusNode" autocomplete="on" name="address1" type="text" tabindex="0" id="address1_45381448" maxlength="30" size="35" aria-invalid="true" aria-required="true" value=""></div></div> + </div> +</div> + +<div > + <div >Apt.,suite, bldg.</div> + <div > + <div id="widget_address2_45381448" role="presentation" widgetid="address2_45381448"><div ><input value="Χ " type="text" tabindex="-1" readonly="readonly" role="presentation"></div><div ><input data-dojo-attach-point="textbox,focusNode" autocomplete="on" name="address2" type="text" tabindex="0" id="address2_45381448" maxlength="30" size="35" aria-invalid="false" value=""></div></div> + </div> +</div> + + </div> + + <div > + +<div > + <div >Country<span >*</span></div> + <div > + <select id="country_45381448" name="country" dojoattachpoint="focusNode,valueNode,textbox,comboNode,containerNode" dojoattachevent="onchange: _selectOption" autocomplete="off" tabindex="0" required="" widgetid="country_45381448"><option value="US">United States</option><option value="CA">Canada</option><option value="AG">Antigua and Barbuda</option><option value="AW">Aruba</option><option value="AU">Australia</option><option value="AT">Austria</option><option value="BS">Bahamas</option><option value="BB">Barbados</option><option value="BE">Belgium</option><option value="BZ">Belize</option><option value="BM">Bermuda</option><option value="BT">Bhutan</option><option value="BN">Brunei</option><option value="CK">Cook Islands</option><option value="CR">Costa Rica</option><option value="CZ">Czech Republic</option><option value="FJ">Fiji</option><option value="FI">Finland</option><option value="FR">France</option><option value="DE">Germany</option><option value="GI">Gibraltar</option><option value="VA">Holy See</option><option value="HK">Hong Kong S.A.R. of China</option><option value="HU">Hungary</option><option value="JP">Japan</option><option value="JO">Jordan</option><option value="KR">Korea, South</option><option value="KW">Kuwait</option><option value="LI">Liechtenstein</option><option value="LT">Lithuania</option><option value="LU">Luxembourg</option><option value="MO">Macau S.A.R. of China</option><option value="MV">Maldives</option><option value="MR">Mauritania</option><option value="MU">Mauritius</option><option value="MD">Moldova</option><option value="NL">Netherlands</option><option value="NZ">New Zealand</option><option value="NO">Norway</option><option value="OM">Oman</option><option value="PA">Panama</option><option value="PY">Paraguay</option><option value="PL">Poland</option><option value="QA">Qatar</option><option value="RO">Romania</option><option value="SM">San Marino</option><option value="SC">Seychelles</option><option value="SG">Singapore</option><option value="SI">Slovenia</option><option value="ZA">South Africa</option><option value="SE">Sweden</option><option value="CH">Switzerland</option><option value="TW">Taiwan</option><option value="TH">Thailand</option><option value="TR">Turkey</option><option value="AE">United Arab Emirates</option><option value="GB">United Kingdom</option><option value="VE">Venezuela</option></select> + </div> +</div> + +<div > + <div >City<span >*</span></div> + <div > + <div id="widget_city_45381448" role="presentation" widgetid="city_45381448"><div ><input value="Χ " type="text" tabindex="-1" readonly="readonly" role="presentation"></div><div ><input data-dojo-attach-point="textbox,focusNode" autocomplete="on" name="city" type="text" tabindex="0" id="city_45381448" maxlength="40" size="35" aria-invalid="true" aria-required="true" value=""></div></div> + </div> +</div> + + <div id="stateZipSection_45381448" > + +<div > + <div >State<span >*</span></div> + <div > + <select id="state_45381448" name="state" dojoattachpoint="focusNode,valueNode,textbox,comboNode,containerNode" dojoattachevent="onchange: _selectOption" autocomplete="off" tabindex="0" required="" widgetid="state_45381448"><option value="" id="state_45381448ph" disabled="" >- Select a State -</option> + <option value="AL">Alabama</option><option value="AK">Alaska</option><option value="AS">American Samoa</option><option value="AZ">Arizona</option><option value="AR">Arkansas</option><option value="AA">Armed Forces Americas (AA)</option><option value="AE">Armed Forces Europe (AE)</option><option value="AP">Armed Forces Pacific (AP)</option><option value="CA">California</option><option value="CO">Colorado</option><option value="CT">Connecticut</option><option value="DE">Delaware</option><option value="DC">District of Columbia</option><option value="FM">Federated States of Micronesia</option><option value="FL">Florida</option><option value="GA">Georgia</option><option value="GU">Guam</option><option value="HI">Hawaii</option><option value="ID">Idaho</option><option value="IL">Illinois</option><option value="IN">Indiana</option><option value="IA">Iowa</option><option value="KS">Kansas</option><option value="KY">Kentucky</option><option value="LA">Louisiana</option><option value="ME">Maine</option><option value="MH">Marshall Islands</option><option value="MD">Maryland</option><option value="MA">Massachusetts</option><option value="MI">Michigan</option><option value="MN">Minnesota</option><option value="MS">Mississippi</option><option value="MO">Missouri</option><option value="MT">Montana</option><option value="NE">Nebraska</option><option value="NV">Nevada</option><option value="NH">New Hampshire</option><option value="NJ">New Jersey</option><option value="NM">New Mexico</option><option value="NY">New York</option><option value="NC">North Carolina</option><option value="ND">North Dakota</option><option value="MP">Northern Mariana Islands</option><option value="OH">Ohio</option><option value="OK">Oklahoma</option><option value="OR">Oregon</option><option value="PW">Palau</option><option value="PA">Pennsylvania</option><option value="PR">Puerto Rico</option><option value="RI">Rhode Island</option><option value="SC">South Carolina</option><option value="SD">South Dakota</option><option value="TN">Tennessee</option><option value="TX">Texas</option><option value="VI">U.S. Virgin Islands</option><option value="UT">Utah</option><option value="VT">Vermont</option><option value="VA">Virginia</option><option value="WA">Washington</option><option value="WV">West Virginia</option><option value="WI">Wisconsin</option><option value="WY">Wyoming</option></select> + </div> +</div> + +<div > + <div >ZIP<span >*</span></div> + <div > + <div id="widget_zipCode_45381448" role="presentation" widgetid="zipCode_45381448"><div ><input value="Χ " type="text" tabindex="-1" readonly="readonly" role="presentation"></div><div ><input data-dojo-attach-point="textbox,focusNode" autocomplete="on" name="zipCode" type="tel" tabindex="0" id="zipCode_45381448" maxlength="30" size="35" aria-invalid="true" aria-required="true" value=""></div></div> + </div> +</div> + + </div> + </div> + + <div > + + + <div > + +<div > + <div >Phone number</div> + <div > + <div id="widget_phone1_45381448" role="presentation" widgetid="phone1_45381448"><div ><input value="Χ " type="text" tabindex="-1" readonly="readonly" role="presentation"></div><div ><input data-dojo-attach-point="textbox,focusNode" autocomplete="on" name="phone1" type="tel" tabindex="0" id="phone1_45381448" maxlength="20" size="20" aria-invalid="false" value=""><span >000-000-0000</span></div></div> + </div> +</div> + + <div id="phoneExtArea_45381448" > + +<div > + <div >Ext</div> + <div > + <div id="widget_phone2_45381448" role="presentation" widgetid="phone2_45381448"><div ><input value="Χ " type="text" tabindex="-1" readonly="readonly" role="presentation"></div><div ><input data-dojo-attach-point="textbox,focusNode" autocomplete="on" name="phone2" type="tel" tabindex="0" id="phone2_45381448" aria-invalid="false" maxlength="5" size="5" value=""></div></div> + </div> +</div> + + </div> + + <div > + <div ></div> + <div >Recommended for PO Box and wine deliveries</div> + </div> + </div> + </div> + + <div > + +<div > + <div ></div> + <div > + <input type="checkbox" id="rbCellPhoneYes" name="phone1Type" value="C"><label for="rbCellPhoneYes">Cell phone</label> + </div> +</div> + + </div> + + + </div> + + + <div > + <div id="emailArea_45381448" > + + <div id="emailAreaMsg_45381448" > + <div >Required field <span >*</span></div> + <div > + <span >To save your billing address,</span> please provide an email address where we can contact you with order updates and information. + </div> + </div> + +<div > + <div >Email address<span >*</span></div> + <div > + <div id="widget_email1_45381448" role="presentation" widgetid="email1_45381448"><div ><input value="Χ " type="text" tabindex="-1" readonly="readonly" role="presentation"></div><div ><input data-dojo-attach-point="textbox,focusNode" autocomplete="on" name="email1" type="text" tabindex="0" id="email1_45381448" aria-required="true" aria-invalid="true" maxlength="100" size="35" value=""><span >Enter your email address</span></div></div> + </div> +</div> + +<div > + <div >Confirm email address<span >*</span></div> + <div > + + <div id="widget_logonId_45381448" role="presentation" widgetid="logonId_45381448"><div ><input value="Χ " type="text" tabindex="-1" readonly="readonly" role="presentation"></div><div ><input data-dojo-attach-point="textbox,focusNode" autocomplete="off" name="logonId" type="text" tabindex="0" id="logonId_45381448" aria-required="true" aria-invalid="true" maxlength="100" size="35" value=""></div></div> + </div> +</div> + + </div> + </div> + + + <div id="addressSection2_45381448" > + + + </div> +</form> + + +<form id="orderPaymentForm" name="orderPaymentForm" method="post"> + <input type="hidden" name="langId" value="-1"> + <input type="hidden" name="orderId" value="14146734"> + <input type="hidden" name="notifyOrderSubmitted" value="0"> + <input type="hidden" id="billtoAddressId" name="billtoAddressId" value=""> + <input type="hidden" name="hiddenPromoCode" value="" id="hiddenPromoCode"> + <input type="hidden" name="hiddenCoupon" value="" id="hiddenCoupon"> + <input type="hidden" name="previousOptIn" id="previousOptIn" value="yes"> + <input type="hidden" name="hiddenOptIn" id="hiddenOptIn2" value="yes"> + <input type="hidden" name="countryOptIn" id="countryOptIn2" value="US"> + +<a name="anchor_payment"></a> +<div dojotype="bec.order.payment.PaymentMethod" id="paymentMethod" jsid="paymentMethod" paypalpreauth="false" paypaltabletremove="false" expresscheckout="false" errormessage="Payment information is missing or invalid." orderid="14146734" widgetid="paymentMethod"> + <input type="hidden" name="policyId" value="" dojoattachpoint="policyId"> + <input type="hidden" name="payMethodId" value="" dojoattachpoint="payMethodId"> + <input type="hidden" name="isPIAddNeeded" value="N"> + <input type="hidden" name="valueFromProfileOrder" value="Y"> + <input type="hidden" name="account" id="account"> + <input type="hidden" name="piAmount" id="piAmount" value="49.90000"> + <input type="hidden" name="remainingAmount" value="0.00"> + <input type="hidden" name="DoExpressCheckout_ErrorCode" value=""> + <input type="hidden" name="DoAuthorization_ErrorCode" value=""> + <input type="hidden" name="tabletDomain" value=""> + + <div id="paymentMethodSection" dojoattachpoint="paymentMethodSection"> + + <div dojotype="bec.data.ItemFileReadStore" id="paymentMethodStore" jsid="paymentMethodStore" clearonclose="true" url="/gifts/store/BECAjaxIncludeView?storeId=10455&includePage=ShoppingArea/CheckoutSection/Billing/PaymentMethods/AvailablePaymentMethodsJSON.jsp&orderId=14146734"></div> + + + <div dojotype="dijit.layout.ContentPane" id="payment2Section" dojoattachpoint="payment2Section" title="" role="group" widgetid="payment2Section"><!-- BEGIN: GiftCard.jsp --> +<input type="hidden" name="gc_expire_month" value="12"> +<input type="hidden" name="gc_expire_year" value="2014"> +<input type="hidden" name="gc_policyId" value="11210"> + +<div id="giftCardSection" dojoattachpoint="giftCardSection" > + <div > + <span >Redeem a Gift Card</span> + </div> + <div > + If your order exceeds your Gift Card balance, please enter additional payment information. + </div> + <div > + <div >Gift Card Number</div> + <div dojoattachpoint="_wrapper" widgetid="gcAccount"><div id="widget_gcAccount" role="presentation"><div ><input value="Χ " type="text" tabindex="-1" readonly="readonly" role="presentation"></div><div ><input data-dojo-attach-point="textbox,focusNode" autocomplete="off" name="GiftCardNumber" type="text" tabindex="0" id="gcAccount" size="22" maxlength="20" aria-invalid="true" value=""></div></div> +<input type="hidden" name="GiftCardBrand" id="GiftCardBrand" value="" dojoattachpoint="_cardType"></div> + </div> + + <div > + <div >PIN*</div> + <div id="widget_gcPin" role="presentation" widgetid="gcPin"><div ><input value="Χ " type="text" tabindex="-1" readonly="readonly" role="presentation"></div><div ><input data-dojo-attach-point="textbox,focusNode" autocomplete="off" name="GiftCardPin" type="text" tabindex="0" id="gcPin" size="6" maxlength="4" aria-invalid="true" aria-required="true" value=""></div></div> + </div> + + <div > + <a href="#checkGiftCardBalance" onclick="return false;" dojoattachevent="onclick: showGiftCardBalancePopup"> + Check Gift Card Balance + </a> + </div> + + <div >*scratch off the covered section on the card back or for an eGift card, refer to your email.</div> +</div> +</div> + + + <div >Payment Method:</div> + + + <div dojotype="dijit.layout.ContentPane" id="payment3Section" dojoattachpoint="payment3Section" title="" role="group" widgetid="payment3Section"><!-- BEGIN: PayPal.jsp --> + +<div id="paypal-section" > + <div > + <div role="presentation" widgetid="paymentType-PayPal"><input name="paymentType" type="radio" data-dojo-attach-point="focusNode" data-dojo-attach-event="onclick:_onClick" value="on" tabindex="0" id="paymentType-PayPal"></div> + </div> + <div > + <label for="paymentType-PayPal"><span ></span></label> + <a href="#whatIsPayPal" id="whatPaypal" >What is PayPal?</a> + </div> +</div> + +<!-- END: PayPal.jsp --></div> + <!-- payPalToken: --> + <div id="payment1Section" > + <div dojotype="dijit.layout.ContentPane" id="paymentInput" dojoattachpoint="paymentInput" title="" role="group" widgetid="paymentInput"><!-- BEGIN: CreditCard.jsp --> +<div > + + <div > + <div role="presentation" widgetid="paymentType-CC"><input name="paymentType" type="radio" data-dojo-attach-point="focusNode" data-dojo-attach-event="onclick:_onClick" value="on" tabindex="0" id="paymentType-CC" aria-checked="true"></div> + </div> + + <div > + <label for="paymentType-CC" ><div id="cardTypeImg" ></div></label> + </div> +</div> +<div id="paymentCreditCard" dojoattachpoint="paymentCreditCard" > + <div > + <div >Card Number</div> + <div dojoattachpoint="_wrapper" widgetid="clearTextAccount"><div id="widget_clearTextAccount" role="presentation"><div ><input value="Χ " type="text" tabindex="-1" readonly="readonly" role="presentation"></div><div ><input data-dojo-attach-point="textbox,focusNode" autocomplete="off" type="text" tabindex="0" id="clearTextAccount" size="23" maxlength="30" aria-required="false" aria-invalid="true" value=""></div></div> +<input type="hidden" name="cc_brand" id="cc_brand" value="" dojoattachpoint="_cardType"></div> + + </div> + <div > + <div >Expiration Date</div> + <div dojotype="bec.data.ItemFileReadStore" id="expirationMonths" jsid="expirationMonths" clearonclose="true" data="bec.order.payment.Expiration.getMonths()"></div> + <select id="expire_month" name="expire_month" dojoattachpoint="focusNode,valueNode,textbox,comboNode,containerNode" dojoattachevent="onchange: _selectOption" autocomplete="off" tabindex="0" required="" widgetid="expire_month"><option value="" id="expire_monthph" disabled="" >- Month -</option><option value="01">01 - Jan</option><option value="02">02 - Feb</option><option value="03">03 - Mar</option><option value="04">04 - Apr</option><option value="05">05 - May</option><option value="06">06 - Jun</option><option value="07">07 - Jul</option><option value="08">08 - Aug</option><option value="09">09 - Sep</option><option value="10">10 - Oct</option><option value="11">11 - Nov</option><option value="12">12 - Dec</option></select> + + <div dojotype="bec.data.ItemFileReadStore" id="expirationYears" jsid="expirationYears" clearonclose="true" data="bec.order.payment.Expiration.getYears({min: new Date(), displayYears: 12})"></div> + <select id="expire_year" name="expire_year" dojoattachpoint="focusNode,valueNode,textbox,comboNode,containerNode" dojoattachevent="onchange: _selectOption" autocomplete="off" tabindex="0" required="" widgetid="expire_year"><option value="" id="expire_yearph" disabled="" >- Year -</option><option value="2014">2014</option><option value="2015">2015</option><option value="2016">2016</option><option value="2017">2017</option><option value="2018">2018</option><option value="2019">2019</option><option value="2020">2020</option><option value="2021">2021</option><option value="2022">2022</option><option value="2023">2023</option><option value="2024">2024</option><option value="2025">2025</option></select> + </div> +</div> +<!-- END: CreditCard.jsp --></div> + </div> + </div> +</div> +<!-- BEGIN Partner Feed PartnerFeedOrderPaymentForm --><!-- END Partner Feed PartnerFeedOrderPaymentForm --> + </form> + +
diff --git a/chrome/test/data/autofill/heuristics/output/24_checkout_harryanddavid.com.out b/chrome/test/data/autofill/heuristics/output/24_checkout_harryanddavid.com.out new file mode 100644 index 0000000..e7ab75db --- /dev/null +++ b/chrome/test/data/autofill/heuristics/output/24_checkout_harryanddavid.com.out
@@ -0,0 +1,42 @@ +UNKNOWN_TYPE | typeOfAddress | Business address | H | typeOfAddress_1-default +UNKNOWN_TYPE | personTitle | Title | | typeOfAddress_1-default +UNKNOWN_TYPE | recipientRelation | Relationship | 0 | typeOfAddress_1-default +COMPANY_NAME | | Company name* | Χ | typeOfAddress_1-default +UNKNOWN_TYPE | organizationName | Company name* | | typeOfAddress_1-default +UNKNOWN_TYPE | | Attn. Line* | Χ | typeOfAddress_1-default +COMPANY_NAME | businessTitle | Attn. Line* | | businessTitle_1-default +UNKNOWN_TYPE | | First Name* | Χ | businessTitle_1-default +NAME_FIRST | firstName | First Name* | | businessTitle_1-default +NAME_LAST | | Last Name* | Χ | businessTitle_1-default +UNKNOWN_TYPE | lastName | Last Name* | | businessTitle_1-default +UNKNOWN_TYPE | | Additional info | Χ | businessTitle_1-default +UNKNOWN_TYPE | middleName | Additional info | | businessTitle_1-default +ADDRESS_HOME_LINE1 | | Street address* | Χ | businessTitle_1-default +ADDRESS_HOME_LINE2 | address1 | Street address* | | businessTitle_1-default +UNKNOWN_TYPE | | Apt.,suite, bldg. | Χ | businessTitle_1-default +UNKNOWN_TYPE | address2 | Apt.,suite, bldg. | | businessTitle_1-default +ADDRESS_HOME_COUNTRY | country | Country* | US | businessTitle_1-default +ADDRESS_HOME_CITY | | City* | Χ | businessTitle_1-default +ADDRESS_HOME_CITY | city | City* | | businessTitle_1-default +ADDRESS_HOME_STATE | state | State* | | businessTitle_1-default +ADDRESS_HOME_ZIP | | ZIP* | Χ | businessTitle_1-default +UNKNOWN_TYPE | zipCode | ZIP* | | businessTitle_1-default +PHONE_HOME_WHOLE_NUMBER | | Phone number | Χ | businessTitle_1-default +PHONE_HOME_WHOLE_NUMBER | phone1 | Phone number | | businessTitle_1-default +UNKNOWN_TYPE | | Ext | Χ | businessTitle_1-default +PHONE_HOME_WHOLE_NUMBER | phone2 | Ext | | businessTitle_1-default +UNKNOWN_TYPE | phone1Type | Cell phone | C | businessTitle_1-default +EMAIL_ADDRESS | | Email address* | Χ | businessTitle_1-default +EMAIL_ADDRESS | email1 | Email address* | | businessTitle_1-default +EMAIL_ADDRESS | | Confirm email address* | Χ | businessTitle_1-default +EMAIL_ADDRESS | logonId | Confirm email address* | | businessTitle_1-default +UNKNOWN_TYPE | | Gift Card Number | Χ | _1-default +UNKNOWN_TYPE | GiftCardNumber | Gift Card Number | | _1-default +UNKNOWN_TYPE | | PIN* | Χ | _1-default +UNKNOWN_TYPE | GiftCardPin | PIN* | | _1-default +UNKNOWN_TYPE | paymentType | What is PayPal? | on | _1-default +UNKNOWN_TYPE | paymentType | Card Number Expiration Date | on | _1-default +CREDIT_CARD_NUMBER | | Card Number | Χ | _1-cc +CREDIT_CARD_NUMBER | clearTextAccount | Card Number | | _1-cc +CREDIT_CARD_EXP_MONTH | expire_month | Expiration Date | | _1-cc +CREDIT_CARD_EXP_4_DIGIT_YEAR | expire_year | Expiration Date | | _1-cc
diff --git a/chrome/test/data/chromeos/virtual_keyboard/attributes_test.js b/chrome/test/data/chromeos/virtual_keyboard/attributes_test.js deleted file mode 100644 index cd8ba90d..0000000 --- a/chrome/test/data/chromeos/virtual_keyboard/attributes_test.js +++ /dev/null
@@ -1,49 +0,0 @@ -/* - * Copyright 2013 The Chromium Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - /** - * Asynchronously tests that invert propagates correctly. This catches the - * regression crbug.com/3277551. - * @param {function} testDoneCallBack The callback function to be called - * on completion. - */ -function testInvertAttributeAsync(testDoneCallback) { - var tester = new SubtaskScheduler(); - tester.init = function() { - $('keyboard').layout = Layout.SYSTEM; - }; - - var onSystemQwertyLower = function() { - assertEquals(Keyset.SYSTEM_LOWER, $('keyboard').activeKeysetId, - 'Invalid keyset.'); - var key = findKey('['); - assertFalse(key.invert, "Unexpected inverted key in lower keyset."); - $('keyboard').keyset = Keyset.UPPER; - }; - - tester.addWaitCondition(onSystemQwertyLower, Keyset.SYSTEM_LOWER); - tester.addSubtask(onSystemQwertyLower); - - var onSystemQwertyUpper = function() { - assertEquals(Keyset.SYSTEM_UPPER, $('keyboard').activeKeysetId, - "Invalid keyset."); - var key = findKey('{'); - assertTrue(key.invert, "Key not inverted in upper keyset."); - $('keyboard').layout = Layout.DEFAULT; - } - - tester.addWaitCondition(onSystemQwertyUpper, Keyset.SYSTEM_UPPER); - tester.addSubtask(onSystemQwertyUpper); - - var onReset = function() { - assertEquals(Keyset.DEFAULT_LOWER, $('keyboard').activeKeysetId, - 'Invalid keyset.'); - }; - tester.addWaitCondition(onReset, Keyset.DEFAULT_LOWER); - tester.addSubtask(onReset); - - tester.scheduleTest('testInvertAttributeAsync', testDoneCallback); -} \ No newline at end of file
diff --git a/chrome/test/data/chromeos/virtual_keyboard/control_keys_test.js b/chrome/test/data/chromeos/virtual_keyboard/control_keys_test.js deleted file mode 100644 index 9c2b21bd..0000000 --- a/chrome/test/data/chromeos/virtual_keyboard/control_keys_test.js +++ /dev/null
@@ -1,309 +0,0 @@ -/* - * Copyright 2013 The Chromium Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/** - * Class for testing keyset transitions resulting from use of the left or right - * shift key. Keyset transitions are asynchronous, and each test needs to be - * broken into subtasks in order to synchronize with keyset updates. - * @param {string=} opt_layout Optional name of the initial layout. - * @param {string=} opt_unlocked Optional short-name of the lowercase keyset. - * @param {string=} opt_locked Optional short-name of the uppercase keyset. - * @constructor - */ -function ShiftKeyTester(opt_layout, opt_unlocked, opt_locked) { - this.layout = opt_layout || 'qwerty'; - this.unlocked = opt_unlocked || 'lower'; - this.locked = opt_locked || 'upper'; - this.subtasks = []; -} - -ShiftKeyTester.prototype = { - /** - * Extends the subtask scheduler. - */ - __proto__: SubtaskScheduler.prototype, - - /** - * Adds a subtask for mocking a single key event on a shift key. - * @param {string} alignment Indicates if triggering on the left or right - * shift key. - * @param {string} keyOp Name of the event. - * @param {string} keysetId Expected keyset at the start of the subtask. - * @param {boolean=} opt_chording Optional parameter to indicate that the key - * event is for a chording operation. - */ - keyEvent: function(alignment, keyOp, keysetId, opt_chording) { - var self = this; - var fn = function() { - Debug('Mocking shift key event: alignment = ' + alignment + ', keyOp = ' + - keyOp + ', keysetId = ' + keysetId + ', chording = ' + - (opt_chording ? true : false)); - self.alignment = alignment; - self.verifyKeyset(keysetId, - 'Unexpected keyset before shift key event.'); - var keys = $('keyboard').activeKeyset.querySelectorAll('kb-shift-key'); - shiftKey = keys[this.alignment == 'left' ? 0 : 1]; - var mockKeyEvent = {pointerId: 2, isPrimary:true, target: shiftKey}; - shiftKey[keyOp](mockKeyEvent); - // An 'up" event needs to fire a pointer up on the keyboard in order to - // handle click counting. - if (keyOp == 'up') - $('keyboard').up(mockKeyEvent); - if (opt_chording) - shiftKey.out(mockKeyEvent); - }; - this.addWaitCondition(fn, keysetId); - this.addSubtask(fn); - }, - - /** - * Adds a subtask for mocking the typing of a lowercase or uppercase 'A'. - * @param {boolean} isUppercase Indicates the case of the character to type. - */ - typeCharacterA: function(keysetId) { - var self = this; - var fn = function() { - var isUppercase = keysetId == Keyset.UPPER; - Debug('Mock typing ' + (isUppercase ? 'A' : 'a')); - self.verifyKeyset(keysetId, - 'Unexpected keyset for typed character.'); - mockTypeCharacter(isUppercase ? 'A' : 'a', 0x41, - isUppercase ? Modifier.SHIFT : Modifier.NONE); - }; - this.addWaitCondition(fn, keysetId); - this.addSubtask(fn); - } -}; - -/** - * Retrieves the left or right shift keys. Shift keys come in pairs for upper - * and lowercase keyboard layouts respectively. - * @param {string} alignment Which of {left, right} shift keys to return. - * @return {Object.<string: Object>} a map from keyset to the shift key in it. - */ -function getShiftKeys(alignment) { - var layout = $('keyboard').layout; - var keysets = ['lower', 'upper']; - - var result={}; - for(var keysetIndex in keysets) { - var keysetId = keysets[keysetIndex]; - // The keyset DOM object which contains a shift key. - var keyset = $('keyboard').querySelector('#' + layout + "-" + keysetId); - assertTrue(!!keyset, "Cannot find keyset: " + keyset); - var shiftKey = keyset.querySelector('kb-shift-key[align="' + - alignment + '"]'); - assertTrue(!!shiftKey, "Keyset " + keysetId + - " does not have a shift key with " + alignment + " alignment"); - result[keysetId] = shiftKey; - } - return result; -} - -/** - * Retrieves the specified modifier key from the system-qwerty layout. - * @param {string} modifier Which modifier key to return. - * @return {Object} The modifier key. - */ -function getModifierKey(modifier) { - var keyset = $('keyboard').activeKeyset; - assertTrue(!!keyset, 'Cannot find active keyset.'); - var modifierKey = keyset.querySelector('kb-modifier-key[char="' + - modifier + '"]'); - assertTrue(!!modifierKey, "Modifier key not found: " + modifierKey); - return modifierKey; -} - -/** - * Tests that a particular shift key has been initialized correctly. - * @param {Object} shift The shift key. - */ -function checkShiftInitialState(shift) { - //Checks that the unlocked case is lower. - var unlocked = 'lower'; - assertEquals(unlocked, shift.lowerCaseKeysetId, - "Mismatched lowerCaseKeysetId."); - //Checks that the locked case is upper. - var locked = 'upper'; - assertEquals(locked, shift.upperCaseKeysetId, - "Mismatched upperCaseKeysetId."); -} - -/** - * Asynchronously tests highlighting of the left and right shift keys. - * @param {function} testDoneCallBack The function to be called - * on completion. - */ -function testShiftHighlightAsync(testDoneCallback) { - var tester = new ShiftKeyTester(); - - var checkShiftTap = function(alignment) { - tester.keyEvent(alignment, EventType.KEY_DOWN, Keyset.LOWER); - tester.keyEvent(alignment, EventType.KEY_UP, Keyset.UPPER); - tester.typeCharacterA(Keyset.UPPER); - tester.typeCharacterA(Keyset.LOWER); - }; - checkShiftTap(Alignment.LEFT); - checkShiftTap(Alignment.RIGHT); - - tester.scheduleTest('testShiftKeyHighlightAsync', testDoneCallback); -} - -/** - * Asynchronously tests initialization of the left and right shift keys. - * @param {function} testDoneCallBack The function to be called - * on completion. - */ -function testShiftKeyInitAsync(testDoneCallback) { - var runTest = function() { - var alignments = ['left', 'right']; - for (var i in alignments) { - var alignment = alignments[i]; - var shifts = getShiftKeys(alignment); - checkShiftInitialState(shifts['lower']); - checkShiftInitialState(shifts['upper']); - } - }; - onKeyboardReady('testShiftKeyInitAsync', runTest, testDoneCallback); -} - -/** - * Asynchronously tests capitalization on double click of the left and - * right shift keys. - * @param {function} testDoneCallBack The function to be called - * on completion. - */ -function testShiftDoubleClickAsync(testDoneCallback) { - var tester = new ShiftKeyTester(); - - var checkShiftDoubleClick = function(alignment) { - tester.keyEvent(alignment, EventType.KEY_DOWN, Keyset.LOWER); - tester.keyEvent(alignment, EventType.KEY_UP, Keyset.UPPER); - tester.keyEvent(alignment, EventType.KEY_DOWN, Keyset.UPPER); - tester.keyEvent(alignment, EventType.KEY_UP, Keyset.UPPER); - - tester.typeCharacterA(Keyset.UPPER); - tester.typeCharacterA(Keyset.UPPER); - - tester.keyEvent(alignment, EventType.KEY_DOWN, Keyset.UPPER); - tester.keyEvent(alignment, EventType.KEY_UP, Keyset.LOWER); - - tester.typeCharacterA(Keyset.LOWER); - }; - checkShiftDoubleClick(Alignment.LEFT); - checkShiftDoubleClick(Alignment.RIGHT); - - tester.scheduleTest('testShiftDoubleClickAsync', testDoneCallback); -} - -/** - * Asynchronously tests capitalization on long press of the left and - * right shift keys. - * @param {function} testDoneCallBack The callback function to be called - * on completion. - */ -function testShiftLongPressAsync(testDoneCallback) { - var tester = new ShiftKeyTester(); - - var checkShiftLongPress = function(alignment) { - tester.keyEvent(alignment, EventType.KEY_DOWN, Keyset.LOWER); - tester.wait(1000, Keyset.UPPER); - tester.keyEvent(alignment, EventType.KEY_UP, Keyset.UPPER); - - tester.typeCharacterA(Keyset.UPPER); - tester.typeCharacterA(Keyset.UPPER); - - tester.keyEvent(alignment, EventType.KEY_DOWN, Keyset.UPPER); - tester.keyEvent(alignment, EventType.KEY_UP, Keyset.LOWER); - - tester.typeCharacterA(Keyset.LOWER); - }; - checkShiftLongPress(Alignment.LEFT); - checkShiftLongPress(Alignment.RIGHT); - - tester.scheduleTest('testShiftLongPressAsync', testDoneCallback); -} - -/** - * Asynchronously tests chording on the keyboard. - * @param {function} testDoneCallBack The callback function to be called - * on completion. - */ -function testShiftChordingAsync(testDoneCallback) { - var tester = new ShiftKeyTester(); - - var checkShiftChording = function(alignment) { - tester.keyEvent(alignment, EventType.KEY_DOWN, Keyset.LOWER, - true /* chording */); - - tester.typeCharacterA(Keyset.UPPER); - - tester.wait(1000, Keyset.UPPER); - tester.keyEvent(alignment, EventType.KEY_UP, Keyset.UPPER); - - tester.typeCharacterA(Keyset.LOWER); - }; - checkShiftChording('left'); - checkShiftChording('right'); - - tester.scheduleTest('testShiftChordingAsync', testDoneCallback); -} - -/** - * Asynchronously tests modifier keys on the keyboard. - * @param {function} testDoneCallBack The callback function to be called - * on completion. - */ -function testModifierKeysAsync(testDoneCallback) { - var setupWork = function() { - $('keyboard').layout = Layout.SYSTEM; - }; - - var onSystemQwertyLower = function() { - assertEquals(Keyset.SYSTEM_LOWER, $('keyboard').activeKeysetId, - 'Invalid keyset.'); - - var ctrl = getModifierKey('Ctrl'); - var alt = getModifierKey('Alt'); - var mockEvent = {pointerId: 1}; - - // Test 'ctrl' + 'a'. - ctrl.down(mockEvent); - ctrl.up(mockEvent); - mockTypeCharacter('a', 0x41, Modifier.CONTROL); - mockTypeCharacter('a', 0x41, Modifier.NONE); - // Test 'ctrl' + 'alt' + 'a'. - ctrl.down(mockEvent); - ctrl.up(mockEvent); - alt.down(mockEvent); - alt.up(mockEvent); - mockTypeCharacter('a', 0x41, Modifier.CONTROL | Modifier.ALT); - mockTypeCharacter('a', 0x41, Modifier.NONE); - // Test chording control. - ctrl.down(mockEvent); - mockTypeCharacter('a', 0x41, Modifier.CONTROL); - mockTypeCharacter('a', 0x41, Modifier.CONTROL); - ctrl.up(mockEvent); - mockTypeCharacter('a', 0x41, Modifier.NONE); - $('keyboard').layout = 'qwerty'; - }; - onSystemQwertyLower.waitCondition = { - state: 'keysetChanged', - value: Keyset.SYSTEM_LOWER - }; - - var onReset = function() { - assertEquals(Keyset.DEFAULT_LOWER, $('keyboard').activeKeysetId, - 'Invalid keyset.'); - }; - onReset.waitCondition = { - state: 'keysetChanged', - value: Keyset.DEFAULT_LOWER - }; - - onKeyboardReady('testModifierKeysAsync', setupWork, testDoneCallback, - [onSystemQwertyLower, onReset]); -}
diff --git a/chrome/test/data/chromeos/virtual_keyboard/end_to_end_test.js b/chrome/test/data/chromeos/virtual_keyboard/end_to_end_test.js index 6b268e9..cd6992e207 100644 --- a/chrome/test/data/chromeos/virtual_keyboard/end_to_end_test.js +++ b/chrome/test/data/chromeos/virtual_keyboard/end_to_end_test.js
@@ -4,28 +4,97 @@ * found in the LICENSE file. */ -var kb = document.getElementById('keyboard'); - /** - * Finds the character specified and types it. Assumes that the default - * layout is qwerty, and the default keyset is lower. - * @param {{string}} char The character to type. + * Defers continuation of a test until a keyset is loaded. + * @param {string} keyset Name of the target keyset. + * @param {Function} continueTestCallback Callback function to invoke in order + * to resume the test. */ -var type = function(char) { - var keyset = kb.querySelector('#qwerty-lower'); - var keys = Array.prototype.slice.call(keyset.querySelectorAll('kb-key')); - var key = keys.filter(function(key) { - return key.charValue == char; - })[0]; - key.down({pointerId: 1}); - key.up({pointerId: 1}); +function onKeysetReady(keyset, continueTestCallback) { + var container = document.querySelector('.inputview-container'); + var bounds = container.getBoundingClientRect(); + if (bounds.bottom > 0 && keyset in controller.container_.keysetViewMap && + keyset == controller.currentKeyset_) { + continueTestCallback(); + return; + } + setTimeout(function() { + onKeysetReady(keyset, continueTestCallback); + }, 100); } -if (kb.isReady()) { - type('a'); -} else { - kb.addKeysetChangedObserver(function() { - if (kb.isReady()) - type('a'); - }); -} \ No newline at end of file + +/** + * Display an error message and abort the test. + * @param {string} message The error message. + */ +function fail(message) { + console.error(message); + window.domAutomationController.send(false); +} + + +/** + * Mocks a touch event targeted on a key. + * @param {!Element} key . + * @param {string} eventType . + */ +function mockTouchEvent(key, eventType) { + var rect = key.getBoundingClientRect(); + var x = rect.left + rect.width/2; + var y = rect.top + rect.height/2; + var e = document.createEvent('UIEvent'); + e.initUIEvent(eventType, true, true); + e.touches = [{pageX: x, pageY: y}]; + e.target = key; + key.dispatchEvent(e); +} + + +/** + * Simulates tapping on a key. + * @param {!Element} key . + */ +function mockTap(key) { + mockTouchEvent(key, 'touchstart'); + mockTouchEvent(key, 'touchend'); +} + + +/** + * Returns the active keyboard view. + * @return {!HTMLElement} + */ +function getActiveView() { + var container = document.querySelector('.inputview-container'); + var views = container.querySelectorAll('.inputview-view'); + for (var i = 0; i < views.length; i++) { + var display = views[i].style.display; + if (!display || display != 'none') + return views[i]; + } + fail('Unable to find active keyboard view'); +} + + +/** + * Locates a key by label. + * @param {string} label The label on the key. If the key has multiple labels, + * |label| can match any of them. + * @returns {?Element} . + */ +function findKey(label) { + var view = getActiveView(); + candidates = view.querySelectorAll('.inputview-special-key-name'); + for (var i = 0; i < candidates.length; i++) { + if (candidates[i].textContent == label) + return candidates[i]; + } + fail('Cannot find key labeled \'' + label + '\''); +} + + +// Wait for keyboard to finish loading asynchronously before tapping key. +onKeysetReady('us.compact.qwerty', function() { + mockTap(findKey('a')); +});
diff --git a/chrome/test/data/chromeos/virtual_keyboard/keyset_transition_test.js b/chrome/test/data/chromeos/virtual_keyboard/keyset_transition_test.js deleted file mode 100644 index e1761de..0000000 --- a/chrome/test/data/chromeos/virtual_keyboard/keyset_transition_test.js +++ /dev/null
@@ -1,283 +0,0 @@ -/* - * Copyright 2013 The Chromium Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/** - * Special keys for toggling keyset transitions. - * @enum {string} - */ -var Key = { - MORE_SYMBOLS: '~[<', - SHIFT: 'shift', - SYMBOL: '?123', - TEXT: 'ABC' -}; - -/** - * Input types. - * @enum {string} - */ -var InputType = { - TEXT: 'text', - NUMBER: 'number' -} - -/** - * Tester for keyset transitions. - * @param {string=} opt_layout Optional layout. Used to generate the full - * keyset ID from its shorthand name. If not specified, then the full - * keyset ID is required for the test. - * @constructor - */ -function KeysetTransitionTester(opt_layout) { - this.layout = opt_layout; - this.subtasks = []; -}; - -KeysetTransitionTester.prototype = { - /** - * Extends the subtask scheduler. - */ - __proto__: SubtaskScheduler.prototype, - - /** - * Adds a task for mocking a key event. - * @param {string} aligment Indicates if the left or right version of the - * keyset transition key should be used. - * @param {string} key Text label on the key. - * @param {string} eventType Name of the event. - * @param {string} keysetId Name of the expected keyset at the start of the - * task. - */ - keyEvent: function(alignment, key, eventType, keysetId) { - var self = this; - var fn = function() { - Debug('Generating key event: alignment = ' + alignment + ', key = ' + key - + ', event type = ' + eventType); - self.verifyKeyset(keysetId, 'Unexpected keyset.'); - var keyset = $('keyboard').activeKeyset; - assertTrue(!!keyset, 'Missing active keyset'); - var search = '[align="' + alignment + '"]'; - var candidates = keyset.querySelectorAll(search).array(); - for (var i = 0; i < candidates.length; i++) { - if (candidates[i].innerText == key || - candidates[i].classList.contains(key)) { - candidates[i][eventType]({pointerId: 1, isPrimary:true}); - return; - } - } - throw new Error('Unable to find \'' + key + '\' key in ' + keysetId); - }; - this.addWaitCondition(fn, keysetId); - this.addSubtask(fn); - }, - - /** - * Adds a task for mocking a key typed event. - * @param {string} key Text label on the key. - * @param {number} keyCode The legacy key code for the character. - * @param {number} modifiers Indicates which if any of the shift, control and - * alt keys are being virtually pressed. - * @param {string} keysetId Name of the expected keyset at the start of the - * task. - */ - typeKey: function(key, keyCode, modifiers, keysetId) { - var self = this; - var fn = function () { - Debug('Generating key typed event for key = ' + key + " and keycode = " - + keyCode); - self.verifyKeyset(keysetId, 'Unexpected keyset.'); - mockTypeCharacter(key, keyCode, modifiers) - }; - this.addWaitCondition(fn, keysetId); - this.addSubtask(fn); - }, - - /** - * Updates the input type. - * @param {string} inputType The new input type. - * @param {string} keysetId Expected keyset at the start of the task. - */ - transition: function(inputType, keysetId) { - var self = this; - var fn = function() { - self.verifyKeyset(keysetId, 'Unexpected keyset'); - Debug('changing input type to ' + inputType); - $('keyboard').inputTypeValue = inputType; - }; - this.addWaitCondition(fn, keysetId); - this.addSubtask(fn); - } -}; - -/** - * Tests that capitalizion persists on keyset transitions. - * The test is run asynchronously since the keyboard loads keysets dynamically. - * @param {Function} testDoneCallback The function to be called on completion. - */ -function testPersistantCapitalizationAsync(testDoneCallback) { - var tester = new KeysetTransitionTester(Layout.DEFAULT); - - /** - * Checks persistant capitalization using the shift key with the given - * alignment. - * @param {string} alignment The alignment of the shift key. - */ - var checkPersistantCapitalization = function(alignment) { - // Shift-lock - tester.keyEvent(alignment, Key.SHIFT, EventType.KEY_DOWN, Keyset.LOWER); - tester.wait(1000, Keyset.UPPER); - tester.keyEvent(alignment, Key.SHIFT, EventType.KEY_UP, Keyset.UPPER); - - // text -> symbol -> more -> text - tester.keyEvent(Alignment.CENTER, Key.SYMBOL, EventType.KEY_DOWN, - Keyset.UPPER); - tester.keyEvent(Alignment.CENTER, Key.TEXT, EventType.KEY_UP, - Keyset.SYMBOL); - tester.keyEvent(Alignment.CENTER, Key.MORE_SYMBOLS, EventType.KEY_DOWN, - Keyset.SYMBOL); - tester.keyEvent(Alignment.CENTER, Key.SYMBOL, EventType.KEY_UP, - Keyset.MORE_SYMBOLS); - tester.keyEvent(Alignment.CENTER, Key.TEXT, EventType.KEY_DOWN, - Keyset.MORE_SYMBOLS); - // Symbol key only has center alignment. - tester.keyEvent(Alignment.CENTER, Key.SYMBOL, EventType.KEY_UP, - Keyset.UPPER); - - // switch back to lower case - tester.keyEvent(alignment, Key.SHIFT, EventType.KEY_DOWN, - Keyset.UPPER); - tester.keyEvent(alignment, Key.SHIFT, EventType.KEY_UP, Keyset.LOWER); - }; - // Run the test using the left shift key. - checkPersistantCapitalization(Alignment.LEFT); - // Run the test using the right shift key. - checkPersistantCapitalization(Alignment.RIGHT); - - tester.scheduleTest('testInputTypeResponsivenessAsync', testDoneCallback); -} - -/** - * Tests that changing the input type changes the layout. The test is run - * asynchronously since the keyboard loads keysets dynamically. - * @param {Function} testDoneCallback The function to be called on completion. - */ -function testInputTypeResponsivenessAsync(testDoneCallback) { - var tester = new KeysetTransitionTester(); - - tester.init = function() { - $('keyboard').inputTypeValue = 'text'; - }; - - // Shift-lock - tester.keyEvent(Alignment.LEFT, Key.SHIFT, EventType.KEY_DOWN, - Keyset.DEFAULT_LOWER); - tester.wait(1000, Keyset.DEFAULT_UPPER); - tester.keyEvent(Alignment.LEFT, Key.SHIFT, EventType.KEY_UP, - Keyset.DEFAULT_UPPER); - - // Force keyset tranistions via input type changes. Should reset to lowercase - // once back to the text keyset. - tester.transition(InputType.NUMBER, Keyset.DEFAULT_UPPER); - tester.transition(InputType.TEXT, Keyset.KEYPAD); - tester.verifyReset(Keyset.DEFAULT_LOWER); - - tester.scheduleTest('testInputTypeResponsivenessAsync', testDoneCallback); -} - -/** - * Tests that keyset transitions work as expected. - * The test is run asynchronously since the keyboard loads keysets dynamically. - * @param {Function} testDoneCallback The function to be called on completion. - */ -function testKeysetTransitionsAsync(testDoneCallback) { - - var tester = new KeysetTransitionTester('qwerty'); - - /** - * Checks the transitions using the shift key with the given alignment. - * @param {string} alignment The alignment of the shift key. - */ - var checkBasicTransitions = function(alignment) { - // Test the path abc -> symbol -> more -> symbol -> abc. - tester.keyEvent(Alignment.CENTER, Key.SYMBOL, EventType.KEY_DOWN, - Keyset.LOWER); - tester.keyEvent(Alignment.CENTER, Key.TEXT, EventType.KEY_UP, - Keyset.SYMBOL); - tester.keyEvent(Alignment.CENTER, Key.MORE_SYMBOLS, EventType.KEY_DOWN, - Keyset.SYMBOL); - tester.keyEvent(Alignment.CENTER, Key.SYMBOL, EventType.KEY_UP, - Keyset.MORE_SYMBOLS); - tester.keyEvent(Alignment.CENTER, Key.SYMBOL, EventType.KEY_DOWN, - Keyset.MORE_SYMBOLS); - tester.keyEvent(Alignment.CENTER, Key.MORE_SYMBOLS, EventType.KEY_UP, - Keyset.SYMBOL); - tester.keyEvent(Alignment.CENTER, Key.TEXT, EventType.KEY_DOWN, - Keyset.SYMBOL); - tester.keyEvent(Alignment.CENTER, Key.SYMBOL, EventType.KEY_UP, - Keyset.LOWER); - - // Test the path abc -> symbol -> more -> abc. - tester.keyEvent(Alignment.CENTER, Key.SYMBOL, EventType.KEY_DOWN, - Keyset.LOWER); - // Mock keyUp on the abc since it occupies the space where the - // symbol key used to be. - tester.keyEvent(Alignment.CENTER, Key.TEXT, EventType.KEY_UP, - Keyset.SYMBOL); - tester.keyEvent(Alignment.CENTER, Key.MORE_SYMBOLS, EventType.KEY_DOWN, - Keyset.SYMBOL); - tester.keyEvent(Alignment.CENTER, Key.SYMBOL, EventType.KEY_UP, - Keyset.MORE_SYMBOLS); - tester.keyEvent(Alignment.CENTER, Key.TEXT, EventType.KEY_DOWN, - Keyset.MORE_SYMBOLS); - tester.keyEvent(Alignment.CENTER, Key.SYMBOL, EventType.KEY_UP, - Keyset.LOWER); - - // Test the path abc -> highlighted ABC -> symbol -> abc. - tester.keyEvent(alignment, Key.SHIFT, EventType.KEY_DOWN, Keyset.LOWER); - tester.keyEvent(alignment, Key.SHIFT, EventType.KEY_UP, Keyset.UPPER); - tester.keyEvent(Alignment.CENTER, Key.SYMBOL, EventType.KEY_DOWN, - Keyset.UPPER); - tester.keyEvent(Alignment.CENTER, Key.TEXT, EventType.KEY_UP, - Keyset.SYMBOL); - tester.keyEvent(Alignment.CENTER, Key.TEXT, EventType.KEY_DOWN, - Keyset.SYMBOL); - tester.keyEvent(Alignment.CENTER, Key.SYMBOL, EventType.KEY_UP, - Keyset.LOWER); - }; - // Tests the transitions using the left shift key. - checkBasicTransitions(Alignment.LEFT); - // Tests the transitions using the right shift key. - checkBasicTransitions(Alignment.RIGHT); - - tester.scheduleTest('testKeysetTransitionsAsync', testDoneCallback); -} - -/** - * Tests that we transition to uppercase on punctuation followed by a space. - * The test is run asynchronously since the keyboard loads keysets dynamically. - * @param {Function} testDoneCallback The function to be called on completion. - */ -function testUpperOnSpaceAfterPunctuation(testDoneCallback) { - var tester = new KeysetTransitionTester('qwerty'); - tester.typeKey('a', 0x41, Modifier.NONE, Keyset.LOWER); - tester.typeKey('.', 0xBE, Modifier.NONE, Keyset.LOWER); - tester.typeKey(' ', 0x20, Modifier.NONE, Keyset.LOWER); - tester.typeKey('A', 0x41, Modifier.SHIFT, Keyset.UPPER); - tester.typeKey('a', 0x41, Modifier.NONE, Keyset.LOWER); - // Test that we do not enter upper if there is a character between the . and - // the space. - tester.typeKey('.', 0xBE, Modifier.NONE, Keyset.LOWER); - tester.typeKey('a', 0x41, Modifier.NONE, Keyset.LOWER); - tester.typeKey(' ', 0x20, Modifier.NONE, Keyset.LOWER); - tester.typeKey('a', 0x41, Modifier.NONE, Keyset.LOWER); - // Test the newline also causes a transition to upper. - tester.typeKey('a', 0x41, Modifier.NONE, Keyset.LOWER); - tester.typeKey('.', 0xBE, Modifier.NONE, Keyset.LOWER); - tester.typeKey('\n', 0x0D, Modifier.NONE, Keyset.LOWER); - tester.typeKey('A', 0x41, Modifier.SHIFT, Keyset.UPPER); - tester.typeKey('a', 0x41, Modifier.NONE, Keyset.LOWER); - tester.scheduleTest('testUpperOnSpaceAfterPunctuation', testDoneCallback); -}
diff --git a/chrome/test/data/extensions/api_test/automation/tests/unit/test.js b/chrome/test/data/extensions/api_test/automation/tests/unit/test.js index 6ff1ece..9c0cda576 100644 --- a/chrome/test/data/extensions/api_test/automation/tests/unit/test.js +++ b/chrome/test/data/extensions/api_test/automation/tests/unit/test.js
@@ -289,19 +289,15 @@ 'docTitle': 'Google Chrome Terms of Service' }, 'intAttributes': { 'scrollY': 583, 'scrollYMax': 9336 }, - 'childIds': [2, 3, 4] + 'childIds': [2, 3] }, { - 'id': 2, 'role': 'editableText', - 'childIds': [] - }, - { - 'id': 3, 'role': 'textField', + 'id': 2, 'role': 'textField', 'intAttributes': { 'textSelStart': 10, 'textSelEnd': 20 }, 'childIds': [] }, { - 'id': 4, 'role': 'textArea', + 'id': 3, 'role': 'textArea', 'childIds': [] }, @@ -312,10 +308,7 @@ assertEq(true, tree.docLoaded); assertFalse('textSelStart' in tree); assertFalse('textSelEnd' in tree); - var editableText = tree.firstChild; - assertEq(-1, editableText.textSelStart); - assertEq(-1, editableText.textSelEnd); - var textField = editableText.nextSibling; + var textField = tree.firstChild; assertEq(10, textField.textSelStart); assertEq(20, textField.textSelEnd); var textArea = textField.nextSibling;
diff --git a/chrome/test/data/extensions/api_test/file_manager_browsertest/file_manager/open_zip_files.js b/chrome/test/data/extensions/api_test/file_manager_browsertest/file_manager/open_zip_files.js deleted file mode 100644 index 8e3aa1e38..0000000 --- a/chrome/test/data/extensions/api_test/file_manager_browsertest/file_manager/open_zip_files.js +++ /dev/null
@@ -1,81 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -'use strict'; - -/** - * Tests if we can open and unmount a zip file. - * @param {string} path Directory path to be tested. - */ -function zipOpen(path) { - var appId; - StepsRunner.run([ - // Add a ZIP file. - function() { - addEntries(['local', 'drive'], [ENTRIES.zipArchive], this.next); - }, - // Open a window. - function(result) { - chrome.test.assertTrue(result); - openNewWindow(null, path, this.next); - }, - // Wait for going back. - function(inAppId) { - appId = inAppId; - remoteCall.waitForElement(appId, '#detail-table').then(this.next); - }, - function() { - remoteCall.waitForFiles(appId, [ENTRIES.zipArchive.getExpectedRow()]). - then(this.next); - }, - // Open a file. - function(result) { - remoteCall.callRemoteTestUtil('openFile', - appId, - [ENTRIES.zipArchive.nameText], - this.next); - }, - // Wait for ZIP contents. - function(result) { - chrome.test.assertTrue(result); - remoteCall.waitForFiles(appId, - [[ - 'SUCCESSFULLY_PERFORMED_FAKE_MOUNT.txt', - '21 bytes', - 'Plain text', - '' - ]], - {ignoreLastModifiedTime: true}).then(this.next); - }, - // Unmount the zip. - function(result) { - remoteCall.waitForElement(appId, '.root-eject', this.next). - then(this.next); - }, - // Unmount the zip. - function(element) { - remoteCall.callRemoteTestUtil('fakeMouseClick', - appId, - ['.root-eject'], - this.next); - }, - // Wait for going back. - function(result) { - chrome.test.assertTrue(result); - remoteCall.waitForFiles(appId, [ENTRIES.zipArchive.getExpectedRow()]). - then(this.next); - }, - function() { - checkIfNoErrorsOccured(this.next); - } - ]); -} - -testcase.zipOpenDownloads = function() { - zipOpen(RootPath.DOWNLOADS); -}; - -testcase.zipOpenDrive = function() { - zipOpen(RootPath.DRIVE); -};
diff --git a/chrome/test/data/extensions/api_test/inline_install_private/app.crx b/chrome/test/data/extensions/api_test/inline_install_private/app.crx new file mode 100644 index 0000000..bae6b40 --- /dev/null +++ b/chrome/test/data/extensions/api_test/inline_install_private/app.crx Binary files differ
diff --git a/chrome/test/data/extensions/api_test/inline_install_private/app.pem b/chrome/test/data/extensions/api_test/inline_install_private/app.pem new file mode 100644 index 0000000..e752e59 --- /dev/null +++ b/chrome/test/data/extensions/api_test/inline_install_private/app.pem
@@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDofAfBjmMBM1Kh +LXPpLaSX6vrKUm4STddnZJHiHb+liaLngIqgoCtZ4Gmx4HADoZovBOt+3o4itayr +sdzYE/FLsaAmt49JoXxri89SoYvEuagjAw+0SgUB7q6ofvNXEVCSMT2UQ6fEEm5U +38Wn65UGsZcsx3IfXpRg7yhL17inhKxR+w3G4gjqUdmqeXNewFINXDzYNNQfae8x +uHp4NgTBSxp8MPVZfjiJSg2TivJj3Nx901qlTIH+Es9tSxJHQsA+f/YB8DIKF8+W +tiXbQ7i7oV3rg6NeWy5xkHLasJzxj7QzR8XJTtzIxfvVR+gmquClwxbjiSnOKUGE +fcFbVlpLAgMBAAECggEARuFRyAxuWPZZ0fQ2q7gTv5GPxtGc542+B7Lc23Cwdnrh +JO3G1jQfI3bNIsNHw4Ooq383gWW/Ngvnyi0fJO3nmmlcZ5F9aTiH444rtoi0QVVN +UudjCVer8SvhKlQSQtBvnTLQEH0UEC6CXvQeohSsSe8pJSjlvXSrjmY8BeuOS9wN +nmeXNT80pm0Y/3ojvCsvWe7Crp98XnKHiBedPnhKVX4adtkNpL9azeANnYc5h/hB +LmubA3CIUeSGUsTqlfYFHOgXiUJPZq3h3JTBUsNkEwMQGHuyQpPHig8dYXhs63Fn +LfsAQ9p8Xet4lVMmyGzWUgmmqZ4Eagd0FB4vKo6zEQKBgQD1nyuNzOeyCk+FYwB3 +v4DJUe73Kuvw/Lb0d3a3sdSiDCCEa9kI0vhGMUj+3WDimaW+q7mT7Fbdh4DNr3pt +w+RDimEaN1Q52/tZEUpTZNIVFJGJ97Yjy8oKox5n2wToNYczaAJ5FpQF7DphEXAN +XCE6WSLaZCCNwTiz1q/blhMwaQKBgQDyTsHzGI4kUqsfx8WcGna/dteEANFjYuBp +YNoHeQOAIJCv2vlgagQjtMQd0o7hQOw9fx51v741Dk6Pjj2HWq7Eagz+IumnbNYA +fVDkZKA2rg42VHxtG0+NiNdk+JnT+OZTN1oT6p6mUuS4NcJ0+m84qsu2PEouJas5 +s1yE3NNekwKBgGzFBeaPnPMM+dYZ13UwCvocHHS8PyvC3co4tQv35i+0qxm5IK11 +r5h17tteca8nV2yuY0oMWRNVFEcBtHezTfxS5VlUsynELvRsYbu4ZAgNyb2NQs1r +S5eWULqxFOU3/x1Wq/Gve/F7gQbHUBW6fMR4AKUxvfDIZjHNmqblOK4xAoGBAIil +r60HWQnU8RpwD9oT9onNXIbd6zewSDxFWU/DiBzWwKHbzKz5vLHiPINQ/jC76z5X +FPd0lbDYC6fboIlXs52i7QbY64n2z8zg3yCeOtf7Wpp7FNx2/WslE8umgyHOiR2+ +5na65pOHxeK4tpw/qz962n1ADNlvdtuIchGfczgvAoGBAMmCbiygMmaddQDUNouw +KaOTvMPuXwX9cbySZ872jcEY/JGqYVmvFh7NQqyMLkGj9EOFhrmHXty1Mp43Ng3M +npscGFJ5mMj3gzstfaNBaLpsgEUVRmxFcxKlQ+0c+A3R+ZwMO3dlqa6aOZ3lj5wT +cvm4Aiatv1fbC96IHwgNMScn +-----END PRIVATE KEY-----
diff --git a/chrome/test/data/extensions/api_test/inline_install_private/app/background.js b/chrome/test/data/extensions/api_test/inline_install_private/app/background.js new file mode 100644 index 0000000..b9d5430 --- /dev/null +++ b/chrome/test/data/extensions/api_test/inline_install_private/app/background.js
@@ -0,0 +1,7 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +chrome.app.runtime.onLaunched.addListener(function() { + chrome.app.window.create("page.html"); +}); \ No newline at end of file
diff --git a/chrome/test/data/extensions/api_test/inline_install_private/app/icon.png b/chrome/test/data/extensions/api_test/inline_install_private/app/icon.png new file mode 100644 index 0000000..85325d6 --- /dev/null +++ b/chrome/test/data/extensions/api_test/inline_install_private/app/icon.png Binary files differ
diff --git a/chrome/test/data/extensions/api_test/inline_install_private/app/manifest.json b/chrome/test/data/extensions/api_test/inline_install_private/app/manifest.json new file mode 100644 index 0000000..29c7f05 --- /dev/null +++ b/chrome/test/data/extensions/api_test/inline_install_private/app/manifest.json
@@ -0,0 +1,13 @@ +{ + "name": "Test App", + "version": "0.5", + "manifest_version": 2, + "icons": { + "48": "icon.png" + }, + "app": { + "background": { + "scripts": ["background.js"] + } + } +}
diff --git a/chrome/test/data/extensions/api_test/inline_install_private/app/page.html b/chrome/test/data/extensions/api_test/inline_install_private/app/page.html new file mode 100644 index 0000000..3b18e51 --- /dev/null +++ b/chrome/test/data/extensions/api_test/inline_install_private/app/page.html
@@ -0,0 +1 @@ +hello world
diff --git a/chrome/test/data/extensions/api_test/inline_install_private/inlineinstall/detail/adjpiofaikamijlfbhehkldllbdcbmeb b/chrome/test/data/extensions/api_test/inline_install_private/inlineinstall/detail/adjpiofaikamijlfbhehkldllbdcbmeb new file mode 100644 index 0000000..665a0159 --- /dev/null +++ b/chrome/test/data/extensions/api_test/inline_install_private/inlineinstall/detail/adjpiofaikamijlfbhehkldllbdcbmeb
@@ -0,0 +1,7 @@ +{ + "icon_url": "inline_install_private/app/icon.png", + "users": "17", + "average_rating": 3.14, + "rating_count": 15, + "manifest": "{ \"name\": \"Test App\", \"version\": \"0.5\", \"manifest_version\": 2, \"icons\": { \"48\": \"icon.png\" }, \"app\": { \"background\": { \"scripts\": [\"background.js\"] } } }" +} \ No newline at end of file
diff --git a/chrome/test/data/extensions/api_test/inline_install_private/test_driver/background.js b/chrome/test/data/extensions/api_test/inline_install_private/test_driver/background.js new file mode 100644 index 0000000..b844294 --- /dev/null +++ b/chrome/test/data/extensions/api_test/inline_install_private/test_driver/background.js
@@ -0,0 +1,25 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +function backgroundInstall() { + chrome.inlineInstallPrivate.install("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + function(error, errorCode) { + if (error == "Must be called from a foreground page") + chrome.test.sendMessage("success"); + else + console.error("Did not receive expected error; got '" + error + "'"); + }); +} + +// This gets set to the name of the test we want to run, either locally in this +// background page or in a window we open up. +var testName; + +chrome.test.sendMessage("ready", function (response) { + testName = response; + if (testName == "backgroundInstall") + backgroundInstall(); + else + chrome.app.window.create("page.html"); +});
diff --git a/chrome/test/data/extensions/api_test/inline_install_private/test_driver/manifest.json b/chrome/test/data/extensions/api_test/inline_install_private/test_driver/manifest.json new file mode 100644 index 0000000..c94c364 --- /dev/null +++ b/chrome/test/data/extensions/api_test/inline_install_private/test_driver/manifest.json
@@ -0,0 +1,11 @@ +{ + "name": "Inline Install API Test Driver", + "version": "0.5", + "manifest_version": 2, + "permissions": ["inlineInstallPrivate"], + "app": { + "background": { + "scripts": ["background.js"] + } + } +}
diff --git a/chrome/test/data/extensions/api_test/inline_install_private/test_driver/page.html b/chrome/test/data/extensions/api_test/inline_install_private/test_driver/page.html new file mode 100644 index 0000000..11066fe --- /dev/null +++ b/chrome/test/data/extensions/api_test/inline_install_private/test_driver/page.html
@@ -0,0 +1,2 @@ + +<script src="page.js"></script>
diff --git a/chrome/test/data/extensions/api_test/inline_install_private/test_driver/page.js b/chrome/test/data/extensions/api_test/inline_install_private/test_driver/page.js new file mode 100644 index 0000000..6706774 --- /dev/null +++ b/chrome/test/data/extensions/api_test/inline_install_private/test_driver/page.js
@@ -0,0 +1,42 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +var app_id = "adjpiofaikamijlfbhehkldllbdcbmeb"; +var extension_id = "ecglahbcnmdpdciemllbhojghbkagdje"; + +function successfulInstall() { + chrome.inlineInstallPrivate.install(app_id, + function(err, errorCode) { + if (err.length == 0 && errorCode == "success") { + chrome.test.sendMessage("success"); + } else { + console.error("unexpected result, error:" + err + " errorCode:" + + errorCode); + } + }); +} + +function expectError(id, expectedErrorCode, expectedError) { + chrome.inlineInstallPrivate.install(id, function(err, errorCode) { + if (errorCode == expectedErrorCode && + (typeof(expectedError) == "undefined" || expectedError == err)) { + chrome.test.sendMessage("success"); + } else { + console.error("unexpected result, error:" + err + ", errorCode:" + + errorCode); + } + }); +} + +chrome.runtime.getBackgroundPage(function(bg) { + console.error("testName is " + bg.testName); + + if (bg.testName == "successfulInstall") { + successfulInstall(); + } else if (bg.testName == "noGesture") { + expectError(app_id, "notPermitted", "Must be called with a user gesture"); + } else if (bg.testName == "onlyApps") { + expectError(extension_id, "notPermitted"); + } +});
diff --git a/chrome/test/data/extensions/api_test/messaging/externally_connectable/sites/assertions.js b/chrome/test/data/extensions/api_test/messaging/externally_connectable/sites/assertions.js index 3fab920..b106b76 100644 --- a/chrome/test/data/extensions/api_test/messaging/externally_connectable/sites/assertions.js +++ b/chrome/test/data/extensions/api_test/messaging/externally_connectable/sites/assertions.js
@@ -250,6 +250,12 @@ }); }, + trySendMessage: function(extensionId) { + chrome.runtime.sendMessage(extensionId, kMessage, function(response) { + // The result is unimportant. All that matters is the attempt. + }); + }, + areAnyRuntimePropertiesDefined: function(names) { var result = false; if (chrome.runtime) {
diff --git a/chrome/test/data/extensions/platform_apps/web_view/rules_registry/main.html b/chrome/test/data/extensions/platform_apps/web_view/rules_registry/main.html new file mode 100644 index 0000000..d7227a6 --- /dev/null +++ b/chrome/test/data/extensions/platform_apps/web_view/rules_registry/main.html
@@ -0,0 +1,12 @@ +<!doctype html> +<!-- + * Copyright 2014 The Chromium Authors. All rights reserved. Use of this + * source code is governed by a BSD-style license that can be found in the + * LICENSE file. +--> +<html> +<body> + <div id="webview-tag-container"></div> + <script src="main.js"></script> +</body> +</html>
diff --git a/chrome/test/data/extensions/platform_apps/web_view/rules_registry/main.js b/chrome/test/data/extensions/platform_apps/web_view/rules_registry/main.js new file mode 100644 index 0000000..85de247 --- /dev/null +++ b/chrome/test/data/extensions/platform_apps/web_view/rules_registry/main.js
@@ -0,0 +1,19 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +var startTest = function() { + document.querySelector('#webview-tag-container').innerHTML = + '<webview style="width: 10px; height: 10px; margin: 0; padding: 0;"' + + '></webview>'; + + var webview = document.querySelector('webview'); + var onLoadStop = function(e) { + chrome.test.sendMessage('WebViewTest.LAUNCHED'); + }; + + webview.addEventListener('loadstop', onLoadStop); + webview.src = 'data:text/html,<body>Guest</body>'; +}; + +window.onload = startTest;
diff --git a/chrome/test/data/extensions/platform_apps/web_view/rules_registry/manifest.json b/chrome/test/data/extensions/platform_apps/web_view/rules_registry/manifest.json new file mode 100644 index 0000000..98bb9963d --- /dev/null +++ b/chrome/test/data/extensions/platform_apps/web_view/rules_registry/manifest.json
@@ -0,0 +1,12 @@ +{ + "name": "<webview> rules registry tests.", + "version": "1", + "permissions": [ + "webview" + ], + "app": { + "background": { + "scripts": ["test.js"] + } + } +}
diff --git a/chrome/test/data/extensions/platform_apps/web_view/rules_registry/test.js b/chrome/test/data/extensions/platform_apps/web_view/rules_registry/test.js new file mode 100644 index 0000000..a80d274 --- /dev/null +++ b/chrome/test/data/extensions/platform_apps/web_view/rules_registry/test.js
@@ -0,0 +1,7 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +chrome.app.runtime.onLaunched.addListener(function() { + chrome.app.window.create('main.html', {}, function () {}); +});
diff --git a/chrome/test/data/extensions/platform_apps/window_api_intercept_all_keys/has_permission/main.html b/chrome/test/data/extensions/platform_apps/window_api_intercept_all_keys/has_permission/main.html new file mode 100644 index 0000000..fa0c45f2 --- /dev/null +++ b/chrome/test/data/extensions/platform_apps/window_api_intercept_all_keys/has_permission/main.html
@@ -0,0 +1 @@ +<!-- empty --> \ No newline at end of file
diff --git a/chrome/test/data/extensions/platform_apps/window_api_intercept_all_keys/has_permission/main.js b/chrome/test/data/extensions/platform_apps/window_api_intercept_all_keys/has_permission/main.js new file mode 100644 index 0000000..4151b531 --- /dev/null +++ b/chrome/test/data/extensions/platform_apps/window_api_intercept_all_keys/has_permission/main.js
@@ -0,0 +1,82 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +var mainWindow; +var debug = 0; +if (debug) { + chrome.test.log = function(msg) { + console.log(msg); + } +} + +function onReply(reply) { + switch (reply) { + case 'enable': + chrome.test.log('enabling intercept all keys'); + mainWindow.setInterceptAllKeys(true); + break; + case 'disable': + chrome.test.log('disabling intercept all keys'); + mainWindow.setInterceptAllKeys(false); + break; + } + chrome.test.sendMessage('readyForCommand', onReply); +} + +function onKeyUp(e) { + handleEvent(e); + chrome.test.sendMessage('KeyReceived: '+ e.keyCode); + return false; +} + +// Based on keyevent browser test to convert event to string. +// Format used is: +// <type> <keyCode> <charCode> <ctrlKey> <shiftKey> <altKey> <commandKey> +// where <type> may be 'D' (keydown), 'P' (keypress) or 'U' (keyup). +// <ctrlKey>, <shiftKey> <altKey> and <commandKey> are boolean value indicating +// the state of corresponding modifier key. +function handleEvent(e) { + var prefixes = { + 'keydown': 'D', + 'keypress': 'P', + 'keyup': 'U', + 'textInput': 'T', + }; + + var evt = e || window.event; + var result = prefixes[evt.type] + ' '; + if (evt.type == 'textInput') { + result += evt.data; + } else { + // On Linux, the keydown event of a modifier key doesn't have the + // corresponding modifier attribute set, while the keyup event does have, + // eg. pressing and releasing ctrl may generate a keydown event with + // ctrlKey=false and a keyup event with ctrlKey=true. + // But Windows and Mac have opposite behavior than Linux. + // To make the C++ testing code simpler, if it's a modifier key event, + // then ignores the corresponding modifier attribute by setting it to true. + var keyId = evt.keyIdentifier; + result += (evt.keyCode + ' ' + evt.charCode + ' ' + + (keyId == 'Control' ? true : evt.ctrlKey) + ' ' + + (keyId == 'Shift' ? true : evt.shiftKey) + ' ' + + (keyId == 'Alt' ? true : evt.altKey) + ' ' + + (keyId == 'Meta' ? true : evt.metaKey)); + } + + chrome.test.log(result); + chrome.test.sendMessage(result); + return false; +} + +chrome.app.runtime.onLaunched.addListener(function() { + chrome.app.window.create('main.html', {}, function(win) { + mainWindow = win; + win.contentWindow.document.addEventListener('keydown', handleEvent); + win.contentWindow.document.addEventListener('keypress', handleEvent); + win.contentWindow.document.addEventListener('keyup', onKeyUp); + + chrome.test.sendMessage('Launched'); + chrome.test.sendMessage('readyForCommand', onReply); + }); +});
diff --git a/chrome/test/data/extensions/platform_apps/window_api_intercept_all_keys/has_permission/manifest.json b/chrome/test/data/extensions/platform_apps/window_api_intercept_all_keys/has_permission/manifest.json new file mode 100644 index 0000000..991d54f --- /dev/null +++ b/chrome/test/data/extensions/platform_apps/window_api_intercept_all_keys/has_permission/manifest.json
@@ -0,0 +1,13 @@ +{ + "name": "Window API - InterceptAllKeys", + "manifest_version": 2, + "version": "1", + "app": { + "background": { + "scripts": ["main.js"] + } + }, + "permissions": [ + "app.window.interceptAllKeys" + ] +}
diff --git a/chrome/test/data/extensions/platform_apps/window_api_intercept_all_keys/no_permission/main.html b/chrome/test/data/extensions/platform_apps/window_api_intercept_all_keys/no_permission/main.html new file mode 100644 index 0000000..fa0c45f2 --- /dev/null +++ b/chrome/test/data/extensions/platform_apps/window_api_intercept_all_keys/no_permission/main.html
@@ -0,0 +1 @@ +<!-- empty --> \ No newline at end of file
diff --git a/chrome/test/data/extensions/platform_apps/window_api_intercept_all_keys/no_permission/main.js b/chrome/test/data/extensions/platform_apps/window_api_intercept_all_keys/no_permission/main.js new file mode 100644 index 0000000..4151b531 --- /dev/null +++ b/chrome/test/data/extensions/platform_apps/window_api_intercept_all_keys/no_permission/main.js
@@ -0,0 +1,82 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +var mainWindow; +var debug = 0; +if (debug) { + chrome.test.log = function(msg) { + console.log(msg); + } +} + +function onReply(reply) { + switch (reply) { + case 'enable': + chrome.test.log('enabling intercept all keys'); + mainWindow.setInterceptAllKeys(true); + break; + case 'disable': + chrome.test.log('disabling intercept all keys'); + mainWindow.setInterceptAllKeys(false); + break; + } + chrome.test.sendMessage('readyForCommand', onReply); +} + +function onKeyUp(e) { + handleEvent(e); + chrome.test.sendMessage('KeyReceived: '+ e.keyCode); + return false; +} + +// Based on keyevent browser test to convert event to string. +// Format used is: +// <type> <keyCode> <charCode> <ctrlKey> <shiftKey> <altKey> <commandKey> +// where <type> may be 'D' (keydown), 'P' (keypress) or 'U' (keyup). +// <ctrlKey>, <shiftKey> <altKey> and <commandKey> are boolean value indicating +// the state of corresponding modifier key. +function handleEvent(e) { + var prefixes = { + 'keydown': 'D', + 'keypress': 'P', + 'keyup': 'U', + 'textInput': 'T', + }; + + var evt = e || window.event; + var result = prefixes[evt.type] + ' '; + if (evt.type == 'textInput') { + result += evt.data; + } else { + // On Linux, the keydown event of a modifier key doesn't have the + // corresponding modifier attribute set, while the keyup event does have, + // eg. pressing and releasing ctrl may generate a keydown event with + // ctrlKey=false and a keyup event with ctrlKey=true. + // But Windows and Mac have opposite behavior than Linux. + // To make the C++ testing code simpler, if it's a modifier key event, + // then ignores the corresponding modifier attribute by setting it to true. + var keyId = evt.keyIdentifier; + result += (evt.keyCode + ' ' + evt.charCode + ' ' + + (keyId == 'Control' ? true : evt.ctrlKey) + ' ' + + (keyId == 'Shift' ? true : evt.shiftKey) + ' ' + + (keyId == 'Alt' ? true : evt.altKey) + ' ' + + (keyId == 'Meta' ? true : evt.metaKey)); + } + + chrome.test.log(result); + chrome.test.sendMessage(result); + return false; +} + +chrome.app.runtime.onLaunched.addListener(function() { + chrome.app.window.create('main.html', {}, function(win) { + mainWindow = win; + win.contentWindow.document.addEventListener('keydown', handleEvent); + win.contentWindow.document.addEventListener('keypress', handleEvent); + win.contentWindow.document.addEventListener('keyup', onKeyUp); + + chrome.test.sendMessage('Launched'); + chrome.test.sendMessage('readyForCommand', onReply); + }); +});
diff --git a/chrome/test/data/extensions/platform_apps/window_api_intercept_all_keys/no_permission/manifest.json b/chrome/test/data/extensions/platform_apps/window_api_intercept_all_keys/no_permission/manifest.json new file mode 100644 index 0000000..9db6c84b --- /dev/null +++ b/chrome/test/data/extensions/platform_apps/window_api_intercept_all_keys/no_permission/manifest.json
@@ -0,0 +1,10 @@ +{ + "name": "Window API - InterceptAllKeys", + "manifest_version": 2, + "version": "1", + "app": { + "background": { + "scripts": ["main.js"] + } + } +}
diff --git a/chrome/test/data/extensions/show_managed_storage.crx b/chrome/test/data/extensions/show_managed_storage.crx new file mode 100644 index 0000000..db1ac004 --- /dev/null +++ b/chrome/test/data/extensions/show_managed_storage.crx Binary files differ
diff --git a/chrome/test/data/file_manager/unit_tests/directory_tree_unittest.js b/chrome/test/data/file_manager/unit_tests/directory_tree_unittest.js index ec9d8ed..d4025a3 100644 --- a/chrome/test/data/file_manager/unit_tests/directory_tree_unittest.js +++ b/chrome/test/data/file_manager/unit_tests/directory_tree_unittest.js
@@ -14,7 +14,9 @@ DRIVE_MY_DRIVE_LABEL: 'My Drive', DRIVE_OFFLINE_COLLECTION_LABEL: 'Offline', DRIVE_SHARED_WITH_ME_COLLECTION_LABEL: 'Shared with me', - DRIVE_RECENT_COLLECTION_LABEL: 'Recent' + DRIVE_RECENT_COLLECTION_LABEL: 'Recent', + REMOVABLE_DIRECTORY_LABEL: 'External Storage', + ARCHIVE_DIRECTORY_LABEL: 'Archives' }; function setUp() { @@ -33,6 +35,21 @@ } /** + * Returns item labels of a directory tree as a list. + * + * @param {DirectoryTree} directoryTree A directory tree. + * @return {Array.<string>} List of labels. + */ +function getDirectoryTreeItemLabelsAsAList(directoryTree) { + var result = []; + for (var i = 0; i < directoryTree.items.length; i++) { + var item = directoryTree.items[i]; + result.push(item.label); + } + return result; +} + +/** * Test case for typical creation of directory tree. * This test expect that the following tree is built. * @@ -89,3 +106,101 @@ driveItem.items[3].label); }), callback); } + +/** + * Test case for updateSubElementsFromList. + * + * Mounts/unmounts removable and archive volumes, and checks these volumes come + * up to/disappear from the list correctly. + */ +function testUpdateSubElementsFromList() { + // Creates elements. + var parentElement = document.createElement('div'); + var directoryTree = document.createElement('div'); + parentElement.appendChild(directoryTree); + + // Creates mocks. + var directoryModel = new MockDirectoryModel(); + var volumeManager = new MockVolumeManager(); + var metadataCache = new MockMetadataCache(); + + // Sets entry which is returned by + // window.webkitResolveLocalFileSystemURLResults. + var driveFileSystem = volumeManager.volumeInfoList.item(0).fileSystem; + window.webkitResolveLocalFileSystemURLEntries['filesystem:drive/root'] = + new MockDirectoryEntry(driveFileSystem, '/root'); + + DirectoryTree.decorate(directoryTree, directoryModel, volumeManager, + metadataCache, true); + directoryTree.dataModel = new MockNavigationListModel(volumeManager); + directoryTree.updateSubElementsFromList(true); + + // There are 2 volumes, Drive and Downloads, at first. + assertArrayEquals([ + str('DRIVE_DIRECTORY_LABEL'), + str('DOWNLOADS_DIRECTORY_LABEL') + ], getDirectoryTreeItemLabelsAsAList(directoryTree)); + + // Mounts a removable volume. + var removableVolume = MockVolumeManager.createMockVolumeInfo( + VolumeManagerCommon.VolumeType.REMOVABLE, + 'removable', + str('REMOVABLE_DIRECTORY_LABEL')); + volumeManager.volumeInfoList.push(removableVolume); + + // Asserts that the directoryTree is not updated before the update. + assertArrayEquals([ + str('DRIVE_DIRECTORY_LABEL'), + str('DOWNLOADS_DIRECTORY_LABEL') + ], getDirectoryTreeItemLabelsAsAList(directoryTree)); + + // Asserts that a removable directory is added after the update. + directoryTree.updateSubElementsFromList(false); + assertArrayEquals([ + str('DRIVE_DIRECTORY_LABEL'), + str('DOWNLOADS_DIRECTORY_LABEL'), + str('REMOVABLE_DIRECTORY_LABEL') + ], getDirectoryTreeItemLabelsAsAList(directoryTree)); + + // Mounts an archive volume before the removable directory. + var archiveVolume = MockVolumeManager.createMockVolumeInfo( + VolumeManagerCommon.VolumeType.ARCHIVE, + 'archive', + str('ARCHIVE_DIRECTORY_LABEL')); + volumeManager.volumeInfoList.splice(2, 0, archiveVolume); + + // Asserts that the directoryTree is not updated before the update. + assertArrayEquals([ + str('DRIVE_DIRECTORY_LABEL'), + str('DOWNLOADS_DIRECTORY_LABEL'), + str('REMOVABLE_DIRECTORY_LABEL') + ], getDirectoryTreeItemLabelsAsAList(directoryTree)); + + // Asserts that an archive directory is added before the removable directory. + directoryTree.updateSubElementsFromList(false); + assertArrayEquals([ + str('DRIVE_DIRECTORY_LABEL'), + str('DOWNLOADS_DIRECTORY_LABEL'), + str('ARCHIVE_DIRECTORY_LABEL'), + str('REMOVABLE_DIRECTORY_LABEL') + ], getDirectoryTreeItemLabelsAsAList(directoryTree)); + + // Deletes an archive directory. + volumeManager.volumeInfoList.splice(2, 1); + + // Asserts that the directoryTree is not updated before the update. + assertArrayEquals([ + str('DRIVE_DIRECTORY_LABEL'), + str('DOWNLOADS_DIRECTORY_LABEL'), + str('ARCHIVE_DIRECTORY_LABEL'), + str('REMOVABLE_DIRECTORY_LABEL') + ], getDirectoryTreeItemLabelsAsAList(directoryTree)); + + // Asserts that an archive directory is deleted. + directoryTree.updateSubElementsFromList(false); + assertArrayEquals([ + str('DRIVE_DIRECTORY_LABEL'), + str('DOWNLOADS_DIRECTORY_LABEL'), + str('REMOVABLE_DIRECTORY_LABEL') + ], getDirectoryTreeItemLabelsAsAList(directoryTree)); +}
diff --git a/chrome/test/data/file_manager/unit_tests/file_operation_manager_unittest.html b/chrome/test/data/file_manager/unit_tests/file_operation_manager_unittest.html index 0ba4542..8e3d798b 100644 --- a/chrome/test/data/file_manager/unit_tests/file_operation_manager_unittest.html +++ b/chrome/test/data/file_manager/unit_tests/file_operation_manager_unittest.html
@@ -13,6 +13,7 @@ <script src="../../../../../ui/file_manager/file_manager/common/js/util.js"></script> <script src="../../../../../ui/file_manager/file_manager/common/js/async_util.js"></script> <script src="../../../../../ui/file_manager/file_manager/background/js/file_operation_manager.js"></script> +<script src="../../../../../ui/file_manager/file_manager/background/js/file_operation_util.js"></script> <script src="mocks/mock_entry.js"></script> <script src="file_operation_manager_unittest.js"></script>
diff --git a/chrome/test/data/file_manager/unit_tests/file_operation_manager_unittest.js b/chrome/test/data/file_manager/unit_tests/file_operation_manager_unittest.js index 80335a6..b94c54b 100644 --- a/chrome/test/data/file_manager/unit_tests/file_operation_manager_unittest.js +++ b/chrome/test/data/file_manager/unit_tests/file_operation_manager_unittest.js
@@ -54,8 +54,8 @@ promise.then( callback.bind(null, false), function(error) { - if (error instanceof FileOperationManager.Error) { - console.error('FileOperationManager.Error: code=' + error.code); + if (error instanceof fileOperationUtil.Error) { + console.error('fileOperationUtil.Error: code=' + error.code); } else { console.error(error.stack || error.name || error); } @@ -215,9 +215,9 @@ var failedPromise = fileOperationUtil.deduplicatePath(fileSystem3.root, 'file.txt'). then(function() { - assertTrue(false, 'FileOperationManager.Error is not reported.'); + assertTrue(false, 'fileOperationUtil.Error is not reported.'); }, function(error) { - assertTrue(error instanceof FileOperationManager.Error); + assertTrue(error instanceof fileOperationUtil.Error); assertEquals(util.FileOperationErrorType.TARGET_EXISTS, error.code); });
diff --git a/chrome/test/data/file_manager/unit_tests/media_scanner_unittest.html b/chrome/test/data/file_manager/unit_tests/media_scanner_unittest.html index dcc7ead..5b31523 100644 --- a/chrome/test/data/file_manager/unit_tests/media_scanner_unittest.html +++ b/chrome/test/data/file_manager/unit_tests/media_scanner_unittest.html
@@ -13,7 +13,7 @@ <!-- Need to load async_util.js before media_scanner.js --> <script src="../../../../../ui/file_manager/file_manager/background/js/media_scanner.js"></script> -<script src="../../../../../ui/file_manager/file_manager/background/js/file_operation_manager.js"></script> +<script src="../../../../../ui/file_manager/file_manager/background/js/file_operation_util.js"></script> <script src="../../../../../ui/file_manager/file_manager/common/js/util.js"></script> <script src="../../../../../ui/file_manager/file_manager/common/js/file_type.js"></script>
diff --git a/chrome/test/data/file_manager/unit_tests/mocks/mock_volume_manager.js b/chrome/test/data/file_manager/unit_tests/mocks/mock_volume_manager.js index 5e11c18..f47dec2e 100644 --- a/chrome/test/data/file_manager/unit_tests/mocks/mock_volume_manager.js +++ b/chrome/test/data/file_manager/unit_tests/mocks/mock_volume_manager.js
@@ -74,7 +74,9 @@ '', // devicePath false, // isReadonly {isCurrentProfile: true, displayName: ''}, // profile - label); // label + label, // label + '', // extensionId + false); // hasMedia return volumeInfo; };
diff --git a/chrome/test/data/iframe.html b/chrome/test/data/iframe.html index a08e34b..eed403d 100644 --- a/chrome/test/data/iframe.html +++ b/chrome/test/data/iframe.html
@@ -1,4 +1,4 @@ <html><head><title>iframe test</title></head> <body> -<iframe src="title1.html"/> +<iframe src="title1.html"></iframe> </body></html> \ No newline at end of file
diff --git a/chrome/test/data/iframe_cross_site.html b/chrome/test/data/iframe_cross_site.html new file mode 100644 index 0000000..37b6148 --- /dev/null +++ b/chrome/test/data/iframe_cross_site.html
@@ -0,0 +1,7 @@ +<html><head><title>cross-site iframe test</title></head> +<body> +<!-- This only works if the CrossSiteRedirector is running on the embedded test + server, and the host_resolver is set up to handle b.com. --> +<iframe src="/cross-site/b.com/title1.html" id="frame1"></iframe> +<iframe src="/cross-site/c.com/title1.html" id="frame2"></iframe> +</body></html> \ No newline at end of file
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json index 44380a73..41c9b6a 100644 --- a/chrome/test/data/policy/policy_test_cases.json +++ b/chrome/test/data/policy/policy_test_cases.json
@@ -319,6 +319,20 @@ "os": ["win", "linux", "mac", "chromeos"] }, + "ForceGoogleSafeSearch": { + "pref": "settings.force_google_safesearch", + "test_policy": { "ForceGoogleSafeSearch": true }, + "settings_pages": [], + "os": ["win", "linux", "mac", "chromeos"] + }, + + "ForceYouTubeSafetyMode": { + "pref": "settings.force_youtube_safety_mode", + "test_policy": { "ForceYouTubeSafetyMode": true }, + "settings_pages": [], + "os": ["win", "linux", "mac", "chromeos"] + }, + "MetricsReportingEnabled": { "os": ["win", "mac", "linux"], "official_only": true,
diff --git a/chrome/test/data/push_messaging/test.html b/chrome/test/data/push_messaging/test.html index 6ee954e..66b6e2f6 100644 --- a/chrome/test/data/push_messaging/test.html +++ b/chrome/test/data/push_messaging/test.html
@@ -48,6 +48,12 @@ } }; + FutureData.prototype.getImmediately = function() { + sendResultToTest(this.data); + }; + + // Notification permission has been coalesced with Push permission. After + // this is granted, Push API registration can succeed. function requestNotificationPermission() { Notification.requestPermission(function(permission) { sendResultToTest('permission status - ' + permission); @@ -61,6 +67,14 @@ }, sendErrorToTest); } + function unregisterServiceWorker() { + navigator.serviceWorker.getRegistration().then(function(swRegistration) { + swRegistration.unregister().then(function(result) { + sendResultToTest('service worker unregistration status: ' + result); + }) + }).catch(sendErrorToTest); + } + function removeManifest() { var element = document.querySelector('link[rel="manifest"]'); if (element) { @@ -71,14 +85,26 @@ } function registerPush() { - navigator.serviceWorker.ready.then(function() { - navigator.push.register().then(function(pushRegistration) { + navigator.serviceWorker.ready.then(function(swRegistration) { + // TODO(mvanouwerkerk): Cleanup once the final API is exposed. + var pushManager = swRegistration.pushManager || navigator.push; + pushManager.register().then(function(pushRegistration) { sendResultToTest(pushRegistration.pushEndpoint + ' - ' + pushRegistration.pushRegistrationId); }, sendErrorToTest); }, sendErrorToTest); } + function hasPermission() { + navigator.serviceWorker.ready.then(function(swRegistration) { + // TODO(mvanouwerkerk): Cleanup once the final API is exposed. + var pushManager = swRegistration.pushManager || navigator.push; + pushManager.hasPermission().then(function(permission) { + sendResultToTest('permission status - ' + permission); + }, sendErrorToTest); + }, sendErrorToTest); + } + function isControlled() { if (navigator.serviceWorker.controller) { sendResultToTest('true - is controlled');
diff --git a/chrome/test/ppapi/ppapi_browsertest.cc b/chrome/test/ppapi/ppapi_browsertest.cc index c3600f7b..f8b76d8 100644 --- a/chrome/test/ppapi/ppapi_browsertest.cc +++ b/chrome/test/ppapi/ppapi_browsertest.cc
@@ -22,6 +22,7 @@ #include "content/public/common/url_constants.h" #include "content/public/test/javascript_test_observer.h" #include "content/public/test/test_renderer_host.h" +#include "extensions/common/constants.h" #include "extensions/test/extension_test_message_listener.h" #include "ppapi/shared_impl/test_harness_utils.h" @@ -320,7 +321,7 @@ RUN_TCPSOCKET_SUBTESTS; } IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClTransitionalNonSfiTest, - MAYBE_PNACL_NONSFI(TCPSocket)) { + MAYBE_PNACL_TRANSITIONAL_NONSFI(TCPSocket)) { RUN_TCPSOCKET_SUBTESTS; } @@ -1480,10 +1481,9 @@ const extensions::Extension* extension = LoadExtension(app_dir); ASSERT_TRUE(extension); - AppLaunchParams params(browser()->profile(), - extension, - extensions::LAUNCH_CONTAINER_NONE, - NEW_WINDOW); + AppLaunchParams params(browser()->profile(), extension, + extensions::LAUNCH_CONTAINER_NONE, NEW_WINDOW, + extensions::SOURCE_UNTRACKED); params.command_line = *CommandLine::ForCurrentProcess(); OpenApplication(params); }
diff --git a/chrome/test/remoting/remote_desktop_browsertest.cc b/chrome/test/remoting/remote_desktop_browsertest.cc index 868f52d..80160d53 100644 --- a/chrome/test/remoting/remote_desktop_browsertest.cc +++ b/chrome/test/remoting/remote_desktop_browsertest.cc
@@ -10,6 +10,7 @@ #include "base/path_service.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/unpacked_installer.h" +#include "chrome/browser/ui/extensions/app_launch_params.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/common/chrome_switches.h" #include "chrome/test/remoting/key_code_conv.h" @@ -174,12 +175,12 @@ // till the chromoting main page is loaded. PageLoadNotificationObserver observer(chromoting_main); - OpenApplication(AppLaunchParams( - browser()->profile(), - extension_, - is_platform_app() ? extensions::LAUNCH_CONTAINER_NONE : - extensions::LAUNCH_CONTAINER_TAB, - is_platform_app() ? NEW_WINDOW : CURRENT_TAB)); + OpenApplication(AppLaunchParams(browser()->profile(), extension_, + is_platform_app() + ? extensions::LAUNCH_CONTAINER_NONE + : extensions::LAUNCH_CONTAINER_TAB, + is_platform_app() ? NEW_WINDOW : CURRENT_TAB, + extensions::SOURCE_UNTRACKED)); observer.Wait();
diff --git a/chrome/unit_tests.isolate b/chrome/unit_tests.isolate index a78618ae..9894a3c 100644 --- a/chrome/unit_tests.isolate +++ b/chrome/unit_tests.isolate
@@ -69,7 +69,7 @@ '../third_party/pyftpdlib/', '../third_party/pywebsocket/', '../third_party/tlslite/', - '<(PRODUCT_DIR)/pyproto/', + '<(PRODUCT_DIR)/pyproto/google/', '<(PRODUCT_DIR)/test_data/', '<(PRODUCT_DIR)/unit_tests<(EXECUTABLE_SUFFIX)', ],
diff --git a/chromecast/base/metrics/cast_metrics_helper.cc b/chromecast/base/metrics/cast_metrics_helper.cc index e492355..b51439f 100644 --- a/chromecast/base/metrics/cast_metrics_helper.cc +++ b/chromecast/base/metrics/cast_metrics_helper.cc
@@ -70,13 +70,11 @@ } void CastMetricsHelper::LogMediaPlay() { - MAKE_SURE_THREAD(LogMediaPlay); - base::RecordComputedAction(GetMetricsNameWithAppName("MediaPlay", "")); + LogAction(GetMetricsNameWithAppName("MediaPlay", "")); } void CastMetricsHelper::LogMediaPause() { - MAKE_SURE_THREAD(LogMediaPause); - base::RecordComputedAction(GetMetricsNameWithAppName("MediaPause", "")); + LogAction(GetMetricsNameWithAppName("MediaPause", "")); } void CastMetricsHelper::LogTimeToDisplayVideo() { @@ -192,6 +190,16 @@ metrics_sink_ = delegate; } +void CastMetricsHelper::LogAction(const std::string& action) { + MAKE_SURE_THREAD(LogAction, action); + + if (metrics_sink_) { + metrics_sink_->OnAction(action); + } else { + base::RecordComputedAction(action); + } +} + void CastMetricsHelper::LogEnumerationHistogramEvent( const std::string& name, int value, int num_buckets) { MAKE_SURE_THREAD(LogEnumerationHistogramEvent, name, value, num_buckets);
diff --git a/chromecast/base/metrics/cast_metrics_helper.h b/chromecast/base/metrics/cast_metrics_helper.h index 4f06a46e1..22384d5 100644 --- a/chromecast/base/metrics/cast_metrics_helper.h +++ b/chromecast/base/metrics/cast_metrics_helper.h
@@ -32,6 +32,7 @@ public: virtual ~MetricsSink() {} + virtual void OnAction(const std::string& action) = 0; virtual void OnEnumerationEvent(const std::string& name, int value, int num_buckets) = 0; virtual void OnTimeEvent(const std::string& name, @@ -88,6 +89,7 @@ CastMetricsHelper(); private: + void LogAction(const std::string& action); void LogEnumerationHistogramEvent(const std::string& name, int value, int num_buckets); void LogTimeHistogramEvent(const std::string& name,
diff --git a/chromecast/common/chromecast_config.cc b/chromecast/common/chromecast_config.cc index 4b5e6bf8..e9cc611 100644 --- a/chromecast/common/chromecast_config.cc +++ b/chromecast/common/chromecast_config.cc
@@ -49,6 +49,7 @@ DCHECK(g_instance_ == NULL); g_instance_ = new ChromecastConfig(); g_instance_->Load(registry); + g_instance_->OnConfigLoaded(); } // static
diff --git a/chromecast/common/chromecast_config.h b/chromecast/common/chromecast_config.h index 23482c6be..ee31832 100644 --- a/chromecast/common/chromecast_config.h +++ b/chromecast/common/chromecast_config.h
@@ -68,6 +68,9 @@ // Registers any needed preferences for the current platform. void RegisterPlatformPrefs(PrefRegistrySimple* registry); + // Called after the pref config file has been loaded. + void OnConfigLoaded(); + // Global singleton instance. static ChromecastConfig* g_instance_;
diff --git a/chromecast/common/chromecast_config_simple.cc b/chromecast/common/chromecast_config_simple.cc index f62efe52..cc0f34d2 100644 --- a/chromecast/common/chromecast_config_simple.cc +++ b/chromecast/common/chromecast_config_simple.cc
@@ -9,4 +9,7 @@ void ChromecastConfig::RegisterPlatformPrefs(PrefRegistrySimple* registry) { } +void ChromecastConfig::OnConfigLoaded() { +} + } // namespace chromecast
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM index 4250859..faf8d3b 100644 --- a/chromeos/CHROMEOS_LKGM +++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@ -6526.0.0 \ No newline at end of file +6529.0.0 \ No newline at end of file
diff --git a/chromeos/attestation/OWNERS b/chromeos/attestation/OWNERS index 8f05b0f8..d7df737 100644 --- a/chromeos/attestation/OWNERS +++ b/chromeos/attestation/OWNERS
@@ -1,4 +1,3 @@ dkrahn@chromium.org mnissler@chromium.org -pastarmovj@chromium.org bartfab@chromium.org
diff --git a/chromeos/dbus/fake_power_manager_client.cc b/chromeos/dbus/fake_power_manager_client.cc index d0fb18b..bfb5f71 100644 --- a/chromeos/dbus/fake_power_manager_client.cc +++ b/chromeos/dbus/fake_power_manager_client.cc
@@ -38,11 +38,6 @@ return false; } -void FakePowerManagerClient::SetRenderProcessManagerDelegate( - base::WeakPtr<RenderProcessManagerDelegate> delegate) { - render_process_manager_delegate_ = delegate; -} - void FakePowerManagerClient::DecreaseScreenBrightness(bool allow_off) { } @@ -108,14 +103,9 @@ void FakePowerManagerClient::SendSuspendImminent() { FOR_EACH_OBSERVER(Observer, observers_, SuspendImminent()); - if (render_process_manager_delegate_) - render_process_manager_delegate_->SuspendImminent(); } void FakePowerManagerClient::SendSuspendDone() { - if (render_process_manager_delegate_) - render_process_manager_delegate_->SuspendDone(); - FOR_EACH_OBSERVER(Observer, observers_, SuspendDone(base::TimeDelta())); }
diff --git a/chromeos/dbus/fake_power_manager_client.h b/chromeos/dbus/fake_power_manager_client.h index 9b9c6cd99..d840d51 100644 --- a/chromeos/dbus/fake_power_manager_client.h +++ b/chromeos/dbus/fake_power_manager_client.h
@@ -38,8 +38,6 @@ virtual void AddObserver(Observer* observer) override; virtual void RemoveObserver(Observer* observer) override; virtual bool HasObserver(const Observer* observer) const override; - virtual void SetRenderProcessManagerDelegate( - base::WeakPtr<RenderProcessManagerDelegate> delegate) override; virtual void DecreaseScreenBrightness(bool allow_off) override; virtual void IncreaseScreenBrightness() override; virtual void SetScreenBrightnessPercent( @@ -92,9 +90,6 @@ // Last projecting state set in SetIsProjecting(). bool is_projecting_; - // Delegate for managing power consumption of Chrome's renderer processes. - base::WeakPtr<RenderProcessManagerDelegate> render_process_manager_delegate_; - DISALLOW_COPY_AND_ASSIGN(FakePowerManagerClient); };
diff --git a/chromeos/dbus/power_manager_client.cc b/chromeos/dbus/power_manager_client.cc index 52b6909..4192e0d1 100644 --- a/chromeos/dbus/power_manager_client.cc +++ b/chromeos/dbus/power_manager_client.cc
@@ -82,13 +82,6 @@ return observers_.HasObserver(observer); } - virtual void SetRenderProcessManagerDelegate( - base::WeakPtr<RenderProcessManagerDelegate> delegate) override { - DCHECK(!render_process_manager_delegate_) - << "There can be only one! ...RenderProcessManagerDelegate"; - render_process_manager_delegate_ = delegate; - } - virtual void DecreaseScreenBrightness(bool allow_off) override { dbus::MethodCall method_call( power_manager::kPowerManagerInterface, @@ -541,10 +534,6 @@ VLOG(1) << "Got " << power_manager::kSuspendDoneSignal << " signal:" << " suspend_id=" << proto.suspend_id() << " duration=" << duration.InSeconds() << " sec"; - - if (render_process_manager_delegate_) - render_process_manager_delegate_->SuspendDone(); - FOR_EACH_OBSERVER( PowerManagerClient::Observer, observers_, SuspendDone(duration)); base::PowerMonitorDeviceSource::HandleSystemResumed(); @@ -690,9 +679,6 @@ delay_id = suspend_delay_id_; } - if (render_process_manager_delegate_ && !suspending_from_dark_resume_) - render_process_manager_delegate_->SuspendImminent(); - dbus::MethodCall method_call( power_manager::kPowerManagerInterface, method_name); dbus::MessageWriter writer(&method_call); @@ -749,10 +735,6 @@ // Last state passed to SetIsProjecting(). bool last_is_projecting_; - // The delegate used to manage the power consumption of Chrome's renderer - // processes. - base::WeakPtr<RenderProcessManagerDelegate> render_process_manager_delegate_; - // Note: This should remain the last member so it'll be destroyed and // invalidate its weak pointers before any other members are destroyed. base::WeakPtrFactory<PowerManagerClientImpl> weak_ptr_factory_; @@ -802,10 +784,6 @@ return observers_.HasObserver(observer); } - virtual void SetRenderProcessManagerDelegate( - base::WeakPtr<RenderProcessManagerDelegate> delegate) override { - } - virtual void DecreaseScreenBrightness(bool allow_off) override { VLOG(1) << "Requested to descrease screen brightness"; SetBrightness(brightness_ - 5.0, true);
diff --git a/chromeos/dbus/power_manager_client.h b/chromeos/dbus/power_manager_client.h index f79b5ec..b6880027 100644 --- a/chromeos/dbus/power_manager_client.h +++ b/chromeos/dbus/power_manager_client.h
@@ -9,7 +9,6 @@ #include "base/basictypes.h" #include "base/callback.h" -#include "base/memory/weak_ptr.h" #include "base/time/time.h" #include "chromeos/chromeos_export.h" #include "chromeos/dbus/dbus_client.h" @@ -103,27 +102,6 @@ virtual void RemoveObserver(Observer* observer) = 0; virtual bool HasObserver(const Observer* observer) const = 0; - // Interface for managing the power consumption of renderer processes. - class RenderProcessManagerDelegate { - public: - virtual ~RenderProcessManagerDelegate() {} - - // Called when a suspend attempt is imminent but after all registered - // observers have reported readiness to suspend. This is only called for - // suspends from the fully powered on state and not for suspends from dark - // resume. - virtual void SuspendImminent() = 0; - - // Called when a previously announced suspend attempt has completed but - // before observers are notified about it. - virtual void SuspendDone() = 0; - }; - - // Sets the PowerManagerClient's RenderProcessManagerDelegate. There can only - // be one delegate. - virtual void SetRenderProcessManagerDelegate( - base::WeakPtr<RenderProcessManagerDelegate> delegate) = 0; - // Decreases the screen brightness. |allow_off| controls whether or not // it's allowed to turn off the back light. virtual void DecreaseScreenBrightness(bool allow_off) = 0;
diff --git a/chromeos/dbus/services/proxy_resolution_service_provider.cc b/chromeos/dbus/services/proxy_resolution_service_provider.cc index 70be592..749ea08 100644 --- a/chromeos/dbus/services/proxy_resolution_service_provider.cc +++ b/chromeos/dbus/services/proxy_resolution_service_provider.cc
@@ -270,12 +270,6 @@ new ProxyResolverImpl(delegate.Pass())); } -ProxyResolutionServiceProvider* -ProxyResolutionServiceProvider::CreateForTesting( - ProxyResolverInterface* resolver) { - return new ProxyResolutionServiceProvider(resolver); -} - ProxyResolverInterface::~ProxyResolverInterface() { }
diff --git a/chromeos/dbus/services/proxy_resolution_service_provider.h b/chromeos/dbus/services/proxy_resolution_service_provider.h index 1d765ad..daef7b55 100644 --- a/chromeos/dbus/services/proxy_resolution_service_provider.h +++ b/chromeos/dbus/services/proxy_resolution_service_provider.h
@@ -97,11 +97,6 @@ private: explicit ProxyResolutionServiceProvider(ProxyResolverInterface *resovler); - // Creates the instance for testing. Takes the ownership of |resovler| - friend class ProxyResolutionServiceProviderTest; - static ProxyResolutionServiceProvider* CreateForTesting( - ProxyResolverInterface* resolver); - // Called from ExportedObject, when ResolveProxyHandler() is exported as // a D-Bus method, or failed to be exported. void OnExported(const std::string& interface_name,
diff --git a/chromeos/dbus/services/proxy_resolution_service_provider_unittest.cc b/chromeos/dbus/services/proxy_resolution_service_provider_unittest.cc index 5ff871aa..0e55c25 100644 --- a/chromeos/dbus/services/proxy_resolution_service_provider_unittest.cc +++ b/chromeos/dbus/services/proxy_resolution_service_provider_unittest.cc
@@ -1,76 +1,57 @@ // Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// -// This test is relatively complicated. Here's the summary of what it does: -// -// - Set up mock D-Bus related objects to mock out D-Bus calls. -// - Set up a mock proxy resolver to mock out the proxy resolution. -// - Create ProxyResolutionServiceProvider by injecting the mocks -// - Start the service provider. -// - Request ProxyResolutionServiceProvider to resolve proxy for kSourceURL. -// - ProxyResolutionServiceProvider will return the result as a signal. -// - Confirm that we receive the signal and check the contents of the signal. #include "chromeos/dbus/services/proxy_resolution_service_provider.h" #include "base/bind.h" +#include "base/message_loop/message_loop_proxy.h" +#include "base/run_loop.h" #include "chromeos/dbus/services/service_provider_test_helper.h" #include "dbus/message.h" -#include "dbus/mock_exported_object.h" +#include "net/url_request/url_request_test_util.h" #include "third_party/cros_system_api/dbus/service_constants.h" -using ::testing::_; - namespace chromeos { -// We want to know about the proxy info for the URL. -const char kSourceURL[] = "http://www.gmail.com/"; +namespace { // ProxyResolutionServiceProvider will return the proxy info as a D-Bus // signal, to the following signal interface and the signal name. const char kReturnSignalInterface[] = "org.chromium.TestInterface"; const char kReturnSignalName[] = "TestSignal"; -// The returned proxy info. -const char kReturnProxyInfo[] = "PROXY cache.example.com:12345"; +// Test ProxyResolverDelegate implementation. +class TestProxyResolverDelegate : public ProxyResolverDelegate { +public: + explicit TestProxyResolverDelegate( + const scoped_refptr<base::SingleThreadTaskRunner>& network_task_runner) + : request_context_getter_( + new net::TestURLRequestContextGetter(network_task_runner)) {} -// The error message is empty if proxy resolution is successful. -const char kReturnEmptyErrorMessage[] = ""; + ~TestProxyResolverDelegate() override {} -// Mock for ProxyResolverInterface. We'll inject this to -// ProxyResolutionServiceProvider to mock out the proxy resolution. -class MockProxyResolver : public ProxyResolverInterface { - public: - MOCK_METHOD4(ResolveProxy, - void(const std::string& source_url, - const std::string& signal_interface, - const std::string& signal_name, - scoped_refptr<dbus::ExportedObject> exported_object)); + // ProxyResolverDelegate override. + scoped_refptr<net::URLRequestContextGetter> GetRequestContext() override { + return request_context_getter_; + } + + private: + scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_; + + DISALLOW_COPY_AND_ASSIGN(TestProxyResolverDelegate); }; +} // namespace + class ProxyResolutionServiceProviderTest : public testing::Test { public: - ProxyResolutionServiceProviderTest() - : signal_received_successfully_(false) { - } - - virtual void SetUp() override { - // Create a mock proxy resolver. Will be owned by - // |proxy_resolution_service|. - MockProxyResolver* mock_resolver = new MockProxyResolver; - // |mock_resolver_|'s ResolveProxy() will use MockResolveProxy(). - EXPECT_CALL(*mock_resolver, - ResolveProxy(kSourceURL, kReturnSignalInterface, - kReturnSignalName, _)) - .WillOnce(Invoke( - this, - &ProxyResolutionServiceProviderTest::MockResolveProxy)); - + void SetUp() override { // Create the proxy resolution service with the mock bus and the mock // resolver injected. - service_provider_.reset( - ProxyResolutionServiceProvider::CreateForTesting(mock_resolver)); + service_provider_.reset(ProxyResolutionServiceProvider::Create( + make_scoped_ptr(new TestProxyResolverDelegate( + base::MessageLoopProxy::current())))); test_helper_.SetUp(kResolveNetworkProxy, service_provider_.get()); @@ -86,7 +67,7 @@ base::Unretained(this))); } - virtual void TearDown() override { + void TearDown() override { test_helper_.TearDown(); service_provider_.reset(); } @@ -94,67 +75,35 @@ protected: // Called when a signal is received. void OnSignalReceived(dbus::Signal* signal) { - ASSERT_EQ(kReturnSignalInterface, signal->GetInterface()); - ASSERT_EQ(kReturnSignalName, signal->GetMember()); - - std::string source_url; - std::string proxy_info; - std::string error_message; + EXPECT_EQ(kReturnSignalInterface, signal->GetInterface()); + EXPECT_EQ(kReturnSignalName, signal->GetMember()); // The signal should contain three strings. dbus::MessageReader reader(signal); - ASSERT_TRUE(reader.PopString(&source_url)); - ASSERT_TRUE(reader.PopString(&proxy_info)); - ASSERT_TRUE(reader.PopString(&error_message)); - - // Check the signal contents. - EXPECT_EQ(kSourceURL, source_url); - EXPECT_EQ(kReturnProxyInfo, proxy_info); - EXPECT_EQ(kReturnEmptyErrorMessage, error_message); - - // Mark that the signal is received successfully. - signal_received_successfully_ = true; + EXPECT_TRUE(reader.PopString(&source_url_)); + EXPECT_TRUE(reader.PopString(&proxy_info_)); + EXPECT_TRUE(reader.PopString(&error_message_)); } // Called when connected to a signal. void OnConnectedToSignal(const std::string& signal_interface, const std::string& signal_name, bool success){ - ASSERT_EQ(kReturnSignalInterface, signal_interface); - ASSERT_EQ(kReturnSignalName, signal_name); + EXPECT_EQ(kReturnSignalInterface, signal_interface); + EXPECT_EQ(kReturnSignalName, signal_name); - ASSERT_TRUE(success); + EXPECT_TRUE(success); } - // Behaves as |mock_resolver_|'s ResolveProxy(). - void MockResolveProxy(const std::string& source_url, - const std::string& signal_interface, - const std::string& signal_name, - scoped_refptr<dbus::ExportedObject> exported_object) { - if (source_url == kSourceURL) { - dbus::Signal signal(signal_interface, - signal_name); - dbus::MessageWriter writer(&signal); - writer.AppendString(kSourceURL); - writer.AppendString(kReturnProxyInfo); - writer.AppendString(kReturnEmptyErrorMessage); - // Send the signal back to the requested signal interface and the - // signal name. - exported_object->SendSignal(&signal); - return; - } - - LOG(ERROR) << "Unexpected source URL: " << source_url; - } - - bool signal_received_successfully_; + std::string source_url_; + std::string proxy_info_; + std::string error_message_; ServiceProviderTestHelper test_helper_; scoped_ptr<CrosDBusService::ServiceProviderInterface> service_provider_; }; TEST_F(ProxyResolutionServiceProviderTest, ResolveProxy) { - // The signal is not yet received. - ASSERT_FALSE(signal_received_successfully_); + const char kSourceURL[] = "http://www.gmail.com/"; // Create a method call to resolve proxy config for kSourceURL. dbus::MethodCall method_call(kLibCrosServiceInterface, kResolveNetworkProxy); @@ -165,15 +114,17 @@ // Call the ResolveNetworkProxy method. scoped_ptr<dbus::Response> response(test_helper_.CallMethod(&method_call)); + base::RunLoop().RunUntilIdle(); // An empty response should be returned. ASSERT_TRUE(response.get()); dbus::MessageReader reader(response.get()); - ASSERT_FALSE(reader.HasMoreData()); + EXPECT_FALSE(reader.HasMoreData()); // Confirm that the signal is received successfully. - // The contents of the signal are checked in OnSignalReceived(). - ASSERT_TRUE(signal_received_successfully_); + EXPECT_EQ(kSourceURL, source_url_); + EXPECT_EQ("DIRECT", proxy_info_); + EXPECT_EQ("", error_message_); } } // namespace chromeos
diff --git a/chromeos/network/network_change_notifier_chromeos.cc b/chromeos/network/network_change_notifier_chromeos.cc index bde8997..39a37d55 100644 --- a/chromeos/network/network_change_notifier_chromeos.cc +++ b/chromeos/network/network_change_notifier_chromeos.cc
@@ -52,7 +52,9 @@ NetworkChangeNotifierChromeos::NetworkChangeNotifierChromeos() : NetworkChangeNotifier(NetworkChangeCalculatorParamsChromeos()), - connection_type_(CONNECTION_NONE) { + connection_type_(CONNECTION_NONE), + poll_callback_(base::Bind(&NetworkChangeNotifierChromeos::PollForState, + base::Unretained(this))) { } NetworkChangeNotifierChromeos::~NetworkChangeNotifierChromeos() { @@ -66,6 +68,10 @@ dns_config_service_->WatchConfig( base::Bind(net::NetworkChangeNotifier::SetDnsConfig)); + PollForState(); +} + +void NetworkChangeNotifierChromeos::PollForState() { // Update initial connection state. DefaultNetworkChanged( NetworkHandler::Get()->network_state_handler()->DefaultNetwork()); @@ -80,6 +86,13 @@ net::NetworkChangeNotifier::ConnectionType NetworkChangeNotifierChromeos::GetCurrentConnectionType() const { + // Re-evaluate connection state if we are offline since there is little + // cost to doing so. Since we are in the context of a const method, + // this is done through a closure that holds a non-const reference to + // |this|, to allow PollForState() to modify our cached state. + // TODO(gauravsh): Figure out why we would have missed this notification. + if (connection_type_ == CONNECTION_NONE) + poll_callback_.Run(); return connection_type_; } @@ -117,8 +130,7 @@ *dns_changed = false; if (!default_network || !default_network->IsConnectedState()) { // If we lost a default network, we must update our state and notify - // observers, otherwise we have nothing to do. (Under normal circumstances, - // we should never get duplicate no default network notifications). + // observers, otherwise we have nothing to do. if (connection_type_ != CONNECTION_NONE) { NET_LOG_EVENT("NCNDefaultNetworkLost", service_path_); *ip_address_changed = true;
diff --git a/chromeos/network/network_change_notifier_chromeos.h b/chromeos/network/network_change_notifier_chromeos.h index 8d07a97..a2ad6955 100644 --- a/chromeos/network/network_change_notifier_chromeos.h +++ b/chromeos/network/network_change_notifier_chromeos.h
@@ -8,6 +8,7 @@ #include <string> #include "base/basictypes.h" +#include "base/callback.h" #include "base/gtest_prod_util.h" #include "base/memory/scoped_ptr.h" #include "chromeos/chromeos_export.h" @@ -59,6 +60,10 @@ bool* ip_address_changed, bool* dns_changed); + // Proactively retrieves current network state from the network + // state handler and calls UpdateState with the result. + void PollForState(); + // Maps the shill network type and technology to its NetworkChangeNotifier // equivalent. static net::NetworkChangeNotifier::ConnectionType @@ -77,6 +82,8 @@ std::vector<std::string> dns_servers_; // Service path for the current default network. std::string service_path_; + // Callback for refreshing network state. + base::Closure poll_callback_; scoped_ptr<DnsConfigService> dns_config_service_;
diff --git a/chromeos/network/onc/onc_translation_tables.cc b/chromeos/network/onc/onc_translation_tables.cc index d02c922..5124c02 100644 --- a/chromeos/network/onc/onc_translation_tables.cc +++ b/chromeos/network/onc/onc_translation_tables.cc
@@ -284,7 +284,9 @@ const StringTranslationEntry kVPNTypeTable[] = { { ::onc::vpn::kTypeL2TP_IPsec, shill::kProviderL2tpIpsec}, - { ::onc::vpn::kOpenVPN, shill::kProviderOpenVpn}, {NULL}}; + { ::onc::vpn::kOpenVPN, shill::kProviderOpenVpn}, + { ::onc::vpn::kThirdPartyVpn, shill::kProviderThirdPartyVpn}, + {NULL}}; // The first matching line is chosen. const StringTranslationEntry kWiFiSecurityTable[] = {
diff --git a/chromeos/network/onc/onc_translator_shill_to_onc.cc b/chromeos/network/onc/onc_translator_shill_to_onc.cc index fb5fcdd2..1daf4a7c 100644 --- a/chromeos/network/onc/onc_translator_shill_to_onc.cc +++ b/chromeos/network/onc/onc_translator_shill_to_onc.cc
@@ -298,7 +298,7 @@ TranslateAndAddNestedObject(::onc::vpn::kIPsec, *provider); TranslateAndAddNestedObject(::onc::vpn::kL2TP, *provider); provider_type_dictionary = ::onc::vpn::kIPsec; - } else { + } else if (onc_provider_type != ::onc::vpn::kThirdPartyVpn) { TranslateAndAddNestedObject(onc_provider_type, *provider); provider_type_dictionary = onc_provider_type; }
diff --git a/chromeos/tpm_token_info_getter.h b/chromeos/tpm_token_info_getter.h index dd3d510..93fee11d 100644 --- a/chromeos/tpm_token_info_getter.h +++ b/chromeos/tpm_token_info_getter.h
@@ -25,6 +25,8 @@ namespace chromeos { // Information retrieved from cryptohome by TPMTokenInfoGetter. +// For invalid token |token_name| and |user_pin| will be empty, while +// |token_slot_id| will be set to -1. struct TPMTokenInfo { // Default constructor creates token info for disabled TPM. TPMTokenInfo();
diff --git a/components/OWNERS b/components/OWNERS index 70df4f6..a03b39b 100644 --- a/components/OWNERS +++ b/components/OWNERS
@@ -156,8 +156,6 @@ per-file precache*=sclittle@chromium.org per-file policy*=mnissler@chromium.org -per-file policy*=pastarmovj@chromium.org -per-file policy*=joaodasilva@chromium.org per-file policy*=bartfab@chromium.org per-file policy*=atwilson@chromium.org per-file policy*=pneubeck@chromium.org
diff --git a/components/autofill.gypi b/components/autofill.gypi index c67abc58..ccaddc4 100644 --- a/components/autofill.gypi +++ b/components/autofill.gypi
@@ -361,6 +361,8 @@ 'sources': [ 'autofill/content/browser/content_autofill_driver.cc', 'autofill/content/browser/content_autofill_driver.h', + 'autofill/content/browser/content_autofill_driver_factory.cc', + 'autofill/content/browser/content_autofill_driver_factory.h', 'autofill/content/browser/request_autocomplete_manager.cc', 'autofill/content/browser/request_autocomplete_manager.h', 'autofill/content/browser/risk/fingerprint.cc',
diff --git a/components/autofill/content/browser/BUILD.gn b/components/autofill/content/browser/BUILD.gn index 9cdcf68b..56d3bf0 100644 --- a/components/autofill/content/browser/BUILD.gn +++ b/components/autofill/content/browser/BUILD.gn
@@ -9,6 +9,8 @@ sources = [ "content_autofill_driver.cc", "content_autofill_driver.h", + "content_autofill_driver_factory.cc", + "content_autofill_driver_factory.h", "request_autocomplete_manager.cc", "request_autocomplete_manager.h", "risk/fingerprint.cc",
diff --git a/components/autofill/content/browser/content_autofill_driver.cc b/components/autofill/content/browser/content_autofill_driver.cc index a3bba0f..d6ecdd3f 100644 --- a/components/autofill/content/browser/content_autofill_driver.cc +++ b/components/autofill/content/browser/content_autofill_driver.cc
@@ -16,48 +16,20 @@ #include "content/public/browser/browser_thread.h" #include "content/public/browser/navigation_controller.h" #include "content/public/browser/navigation_details.h" +#include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_view_host.h" -#include "content/public/browser/web_contents.h" -#include "content/public/common/frame_navigate_params.h" +#include "content/public/browser/site_instance.h" #include "ipc/ipc_message_macros.h" namespace autofill { -namespace { - -const char kContentAutofillDriverWebContentsUserDataKey[] = - "web_contents_autofill_driver_impl"; - -} // namespace - -// static -void ContentAutofillDriver::CreateForWebContentsAndDelegate( - content::WebContents* contents, - AutofillClient* client, - const std::string& app_locale, - AutofillManager::AutofillDownloadManagerState enable_download_manager) { - if (FromWebContents(contents)) - return; - - contents->SetUserData( - kContentAutofillDriverWebContentsUserDataKey, - new ContentAutofillDriver( - contents, client, app_locale, enable_download_manager)); -} - -// static -ContentAutofillDriver* ContentAutofillDriver::FromWebContents( - content::WebContents* contents) { - return static_cast<ContentAutofillDriver*>( - contents->GetUserData(kContentAutofillDriverWebContentsUserDataKey)); -} - ContentAutofillDriver::ContentAutofillDriver( - content::WebContents* web_contents, + content::RenderFrameHost* render_frame_host, AutofillClient* client, const std::string& app_locale, AutofillManager::AutofillDownloadManagerState enable_download_manager) - : content::WebContentsObserver(web_contents), + : render_frame_host_(render_frame_host), + client_(client), autofill_manager_(new AutofillManager(this, client, app_locale, @@ -70,11 +42,15 @@ ContentAutofillDriver::~ContentAutofillDriver() {} bool ContentAutofillDriver::IsOffTheRecord() const { - return web_contents()->GetBrowserContext()->IsOffTheRecord(); + return render_frame_host_->GetSiteInstance() + ->GetBrowserContext() + ->IsOffTheRecord(); } net::URLRequestContextGetter* ContentAutofillDriver::GetURLRequestContext() { - return web_contents()->GetBrowserContext()->GetRequestContext(); + return render_frame_host_->GetSiteInstance() + ->GetBrowserContext() + ->GetRequestContext(); } base::SequencedWorkerPool* ContentAutofillDriver::GetBlockingPool() { @@ -82,7 +58,7 @@ } bool ContentAutofillDriver::RendererIsAvailable() { - return (web_contents()->GetRenderViewHost() != NULL); + return render_frame_host_->GetRenderViewHost() != NULL; } void ContentAutofillDriver::SendFormDataToRenderer( @@ -91,15 +67,14 @@ const FormData& data) { if (!RendererIsAvailable()) return; - content::RenderViewHost* host = web_contents()->GetRenderViewHost(); switch (action) { case FORM_DATA_ACTION_FILL: - host->Send( - new AutofillMsg_FillForm(host->GetRoutingID(), query_id, data)); + render_frame_host_->Send(new AutofillMsg_FillForm( + render_frame_host_->GetRoutingID(), query_id, data)); break; case FORM_DATA_ACTION_PREVIEW: - host->Send( - new AutofillMsg_PreviewForm(host->GetRoutingID(), query_id, data)); + render_frame_host_->Send(new AutofillMsg_PreviewForm( + render_frame_host_->GetRoutingID(), query_id, data)); break; } } @@ -107,8 +82,14 @@ void ContentAutofillDriver::PingRenderer() { if (!RendererIsAvailable()) return; - content::RenderViewHost* host = web_contents()->GetRenderViewHost(); - host->Send(new AutofillMsg_Ping(host->GetRoutingID())); + render_frame_host_->Send( + new AutofillMsg_Ping(render_frame_host_->GetRoutingID())); +} + +void ContentAutofillDriver::DetectAccountCreationForms( + const std::vector<FormStructure*>& forms) { + autofill_manager_->client()->DetectAccountCreationForms(render_frame_host_, + forms); } void ContentAutofillDriver::SendAutofillTypePredictionsToRenderer( @@ -119,56 +100,56 @@ if (!RendererIsAvailable()) return; - content::RenderViewHost* host = web_contents()->GetRenderViewHost(); std::vector<FormDataPredictions> type_predictions; FormStructure::GetFieldTypePredictions(forms, &type_predictions); - host->Send(new AutofillMsg_FieldTypePredictionsAvailable(host->GetRoutingID(), - type_predictions)); + render_frame_host_->Send(new AutofillMsg_FieldTypePredictionsAvailable( + render_frame_host_->GetRoutingID(), type_predictions)); } void ContentAutofillDriver::RendererShouldAcceptDataListSuggestion( const base::string16& value) { if (!RendererIsAvailable()) return; - content::RenderViewHost* host = web_contents()->GetRenderViewHost(); - host->Send( - new AutofillMsg_AcceptDataListSuggestion(host->GetRoutingID(), value)); + render_frame_host_->Send(new AutofillMsg_AcceptDataListSuggestion( + render_frame_host_->GetRoutingID(), value)); } void ContentAutofillDriver::RendererShouldClearFilledForm() { if (!RendererIsAvailable()) return; - content::RenderViewHost* host = web_contents()->GetRenderViewHost(); - host->Send(new AutofillMsg_ClearForm(host->GetRoutingID())); + render_frame_host_->Send( + new AutofillMsg_ClearForm(render_frame_host_->GetRoutingID())); } void ContentAutofillDriver::RendererShouldClearPreviewedForm() { if (!RendererIsAvailable()) return; - content::RenderViewHost* host = web_contents()->GetRenderViewHost(); - host->Send(new AutofillMsg_ClearPreviewedForm(host->GetRoutingID())); + render_frame_host_->Send( + new AutofillMsg_ClearPreviewedForm(render_frame_host_->GetRoutingID())); } void ContentAutofillDriver::RendererShouldFillFieldWithValue( const base::string16& value) { if (!RendererIsAvailable()) return; - content::RenderViewHost* host = web_contents()->GetRenderViewHost(); - host->Send(new AutofillMsg_FillFieldWithValue(host->GetRoutingID(), value)); + render_frame_host_->Send(new AutofillMsg_FillFieldWithValue( + render_frame_host_->GetRoutingID(), value)); } + void ContentAutofillDriver::RendererShouldPreviewFieldWithValue( const base::string16& value) { if (!RendererIsAvailable()) return; - content::RenderViewHost* host = web_contents()->GetRenderViewHost(); - host->Send(new AutofillMsg_PreviewFieldWithValue(host->GetRoutingID(), - value)); + render_frame_host_->Send(new AutofillMsg_PreviewFieldWithValue( + render_frame_host_->GetRoutingID(), value)); } -bool ContentAutofillDriver::OnMessageReceived(const IPC::Message& message) { +bool ContentAutofillDriver::HandleMessage(const IPC::Message& message) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(ContentAutofillDriver, message) + IPC_MESSAGE_FORWARD(AutofillHostMsg_FirstUserGestureObserved, client_, + AutofillClient::OnFirstUserGestureObserved) IPC_MESSAGE_FORWARD(AutofillHostMsg_FormsSeen, autofill_manager_.get(), AutofillManager::OnFormsSeen) @@ -210,7 +191,7 @@ return handled; } -void ContentAutofillDriver::DidNavigateMainFrame( +void ContentAutofillDriver::DidNavigateFrame( const content::LoadCommittedDetails& details, const content::FrameNavigateParams& params) { if (details.is_navigation_to_different_page()) @@ -223,13 +204,4 @@ autofill_manager_->SetExternalDelegate(&autofill_external_delegate_); } -void ContentAutofillDriver::NavigationEntryCommitted( - const content::LoadCommittedDetails& load_details) { - autofill_manager_->client()->HideAutofillPopup(); -} - -void ContentAutofillDriver::WasHidden() { - autofill_manager_->client()->HideAutofillPopup(); -} - } // namespace autofill
diff --git a/components/autofill/content/browser/content_autofill_driver.h b/components/autofill/content/browser/content_autofill_driver.h index 8247c1d..cb35d81 100644 --- a/components/autofill/content/browser/content_autofill_driver.h +++ b/components/autofill/content/browser/content_autofill_driver.h
@@ -13,10 +13,12 @@ #include "components/autofill/core/browser/autofill_driver.h" #include "components/autofill/core/browser/autofill_external_delegate.h" #include "components/autofill/core/browser/autofill_manager.h" -#include "content/public/browser/web_contents_observer.h" namespace content { -class WebContents; +class BrowserContext; +class RenderFrameHost; +struct FrameNavigateParams; +struct LoadCommittedDetails; } namespace IPC { @@ -29,17 +31,15 @@ // Class that drives autofill flow in the browser process based on // communication from the renderer and from the external world. There is one -// instance per WebContents. -class ContentAutofillDriver : public AutofillDriver, - public content::WebContentsObserver, - public base::SupportsUserData::Data { +// instance per RenderFrameHost. +class ContentAutofillDriver : public AutofillDriver { public: - static void CreateForWebContentsAndDelegate( - content::WebContents* contents, + ContentAutofillDriver( + content::RenderFrameHost* render_frame_host, AutofillClient* client, const std::string& app_locale, AutofillManager::AutofillDownloadManagerState enable_download_manager); - static ContentAutofillDriver* FromWebContents(content::WebContents* contents); + ~ContentAutofillDriver() override; // AutofillDriver: bool IsOffTheRecord() const override; @@ -50,6 +50,8 @@ RendererFormDataAction action, const FormData& data) override; void PingRenderer() override; + void DetectAccountCreationForms( + const std::vector<autofill::FormStructure*>& forms) override; void SendAutofillTypePredictionsToRenderer( const std::vector<FormStructure*>& forms) override; void RendererShouldAcceptDataListSuggestion( @@ -60,34 +62,33 @@ void RendererShouldPreviewFieldWithValue( const base::string16& value) override; + // Handles a message that came from the associated render frame. + bool HandleMessage(const IPC::Message& message); + + // Called when the frame has navigated. + void DidNavigateFrame(const content::LoadCommittedDetails& details, + const content::FrameNavigateParams& params); + AutofillExternalDelegate* autofill_external_delegate() { return &autofill_external_delegate_; } AutofillManager* autofill_manager() { return autofill_manager_.get(); } + content::RenderFrameHost* render_frame_host() { return render_frame_host_; } protected: - ContentAutofillDriver( - content::WebContents* web_contents, - AutofillClient* client, - const std::string& app_locale, - AutofillManager::AutofillDownloadManagerState enable_download_manager); - ~ContentAutofillDriver() override; - - // content::WebContentsObserver: - void DidNavigateMainFrame( - const content::LoadCommittedDetails& details, - const content::FrameNavigateParams& params) override; - void NavigationEntryCommitted( - const content::LoadCommittedDetails& load_details) override; - void WasHidden() override; - bool OnMessageReceived(const IPC::Message& message) override; - // Sets the manager to |manager| and sets |manager|'s external delegate // to |autofill_external_delegate_|. Takes ownership of |manager|. void SetAutofillManager(scoped_ptr<AutofillManager> manager); private: + // Weak ref to the RenderFrameHost the driver is associated with. Should + // always be non-NULL and valid for lifetime of |this|. + content::RenderFrameHost* const render_frame_host_; + + // The per-tab client. + AutofillClient* client_; + // AutofillManager instance via which this object drives the shared Autofill // code. scoped_ptr<AutofillManager> autofill_manager_;
diff --git a/components/autofill/content/browser/content_autofill_driver_factory.cc b/components/autofill/content/browser/content_autofill_driver_factory.cc new file mode 100644 index 0000000..aec0d9cb --- /dev/null +++ b/components/autofill/content/browser/content_autofill_driver_factory.cc
@@ -0,0 +1,113 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill/content/browser/content_autofill_driver_factory.h" + +#include "base/bind.h" +#include "base/stl_util.h" +#include "components/autofill/content/browser/content_autofill_driver.h" +#include "components/autofill/core/browser/autofill_client.h" +#include "components/autofill/core/browser/autofill_manager.h" +#include "components/autofill/core/browser/form_structure.h" +#include "components/autofill/core/common/autofill_switches.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/web_contents.h" +#include "ipc/ipc_message_macros.h" + +namespace autofill { + +const char ContentAutofillDriverFactory:: + kContentAutofillDriverFactoryWebContentsUserDataKey[] = + "web_contents_autofill_driver_factory"; + +// static +void ContentAutofillDriverFactory::CreateForWebContentsAndDelegate( + content::WebContents* contents, + AutofillClient* client, + const std::string& app_locale, + AutofillManager::AutofillDownloadManagerState enable_download_manager) { + if (FromWebContents(contents)) + return; + + contents->SetUserData( + kContentAutofillDriverFactoryWebContentsUserDataKey, + new ContentAutofillDriverFactory(contents, client, app_locale, + enable_download_manager)); +} + +// static +ContentAutofillDriverFactory* ContentAutofillDriverFactory::FromWebContents( + content::WebContents* contents) { + return static_cast<ContentAutofillDriverFactory*>(contents->GetUserData( + kContentAutofillDriverFactoryWebContentsUserDataKey)); +} + +ContentAutofillDriverFactory::ContentAutofillDriverFactory( + content::WebContents* web_contents, + AutofillClient* client, + const std::string& app_locale, + AutofillManager::AutofillDownloadManagerState enable_download_manager) + : content::WebContentsObserver(web_contents), + client_(client), + app_locale_(app_locale), + enable_download_manager_(enable_download_manager) { + web_contents->ForEachFrame( + base::Bind(&ContentAutofillDriverFactory::CreateDriverForFrame, + base::Unretained(this))); +} + +ContentAutofillDriverFactory::~ContentAutofillDriverFactory() { + STLDeleteContainerPairSecondPointers(frame_driver_map_.begin(), + frame_driver_map_.end()); + frame_driver_map_.clear(); +} + +ContentAutofillDriver* ContentAutofillDriverFactory::DriverForFrame( + content::RenderFrameHost* render_frame_host) { + return frame_driver_map_[render_frame_host]; +} + +bool ContentAutofillDriverFactory::OnMessageReceived( + const IPC::Message& message, + content::RenderFrameHost* render_frame_host) { + return frame_driver_map_[render_frame_host]->HandleMessage(message); +} + +void ContentAutofillDriverFactory::RenderFrameCreated( + content::RenderFrameHost* render_frame_host) { + // The driver for the main frame has already been created. + if (!frame_driver_map_[render_frame_host]) + CreateDriverForFrame(render_frame_host); +} + +void ContentAutofillDriverFactory::RenderFrameDeleted( + content::RenderFrameHost* render_frame_host) { + delete frame_driver_map_[render_frame_host]; + frame_driver_map_.erase(render_frame_host); +} + +void ContentAutofillDriverFactory::DidNavigateAnyFrame( + content::RenderFrameHost* render_frame_host, + const content::LoadCommittedDetails& details, + const content::FrameNavigateParams& params) { + frame_driver_map_[render_frame_host]->DidNavigateFrame(details, params); +} + +void ContentAutofillDriverFactory::NavigationEntryCommitted( + const content::LoadCommittedDetails& load_details) { + client_->HideAutofillPopup(); +} + +void ContentAutofillDriverFactory::WasHidden() { + client_->HideAutofillPopup(); +} + +void ContentAutofillDriverFactory::CreateDriverForFrame( + content::RenderFrameHost* render_frame_host) { + DCHECK(!frame_driver_map_[render_frame_host]); + frame_driver_map_[render_frame_host] = new ContentAutofillDriver( + render_frame_host, client_, app_locale_, enable_download_manager_); +} + +} // namespace autofill
diff --git a/components/autofill/content/browser/content_autofill_driver_factory.h b/components/autofill/content/browser/content_autofill_driver_factory.h new file mode 100644 index 0000000..02fa868 --- /dev/null +++ b/components/autofill/content/browser/content_autofill_driver_factory.h
@@ -0,0 +1,81 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_AUTOFILL_CONTENT_BROWSER_CONTENT_AUTOFILL_DRIVER_FACTORY_H_ +#define COMPONENTS_AUTOFILL_CONTENT_BROWSER_CONTENT_AUTOFILL_DRIVER_FACTORY_H_ + +#include <string> + +#include "base/memory/scoped_ptr.h" +#include "base/supports_user_data.h" +#include "components/autofill/content/browser/request_autocomplete_manager.h" +#include "components/autofill/core/browser/autofill_manager.h" +#include "content/public/browser/web_contents_observer.h" + +namespace content { +class RenderFrameHost; +} + +namespace IPC { +class Message; +} + +namespace autofill { + +class AutofillDriver; +class ContentAutofillDriver; + +// Manages lifetime of ContentAutofillDriver. One Factory per WebContents +// creates one Driver per RenderFrame. +class ContentAutofillDriverFactory : public content::WebContentsObserver, + public base::SupportsUserData::Data { + public: + static void CreateForWebContentsAndDelegate( + content::WebContents* contents, + AutofillClient* client, + const std::string& app_locale, + AutofillManager::AutofillDownloadManagerState enable_download_manager); + static ContentAutofillDriverFactory* FromWebContents( + content::WebContents* contents); + + // Gets the |ContentAutofillDriver| associated with |render_frame_host|. + // |render_frame_host| must be owned by |web_contents()|. + ContentAutofillDriver* DriverForFrame( + content::RenderFrameHost* render_frame_host); + + // content::WebContentsObserver: + bool OnMessageReceived(const IPC::Message& message, + content::RenderFrameHost* render_frame_host) override; + void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override; + void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override; + void DidNavigateAnyFrame(content::RenderFrameHost* render_frame_host, + const content::LoadCommittedDetails& details, + const content::FrameNavigateParams& params) override; + void NavigationEntryCommitted( + const content::LoadCommittedDetails& load_details) override; + void WasHidden() override; + + static const char kContentAutofillDriverFactoryWebContentsUserDataKey[]; + + protected: + ContentAutofillDriverFactory( + content::WebContents* web_contents, + AutofillClient* client, + const std::string& app_locale, + AutofillManager::AutofillDownloadManagerState enable_download_manager); + ~ContentAutofillDriverFactory() override; + + private: + void CreateDriverForFrame(content::RenderFrameHost* render_frame_host); + + AutofillClient* client_; + std::string app_locale_; + AutofillManager::AutofillDownloadManagerState enable_download_manager_; + + std::map<content::RenderFrameHost*, ContentAutofillDriver*> frame_driver_map_; +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CONTENT_BROWSER_CONTENT_AUTOFILL_DRIVER_FACTORY_H_
diff --git a/components/autofill/content/browser/content_autofill_driver_unittest.cc b/components/autofill/content/browser/content_autofill_driver_unittest.cc index 6481cfd..76fbf7c2 100644 --- a/components/autofill/content/browser/content_autofill_driver_unittest.cc +++ b/components/autofill/content/browser/content_autofill_driver_unittest.cc
@@ -47,9 +47,9 @@ class TestContentAutofillDriver : public ContentAutofillDriver { public: - TestContentAutofillDriver(content::WebContents* contents, + TestContentAutofillDriver(content::RenderFrameHost* rfh, AutofillClient* client) - : ContentAutofillDriver(contents, client, kAppLocale, kDownloadState) { + : ContentAutofillDriver(rfh, client, kAppLocale, kDownloadState) { scoped_ptr<AutofillManager> autofill_manager( new MockAutofillManager(this, client)); SetAutofillManager(autofill_manager.Pass()); @@ -60,7 +60,7 @@ return static_cast<MockAutofillManager*>(autofill_manager()); } - using ContentAutofillDriver::DidNavigateMainFrame; + using ContentAutofillDriver::DidNavigateFrame; }; class ContentAutofillDriverTest : public content::RenderViewHostTestHarness { @@ -69,7 +69,7 @@ content::RenderViewHostTestHarness::SetUp(); test_autofill_client_.reset(new TestAutofillClient()); - driver_.reset(new TestContentAutofillDriver(web_contents(), + driver_.reset(new TestContentAutofillDriver(web_contents()->GetMainFrame(), test_autofill_client_.get())); } @@ -210,7 +210,7 @@ details.is_in_page = false; ASSERT_TRUE(details.is_navigation_to_different_page()); content::FrameNavigateParams params = content::FrameNavigateParams(); - driver_->DidNavigateMainFrame(details, params); + driver_->DidNavigateFrame(details, params); } TEST_F(ContentAutofillDriverTest, NavigatedWithinSamePage) { @@ -219,7 +219,7 @@ details.is_main_frame = false; ASSERT_TRUE(!details.is_navigation_to_different_page()); content::FrameNavigateParams params = content::FrameNavigateParams(); - driver_->DidNavigateMainFrame(details, params); + driver_->DidNavigateFrame(details, params); } TEST_F(ContentAutofillDriverTest, FormDataSentToRenderer_FillForm) {
diff --git a/components/autofill/content/browser/request_autocomplete_manager.cc b/components/autofill/content/browser/request_autocomplete_manager.cc index 89c08bf78..df2d095 100644 --- a/components/autofill/content/browser/request_autocomplete_manager.cc +++ b/components/autofill/content/browser/request_autocomplete_manager.cc
@@ -9,7 +9,7 @@ #include "components/autofill/core/browser/form_structure.h" #include "components/autofill/core/common/autofill_data_validation.h" #include "components/autofill/core/common/form_data.h" -#include "content/public/browser/render_view_host.h" +#include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" #include "third_party/WebKit/public/web/WebFormElement.h" #include "url/gurl.h" @@ -66,13 +66,7 @@ AutofillClient::RequestAutocompleteResult result, const base::string16& debug_message, const FormStructure* form_structure) { - // autofill_driver_->web_contents() will be NULL when the interactive - // autocomplete is closed due to a tab or browser window closing. - if (!autofill_driver_->web_contents()) - return; - - content::RenderViewHost* host = - autofill_driver_->web_contents()->GetRenderViewHost(); + content::RenderFrameHost* host = autofill_driver_->render_frame_host(); if (!host) return;
diff --git a/components/autofill/content/browser/request_autocomplete_manager_unittest.cc b/components/autofill/content/browser/request_autocomplete_manager_unittest.cc index c2de017..193411d 100644 --- a/components/autofill/content/browser/request_autocomplete_manager_unittest.cc +++ b/components/autofill/content/browser/request_autocomplete_manager_unittest.cc
@@ -6,6 +6,7 @@ #include "components/autofill/content/browser/request_autocomplete_manager.h" #include "components/autofill/content/common/autofill_messages.h" #include "components/autofill/core/browser/test_autofill_client.h" +#include "content/public/browser/web_contents.h" #include "content/public/test/mock_render_process_host.h" #include "content/public/test/test_renderer_host.h" #include "testing/gtest/include/gtest/gtest.h" @@ -71,9 +72,9 @@ class TestContentAutofillDriver : public ContentAutofillDriver { public: - TestContentAutofillDriver(content::WebContents* contents, + TestContentAutofillDriver(content::RenderFrameHost* rfh, AutofillClient* client) - : ContentAutofillDriver(contents, client, kAppLocale, kDownloadState) { + : ContentAutofillDriver(rfh, client, kAppLocale, kDownloadState) { SetAutofillManager(make_scoped_ptr<AutofillManager>( new TestAutofillManager(this, client))); } @@ -83,8 +84,6 @@ return static_cast<TestAutofillManager*>(autofill_manager()); } - using ContentAutofillDriver::DidNavigateMainFrame; - DISALLOW_COPY_AND_ASSIGN(TestContentAutofillDriver); }; @@ -98,8 +97,8 @@ void SetUp() override { content::RenderViewHostTestHarness::SetUp(); - driver_.reset( - new TestContentAutofillDriver(web_contents(), &autofill_client_)); + driver_.reset(new TestContentAutofillDriver(web_contents()->GetMainFrame(), + &autofill_client_)); request_autocomplete_manager_.reset( new RequestAutocompleteManager(driver_.get())); }
diff --git a/components/autofill/content/common/autofill_messages.h b/components/autofill/content/common/autofill_messages.h index cd5cd1e..916d99b5 100644 --- a/components/autofill/content/common/autofill_messages.h +++ b/components/autofill/content/common/autofill_messages.h
@@ -100,6 +100,10 @@ // Autofill messages sent from the browser to the renderer. +// Tells the render frame that a user gesture was observed somewhere in the tab +// (including in a different frame). +IPC_MESSAGE_ROUTED0(AutofillMsg_FirstUserGestureObservedInTab) + // Instructs the renderer to immediately return an IPC acknowledging the ping. // This is used to correctly sequence events, since IPCs are guaranteed to be // processed in order. @@ -192,6 +196,9 @@ // TODO(creis): check in the browser that the renderer actually has permission // for the URL to avoid compromised renderers talking to the browser. +// Notification that there has been a user gesture. +IPC_MESSAGE_ROUTED0(AutofillHostMsg_FirstUserGestureObserved) + // Notification that forms have been seen that are candidates for // filling/submitting by the AutofillManager. IPC_MESSAGE_ROUTED2(AutofillHostMsg_FormsSeen,
diff --git a/components/autofill/content/renderer/autofill_agent.cc b/components/autofill/content/renderer/autofill_agent.cc index 1b4daba..8a9350e9 100644 --- a/components/autofill/content/renderer/autofill_agent.cc +++ b/components/autofill/content/renderer/autofill_agent.cc
@@ -27,6 +27,7 @@ #include "content/public/common/content_switches.h" #include "content/public/common/ssl_status.h" #include "content/public/common/url_constants.h" +#include "content/public/renderer/render_frame.h" #include "content/public/renderer/render_view.h" #include "net/cert/cert_status_flags.h" #include "third_party/WebKit/public/platform/WebRect.h" @@ -128,27 +129,23 @@ show_password_suggestions_only(false) { } -AutofillAgent::AutofillAgent(content::RenderView* render_view, +AutofillAgent::AutofillAgent(content::RenderFrame* render_frame, PasswordAutofillAgent* password_autofill_agent, PasswordGenerationAgent* password_generation_agent) - : content::RenderViewObserver(render_view), + : content::RenderFrameObserver(render_frame), password_autofill_agent_(password_autofill_agent), password_generation_agent_(password_generation_agent), + legacy_(render_frame->GetRenderView(), this), + page_click_tracker_(render_frame->GetRenderView(), this), autofill_query_id_(0), - web_view_(render_view->GetWebView()), display_warning_if_disabled_(false), was_query_node_autofilled_(false), has_shown_autofill_popup_for_current_edit_(false), did_set_node_text_(false), ignore_text_changes_(false), is_popup_possibly_visible_(false), - main_frame_processed_(false), weak_ptr_factory_(this) { - render_view->GetWebView()->setAutofillClient(this); - - // The PageClickTracker is a RenderViewObserver, and hence will be freed when - // the RenderView is destroyed. - new PageClickTracker(render_view, this); + render_frame->GetWebFrame()->setAutofillClient(this); } AutofillAgent::~AutofillAgent() {} @@ -156,6 +153,8 @@ bool AutofillAgent::OnMessageReceived(const IPC::Message& message) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(AutofillAgent, message) + IPC_MESSAGE_HANDLER(AutofillMsg_FirstUserGestureObservedInTab, + OnFirstUserGestureObservedInTab) IPC_MESSAGE_HANDLER(AutofillMsg_Ping, OnPing) IPC_MESSAGE_HANDLER(AutofillMsg_FillForm, OnFillForm) IPC_MESSAGE_HANDLER(AutofillMsg_PreviewForm, OnPreviewForm) @@ -179,38 +178,27 @@ return handled; } -void AutofillAgent::DidFinishDocumentLoad(WebLocalFrame* frame) { - // If the main frame just finished loading, we should process it. - if (!frame->parent()) - main_frame_processed_ = false; - - ProcessForms(*frame); +void AutofillAgent::DidCommitProvisionalLoad(bool is_new_navigation) { + // TODO(estade): |form_cache_| shouldn't track multiple frames. + form_cache_.ResetFrame(*render_frame()->GetWebFrame()); } -void AutofillAgent::DidCommitProvisionalLoad(WebLocalFrame* frame, - bool is_new_navigation) { - form_cache_.ResetFrame(*frame); +void AutofillAgent::DidFinishDocumentLoad() { + ProcessForms(); } void AutofillAgent::FrameDetached(WebFrame* frame) { - form_cache_.ResetFrame(*frame); -} - -void AutofillAgent::FrameWillClose(WebFrame* frame) { - if (in_flight_request_form_.isNull()) + if (frame != render_frame()->GetWebFrame()) return; - for (WebFrame* temp = in_flight_request_form_.document().frame(); - temp; temp = temp->parent()) { - if (temp == frame) { - Send(new AutofillHostMsg_CancelRequestAutocomplete(routing_id())); - break; - } - } + form_cache_.ResetFrame(*frame); } void AutofillAgent::WillSubmitForm(WebLocalFrame* frame, const WebFormElement& form) { + if (frame != render_frame()->GetWebFrame()) + return; + FormData form_data; if (WebFormElementToFormData(form, WebFormControlElement(), @@ -224,22 +212,32 @@ } } +void AutofillAgent::DidChangeScrollOffset(WebLocalFrame* frame) { + if (frame != render_frame()->GetWebFrame()) + return; + + HidePopup(); +} + void AutofillAgent::FocusedNodeChanged(const WebNode& node) { HidePopup(); + if (node.isNull() || !node.isElementNode()) + return; + + if (node.document().frame() != render_frame()->GetWebFrame()) + return; + if (password_generation_agent_ && password_generation_agent_->FocusedNodeHasChanged(node)) { is_popup_possibly_visible_ = true; return; } - if (node.isNull() || !node.isElementNode()) - return; - WebElement web_element = node.toConst<WebElement>(); if (!web_element.document().frame()) - return; + return; const WebInputElement* element = toWebInputElement(&web_element); @@ -258,19 +256,31 @@ HidePopup(); } -void AutofillAgent::DidChangeScrollOffset(WebLocalFrame*) { - HidePopup(); +void AutofillAgent::LegacyFrameWillClose(blink::WebFrame* frame) { + if (in_flight_request_form_.isNull()) + return; + + for (blink::WebFrame* temp = render_frame()->GetWebFrame(); temp; + temp = temp->parent()) { + if (temp == frame) { + Send(new AutofillHostMsg_CancelRequestAutocomplete(routing_id())); + break; + } + } } void AutofillAgent::didRequestAutocomplete( const WebFormElement& form) { + DCHECK_EQ(form.document().frame(), render_frame()->GetWebFrame()); + // Disallow the dialog over non-https or broken https, except when the // ignore SSL flag is passed. See http://crbug.com/272512. // TODO(palmer): this should be moved to the browser process after frames // get their own processes. GURL url(form.document().url()); content::SSLStatus ssl_status = - render_view()->GetSSLStatusOfFrame(form.document().frame()); + render_frame()->GetRenderView()->GetSSLStatusOfFrame( + form.document().frame()); bool is_safe = url.SchemeIs(url::kHttpsScheme) && !net::IsCertStatusError(ssl_status.cert_status); bool allow_unsafe = base::CommandLine::ForCurrentProcess()->HasSwitch( @@ -321,6 +331,10 @@ void AutofillAgent::FormControlElementClicked( const WebFormControlElement& element, bool was_focused) { + // TODO(estade): Remove this check when PageClickTracker is per-frame. + if (element.document().frame() != render_frame()->GetWebFrame()) + return; + const WebInputElement* input_element = toWebInputElement(&element); if (!input_element && !IsTextAreaElement(element)) return; @@ -437,6 +451,7 @@ void AutofillAgent::firstUserGestureObserved() { password_autofill_agent_->FirstUserGestureObserved(); + Send(new AutofillHostMsg_FirstUserGestureObserved(routing_id())); } void AutofillAgent::AcceptDataListSuggestion( @@ -477,7 +492,7 @@ } void AutofillAgent::OnFillForm(int query_id, const FormData& form) { - if (!render_view()->GetWebView() || query_id != autofill_query_id_) + if (query_id != autofill_query_id_) return; was_query_node_autofilled_ = element_.isAutofilled(); @@ -486,12 +501,16 @@ base::TimeTicks::Now())); } +void AutofillAgent::OnFirstUserGestureObservedInTab() { + password_autofill_agent_->FirstUserGestureObserved(); +} + void AutofillAgent::OnPing() { Send(new AutofillHostMsg_PingAck(routing_id())); } void AutofillAgent::OnPreviewForm(int query_id, const FormData& form) { - if (!render_view()->GetWebView() || query_id != autofill_query_id_) + if (query_id != autofill_query_id_) return; was_query_node_autofilled_ = element_.isAutofilled(); @@ -678,8 +697,9 @@ if (datalist_only) field.should_autocomplete = false; - gfx::RectF bounding_box_scaled = - GetScaledBoundingBox(web_view_->pageScaleFactor(), &element_); + gfx::RectF bounding_box_scaled = GetScaledBoundingBox( + render_frame()->GetRenderView()->GetWebView()->pageScaleFactor(), + &element_); std::vector<base::string16> data_list_values; std::vector<base::string16> data_list_labels; @@ -722,22 +742,19 @@ node->suggestedValue().length()); } -void AutofillAgent::ProcessForms(const WebLocalFrame& frame) { +void AutofillAgent::ProcessForms() { // Record timestamp of when the forms are first seen. This is used to // measure the overhead of the Autofill feature. base::TimeTicks forms_seen_timestamp = base::TimeTicks::Now(); - std::vector<FormData> forms = form_cache_.ExtractNewForms(frame); + WebLocalFrame* frame = render_frame()->GetWebFrame(); + std::vector<FormData> forms = form_cache_.ExtractNewForms(*frame); // Always communicate to browser process for topmost frame. - if (!forms.empty() || - (!frame.parent() && !main_frame_processed_)) { + if (!forms.empty() || !frame->parent()) { Send(new AutofillHostMsg_FormsSeen(routing_id(), forms, forms_seen_timestamp)); } - - if (!frame.parent()) - main_frame_processed_ = true; } void AutofillAgent::HidePopup() { @@ -758,14 +775,62 @@ // inserted in iframes are not captured yet. Frame is only processed // if it has finished loading, otherwise you can end up with a partially // parsed form. - if (frame && !frame->parent() && !frame->isLoading()) { - ProcessForms(*frame); - password_autofill_agent_->OnDynamicFormsSeen(frame); + if (frame && !frame->isLoading()) { + ProcessForms(); + password_autofill_agent_->OnDynamicFormsSeen(); if (password_generation_agent_) - password_generation_agent_->OnDynamicFormsSeen(frame); + password_generation_agent_->OnDynamicFormsSeen(); return; } } } +// LegacyAutofillAgent --------------------------------------------------------- + +AutofillAgent::LegacyAutofillAgent::LegacyAutofillAgent( + content::RenderView* render_view, + AutofillAgent* agent) + : content::RenderViewObserver(render_view), agent_(agent) { +} + +AutofillAgent::LegacyAutofillAgent::~LegacyAutofillAgent() { +} + +void AutofillAgent::LegacyAutofillAgent::OnDestruct() { + // No-op. Don't delete |this|. +} + +void AutofillAgent::LegacyAutofillAgent::FrameDetached(WebFrame* frame) { + agent_->FrameDetached(frame); +} + +void AutofillAgent::LegacyAutofillAgent::WillSubmitForm( + WebLocalFrame* frame, + const WebFormElement& form) { + agent_->WillSubmitForm(frame, form); +} + +void AutofillAgent::LegacyAutofillAgent::DidChangeScrollOffset( + WebLocalFrame* frame) { + agent_->DidChangeScrollOffset(frame); +} + +void AutofillAgent::LegacyAutofillAgent::FocusedNodeChanged( + const WebNode& node) { + agent_->FocusedNodeChanged(node); +} + +void AutofillAgent::LegacyAutofillAgent::OrientationChangeEvent() { + agent_->OrientationChangeEvent(); +} + +void AutofillAgent::LegacyAutofillAgent::Resized() { + agent_->Resized(); +} + +void AutofillAgent::LegacyAutofillAgent::FrameWillClose( + blink::WebFrame* frame) { + agent_->LegacyFrameWillClose(frame); +} + } // namespace autofill
diff --git a/components/autofill/content/renderer/autofill_agent.h b/components/autofill/content/renderer/autofill_agent.h index 93eb163..9717fac 100644 --- a/components/autofill/content/renderer/autofill_agent.h +++ b/components/autofill/content/renderer/autofill_agent.h
@@ -14,6 +14,8 @@ #include "base/time/time.h" #include "components/autofill/content/renderer/form_cache.h" #include "components/autofill/content/renderer/page_click_listener.h" +#include "components/autofill/content/renderer/page_click_tracker.h" +#include "content/public/renderer/render_frame_observer.h" #include "content/public/renderer/render_view_observer.h" #include "third_party/WebKit/public/web/WebAutofillClient.h" #include "third_party/WebKit/public/web/WebFormControlElement.h" @@ -34,26 +36,51 @@ class PasswordGenerationAgent; // AutofillAgent deals with Autofill related communications between WebKit and -// the browser. There is one AutofillAgent per RenderView. -// This code was originally part of RenderView. +// the browser. There is one AutofillAgent per RenderFrame. // Note that Autofill encompasses: // - single text field suggestions, that we usually refer to as Autocomplete, // - password form fill, refered to as Password Autofill, and // - entire form fill based on one field entry, referred to as Form Autofill. -class AutofillAgent : public content::RenderViewObserver, +class AutofillAgent : public content::RenderFrameObserver, public PageClickListener, public blink::WebAutofillClient { public: // PasswordAutofillAgent is guaranteed to outlive AutofillAgent. // PasswordGenerationAgent may be NULL. If it is not, then it is also // guaranteed to outlive AutofillAgent. - AutofillAgent(content::RenderView* render_view, + AutofillAgent(content::RenderFrame* render_frame, PasswordAutofillAgent* password_autofill_manager, PasswordGenerationAgent* password_generation_agent); virtual ~AutofillAgent(); private: + // Thunk class for RenderViewObserver methods that haven't yet been migrated + // to RenderFrameObserver. Should eventually be removed. + // http://crbug.com/433486 + class LegacyAutofillAgent : public content::RenderViewObserver { + public: + LegacyAutofillAgent(content::RenderView* render_view, AutofillAgent* agent); + ~LegacyAutofillAgent() override; + + private: + // content::RenderViewObserver: + void OnDestruct() override; + void FrameDetached(blink::WebFrame* frame) override; + void WillSubmitForm(blink::WebLocalFrame* frame, + const blink::WebFormElement& form) override; + void DidChangeScrollOffset(blink::WebLocalFrame* frame) override; + void FocusedNodeChanged(const blink::WebNode& node) override; + void OrientationChangeEvent() override; + void Resized() override; + void FrameWillClose(blink::WebFrame* frame) override; + + AutofillAgent* agent_; + + DISALLOW_COPY_AND_ASSIGN(LegacyAutofillAgent); + }; + friend class LegacyAutofillAgent; + // Flags passed to ShowSuggestions. struct ShowSuggestionsOptions { // All fields are default initialized to false. @@ -87,19 +114,21 @@ bool show_password_suggestions_only; }; - // content::RenderViewObserver: + // content::RenderFrameObserver: bool OnMessageReceived(const IPC::Message& message) override; - void DidFinishDocumentLoad(blink::WebLocalFrame* frame) override; - void DidCommitProvisionalLoad(blink::WebLocalFrame* frame, - bool is_new_navigation) override; - void FrameDetached(blink::WebFrame* frame) override; - void FrameWillClose(blink::WebFrame* frame) override; + void DidCommitProvisionalLoad(bool is_new_navigation) override; + void DidFinishDocumentLoad() override; + + // Pass-throughs from LegacyAutofillAgent. These correlate with + // RenderViewObserver methods. + void FrameDetached(blink::WebFrame* frame); void WillSubmitForm(blink::WebLocalFrame* frame, - const blink::WebFormElement& form) override; - void DidChangeScrollOffset(blink::WebLocalFrame* frame) override; - void FocusedNodeChanged(const blink::WebNode& node) override; - void OrientationChangeEvent() override; - void Resized() override; + const blink::WebFormElement& form); + void DidChangeScrollOffset(blink::WebLocalFrame* frame); + void FocusedNodeChanged(const blink::WebNode& node); + void OrientationChangeEvent(); + void Resized(); + void LegacyFrameWillClose(blink::WebFrame* frame); // PageClickListener: void FormControlElementClicked(const blink::WebFormControlElement& element, @@ -124,6 +153,7 @@ void OnFieldTypePredictionsAvailable( const std::vector<FormDataPredictions>& forms); void OnFillForm(int query_id, const FormData& form); + void OnFirstUserGestureObservedInTab(); void OnPing(); void OnPreviewForm(int query_id, const FormData& form); @@ -185,17 +215,25 @@ void PreviewFieldWithValue(const base::string16& value, blink::WebInputElement* node); - // Notifies browser of new fillable forms in |frame|. - void ProcessForms(const blink::WebLocalFrame& frame); + // Notifies browser of new fillable forms in |render_frame|. + void ProcessForms(); // Hides any currently showing Autofill popup. void HidePopup(); + // Formerly cached forms for all frames, now only caches forms for the current + // frame. TODO(estade): simplify |FormCache| to only work with a single frame. FormCache form_cache_; PasswordAutofillAgent* password_autofill_agent_; // Weak reference. PasswordGenerationAgent* password_generation_agent_; // Weak reference. + // Passes through RenderViewObserver methods to |this|. + LegacyAutofillAgent legacy_; + + // Tracks clicks on the RenderViewHost, informs |this|. + PageClickTracker page_click_tracker_; + // The ID of the last request sent for form field Autofill. Used to ignore // out of date responses. int autofill_query_id_; @@ -206,9 +244,6 @@ // The form element currently requesting an interactive autocomplete. blink::WebFormElement in_flight_request_form_; - // Pointer to the WebView. Used to access page scale factor. - blink::WebView* web_view_; - // Should we display a warning if autofill is disabled? bool display_warning_if_disabled_; @@ -232,11 +267,6 @@ // messages to close the Autofill popup when it can't possibly be showing. bool is_popup_possibly_visible_; - // True if a message has already been sent about forms for the main frame. - // When the main frame is first loaded, a message is sent even if no forms - // exist in the frame. Otherwise, such messages are supressed. - bool main_frame_processed_; - base::WeakPtrFactory<AutofillAgent> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(AutofillAgent);
diff --git a/components/autofill/content/renderer/form_autofill_util.cc b/components/autofill/content/renderer/form_autofill_util.cc index 7501905..628711c 100644 --- a/components/autofill/content/renderer/form_autofill_util.cc +++ b/components/autofill/content/renderer/form_autofill_util.cc
@@ -501,9 +501,8 @@ FieldFilterMask filters, bool force_override, Callback callback) { - std::vector<WebFormControlElement> control_elements; - ExtractAutofillableElements( - form_element, ExtractionRequirements(), &control_elements); + std::vector<WebFormControlElement> control_elements = + ExtractAutofillableElementsInForm(form_element, ExtractionRequirements()); if (control_elements.size() != data.fields.size()) { // This case should be reachable only for pathological websites and tests, @@ -658,6 +657,177 @@ return false; } +bool ExtractFieldsFromControlElements( + const WebVector<WebFormControlElement>& control_elements, + RequirementsMask requirements, + ExtractMask extract_mask, + ScopedVector<FormFieldData>* form_fields, + std::vector<bool>* fields_extracted, + std::map<base::string16, FormFieldData*>* name_map) { + for (size_t i = 0; i < control_elements.size(); ++i) { + const WebFormControlElement& control_element = control_elements[i]; + + if (!IsAutofillableElement(control_element)) + continue; + + const WebInputElement* input_element = toWebInputElement(&control_element); + if (requirements & REQUIRE_AUTOCOMPLETE && + IsAutofillableInputElement(input_element) && + !SatisfiesRequireAutocomplete(*input_element)) + continue; + + // Create a new FormFieldData, fill it out and map it to the field's name. + FormFieldData* form_field = new FormFieldData; + WebFormControlElementToFormField(control_element, extract_mask, form_field); + form_fields->push_back(form_field); + // TODO(jhawkins): A label element is mapped to a form control element's id. + // field->name() will contain the id only if the name does not exist. Add + // an id() method to WebFormControlElement and use that here. + (*name_map)[form_field->name] = form_field; + (*fields_extracted)[i] = true; + } + + // If we failed to extract any fields, give up. Also, to avoid overly + // expensive computation, we impose a maximum number of allowable fields. + if (form_fields->empty() || form_fields->size() > kMaxParseableFields) + return false; + return true; +} + +// For each label element, get the corresponding form control element, use the +// form control element's name as a key into the <name, FormFieldData> map to +// find the previously created FormFieldData and set the FormFieldData's label +// to the label.firstChild().nodeValue() of the label element. +void MatchLabelsAndFields(const WebElementCollection& labels, + std::map<base::string16, FormFieldData*>* name_map) { + CR_DEFINE_STATIC_LOCAL(WebString, kFor, ("for")); + CR_DEFINE_STATIC_LOCAL(WebString, kHidden, ("hidden")); + + for (WebElement item = labels.firstItem(); !item.isNull(); + item = labels.nextItem()) { + WebLabelElement label = item.to<WebLabelElement>(); + WebFormControlElement field_element = + label.correspondingControl().to<WebFormControlElement>(); + + base::string16 element_name; + if (field_element.isNull()) { + // Sometimes site authors will incorrectly specify the corresponding + // field element's name rather than its id, so we compensate here. + element_name = label.getAttribute(kFor); + } else if (!field_element.isFormControlElement() || + field_element.formControlType() == kHidden) { + continue; + } else { + element_name = field_element.nameForAutofill(); + } + + auto iter = name_map->find(element_name); + if (iter == name_map->end()) + continue; + + base::string16 label_text = FindChildText(label); + + // Concatenate labels because some sites might have multiple label + // candidates. + if (!iter->second->label.empty() && !label_text.empty()) + iter->second->label += base::ASCIIToUTF16(" "); + iter->second->label += label_text; + } +} + +// Common function shared by WebFormElementToFormData() and +// UnownedFormElementsAndFieldSetsToFormData(). Either pass in: +// 1) |form_element|, |form_control_element| and an empty |fieldsets|. +// or +// 2) a non-empty |fieldsets|. +bool FormOrFieldsetsToFormData( + const blink::WebFormElement* form_element, + const blink::WebFormControlElement* form_control_element, + const std::vector<blink::WebElement>& fieldsets, + const WebVector<WebFormControlElement>& control_elements, + RequirementsMask requirements, + ExtractMask extract_mask, + FormData* form, + FormFieldData* field) { + CR_DEFINE_STATIC_LOCAL(WebString, kLabel, ("label")); + + if (form_element) { + DCHECK(form_control_element); + DCHECK(fieldsets.empty()); + } else { + DCHECK(!form_control_element); + DCHECK(!field); + } + + // A map from a FormFieldData's name to the FormFieldData itself. + std::map<base::string16, FormFieldData*> name_map; + + // The extracted FormFields. We use pointers so we can store them in + // |name_map|. + ScopedVector<FormFieldData> form_fields; + + // A vector of bools that indicate whether each field in the form meets the + // requirements and thus will be in the resulting |form|. + std::vector<bool> fields_extracted(control_elements.size(), false); + + if (!ExtractFieldsFromControlElements(control_elements, + requirements, + extract_mask, + &form_fields, + &fields_extracted, + &name_map)) { + return false; + } + + if (form_element) { + // Loop through the label elements inside the form element. For each label + // element, get the corresponding form control element, use the form control + // element's name as a key into the <name, FormFieldData> map to find the + // previously created FormFieldData and set the FormFieldData's label to the + // label.firstChild().nodeValue() of the label element. + WebElementCollection labels = + form_element->getElementsByHTMLTagName(kLabel); + DCHECK(!labels.isNull()); + MatchLabelsAndFields(labels, &name_map); + } else { + // Same as the if block, but for all the labels in fieldsets. + for (size_t i = 0; i < fieldsets.size(); ++i) { + WebElementCollection labels = + fieldsets[i].getElementsByHTMLTagName(kLabel); + DCHECK(!labels.isNull()); + MatchLabelsAndFields(labels, &name_map); + } + } + + // Loop through the form control elements, extracting the label text from + // the DOM. We use the |fields_extracted| vector to make sure we assign the + // extracted label to the correct field, as it's possible |form_fields| will + // not contain all of the elements in |control_elements|. + for (size_t i = 0, field_idx = 0; + i < control_elements.size() && field_idx < form_fields.size(); ++i) { + // This field didn't meet the requirements, so don't try to find a label + // for it. + if (!fields_extracted[i]) + continue; + + const WebFormControlElement& control_element = control_elements[i]; + if (form_fields[field_idx]->label.empty()) + form_fields[field_idx]->label = InferLabelForElement(control_element); + form_fields[field_idx]->label = + form_fields[field_idx]->label.substr(0, kMaxDataLength); + + if (field && *form_control_element == control_element) + *field = *form_fields[field_idx]; + + ++field_idx; + } + + // Copy the created FormFields into the resulting FormData object. + for (const auto& iter : form_fields) + form->fields.push_back(*iter); + return true; +} + } // namespace const size_t kMaxParseableFields = 200; @@ -747,16 +917,10 @@ return true; } -// Fills |autofillable_elements| with all the auto-fillable form control -// elements in |form_element|. -void ExtractAutofillableElements( - const WebFormElement& form_element, - RequirementsMask requirements, - std::vector<WebFormControlElement>* autofillable_elements) { - WebVector<WebFormControlElement> control_elements; - form_element.getFormControlElements(control_elements); - - autofillable_elements->clear(); +std::vector<blink::WebFormControlElement> ExtractAutofillableElementsFromSet( + const WebVector<WebFormControlElement>& control_elements, + RequirementsMask requirements) { + std::vector<blink::WebFormControlElement> autofillable_elements; for (size_t i = 0; i < control_elements.size(); ++i) { WebFormControlElement element = control_elements[i]; if (!IsAutofillableElement(element)) @@ -765,14 +929,25 @@ if (requirements & REQUIRE_AUTOCOMPLETE) { // TODO(isherman): WebKit currently doesn't handle the autocomplete // attribute for select or textarea elements, but it probably should. - WebInputElement* input_element = toWebInputElement(&control_elements[i]); + const WebInputElement* input_element = + toWebInputElement(&control_elements[i]); if (IsAutofillableInputElement(input_element) && !SatisfiesRequireAutocomplete(*input_element)) continue; } - autofillable_elements->push_back(element); + autofillable_elements.push_back(element); } + return autofillable_elements; +} + +std::vector<WebFormControlElement> ExtractAutofillableElementsInForm( + const WebFormElement& form_element, + RequirementsMask requirements) { + WebVector<WebFormControlElement> control_elements; + form_element.getFormControlElements(control_elements); + + return ExtractAutofillableElementsFromSet(control_elements, requirements); } void WebFormControlElementToFormField(const WebFormControlElement& element, @@ -862,10 +1037,6 @@ ExtractMask extract_mask, FormData* form, FormFieldData* field) { - CR_DEFINE_STATIC_LOCAL(WebString, kLabel, ("label")); - CR_DEFINE_STATIC_LOCAL(WebString, kFor, ("for")); - CR_DEFINE_STATIC_LOCAL(WebString, kHidden, ("hidden")); - const WebFrame* frame = form_element.document().frame(); if (!frame) return false; @@ -883,117 +1054,27 @@ if (!form->action.is_valid()) form->action = GURL(form_element.action()); - // A map from a FormFieldData's name to the FormFieldData itself. - std::map<base::string16, FormFieldData*> name_map; - - // The extracted FormFields. We use pointers so we can store them in - // |name_map|. - ScopedVector<FormFieldData> form_fields; - WebVector<WebFormControlElement> control_elements; form_element.getFormControlElements(control_elements); - // A vector of bools that indicate whether each field in the form meets the - // requirements and thus will be in the resulting |form|. - std::vector<bool> fields_extracted(control_elements.size(), false); + std::vector<blink::WebElement> dummy_fieldset; + return FormOrFieldsetsToFormData(&form_element, &form_control_element, + dummy_fieldset, control_elements, + requirements, extract_mask, form, field); +} - for (size_t i = 0; i < control_elements.size(); ++i) { - const WebFormControlElement& control_element = control_elements[i]; +bool UnownedFormElementsAndFieldSetsToFormData( + const std::vector<blink::WebElement>& fieldsets, + const std::vector<blink::WebFormControlElement>& control_elements, + const GURL& origin, + ExtractMask extract_mask, + FormData* form) { + form->origin = origin; + form->user_submitted = false; - if (!IsAutofillableElement(control_element)) - continue; - - const WebInputElement* input_element = toWebInputElement(&control_element); - if (requirements & REQUIRE_AUTOCOMPLETE && - IsAutofillableInputElement(input_element) && - !SatisfiesRequireAutocomplete(*input_element)) - continue; - - // Create a new FormFieldData, fill it out and map it to the field's name. - FormFieldData* form_field = new FormFieldData; - WebFormControlElementToFormField(control_element, extract_mask, form_field); - form_fields.push_back(form_field); - // TODO(jhawkins): A label element is mapped to a form control element's id. - // field->name() will contain the id only if the name does not exist. Add - // an id() method to WebFormControlElement and use that here. - name_map[form_field->name] = form_field; - fields_extracted[i] = true; - } - - // If we failed to extract any fields, give up. Also, to avoid overly - // expensive computation, we impose a maximum number of allowable fields. - if (form_fields.empty() || form_fields.size() > kMaxParseableFields) - return false; - - // Loop through the label elements inside the form element. For each label - // element, get the corresponding form control element, use the form control - // element's name as a key into the <name, FormFieldData> map to find the - // previously created FormFieldData and set the FormFieldData's label to the - // label.firstChild().nodeValue() of the label element. - WebElementCollection labels = form_element.getElementsByHTMLTagName(kLabel); - DCHECK(!labels.isNull()); - for (WebElement item = labels.firstItem(); !item.isNull(); - item = labels.nextItem()) { - WebLabelElement label = item.to<WebLabelElement>(); - WebFormControlElement field_element = - label.correspondingControl().to<WebFormControlElement>(); - - base::string16 element_name; - if (field_element.isNull()) { - // Sometimes site authors will incorrectly specify the corresponding - // field element's name rather than its id, so we compensate here. - element_name = label.getAttribute(kFor); - } else if ( - !field_element.isFormControlElement() || - field_element.formControlType() == kHidden) { - continue; - } else { - element_name = field_element.nameForAutofill(); - } - - std::map<base::string16, FormFieldData*>::iterator iter = - name_map.find(element_name); - if (iter != name_map.end()) { - base::string16 label_text = FindChildText(label); - - // Concatenate labels because some sites might have multiple label - // candidates. - if (!iter->second->label.empty() && !label_text.empty()) - iter->second->label += base::ASCIIToUTF16(" "); - iter->second->label += label_text; - } - } - - // Loop through the form control elements, extracting the label text from - // the DOM. We use the |fields_extracted| vector to make sure we assign the - // extracted label to the correct field, as it's possible |form_fields| will - // not contain all of the elements in |control_elements|. - for (size_t i = 0, field_idx = 0; - i < control_elements.size() && field_idx < form_fields.size(); ++i) { - // This field didn't meet the requirements, so don't try to find a label - // for it. - if (!fields_extracted[i]) - continue; - - const WebFormControlElement& control_element = control_elements[i]; - if (form_fields[field_idx]->label.empty()) - form_fields[field_idx]->label = InferLabelForElement(control_element); - form_fields[field_idx]->label = - form_fields[field_idx]->label.substr(0, kMaxDataLength); - - if (field && form_control_element == control_element) - *field = *form_fields[field_idx]; - - ++field_idx; - } - - // Copy the created FormFields into the resulting FormData object. - for (ScopedVector<FormFieldData>::const_iterator iter = form_fields.begin(); - iter != form_fields.end(); ++iter) { - form->fields.push_back(**iter); - } - - return true; + return FormOrFieldsetsToFormData(nullptr, nullptr, fieldsets, + control_elements, REQUIRE_NONE, extract_mask, + form, nullptr); } bool FindFormAndFieldForFormControlElement(const WebFormControlElement& element, @@ -1077,9 +1158,8 @@ if (form_element.isNull()) return false; - std::vector<WebFormControlElement> control_elements; - ExtractAutofillableElements( - form_element, ExtractionRequirements(), &control_elements); + std::vector<WebFormControlElement> control_elements = + ExtractAutofillableElementsInForm(form_element, ExtractionRequirements()); for (size_t i = 0; i < control_elements.size(); ++i) { // There might be unrelated elements in this form which have already been // auto-filled. For example, the user might have already filled the address
diff --git a/components/autofill/content/renderer/form_autofill_util.h b/components/autofill/content/renderer/form_autofill_util.h index 916ddb9..a43231a5d 100644 --- a/components/autofill/content/renderer/form_autofill_util.h +++ b/components/autofill/content/renderer/form_autofill_util.h
@@ -8,8 +8,11 @@ #include <vector> #include "base/strings/string16.h" +#include "third_party/WebKit/public/platform/WebVector.h" #include "ui/gfx/rect.h" +class GURL; + namespace blink { class WebDocument; class WebElement; @@ -84,12 +87,15 @@ bool ClickElement(const blink::WebDocument& document, const WebElementDescriptor& element_descriptor); -// Fills |autofillable_elements| with all the auto-fillable form control -// elements in |form_element|. -void ExtractAutofillableElements( +// Returns all the auto-fillable form control elements in |control_elements|. +std::vector<blink::WebFormControlElement> ExtractAutofillableElementsFromSet( + const blink::WebVector<blink::WebFormControlElement>& control_elements, + RequirementsMask requirements); + +// Returns all the auto-fillable form control elements in |form_element|. +std::vector<blink::WebFormControlElement> ExtractAutofillableElementsInForm( const blink::WebFormElement& form_element, - RequirementsMask requirements, - std::vector<blink::WebFormControlElement>* autofillable_elements); + RequirementsMask requirements); // Fills out a FormField object from a given WebFormControlElement. // |extract_mask|: See the enum ExtractMask above for details. @@ -113,6 +119,16 @@ FormData* form, FormFieldData* field); +// Fills |form| with the form data derived from |fieldsets|, |control_elements| +// and |origin|. |extract_mask| usage and the return value are the same as +// WebFormElementToFormData() above. +bool UnownedFormElementsAndFieldSetsToFormData( + const std::vector<blink::WebElement>& fieldsets, + const std::vector<blink::WebFormControlElement>& control_elements, + const GURL& origin, + ExtractMask extract_mask, + FormData* form); + // Finds the form that contains |element| and returns it in |form|. Fills // |field| with the |FormField| representation for element. // Returns false if the form is not found or cannot be serialized.
diff --git a/components/autofill/content/renderer/form_cache.cc b/components/autofill/content/renderer/form_cache.cc index a42efa1..a0b293a 100644 --- a/components/autofill/content/renderer/form_cache.cc +++ b/components/autofill/content/renderer/form_cache.cc
@@ -5,6 +5,7 @@ #include "components/autofill/content/renderer/form_cache.h" #include "base/logging.h" +#include "base/stl_util.h" #include "base/strings/utf_string_conversions.h" #include "components/autofill/content/renderer/form_autofill_util.h" #include "components/autofill/core/common/autofill_constants.h" @@ -15,23 +16,28 @@ #include "third_party/WebKit/public/platform/WebVector.h" #include "third_party/WebKit/public/web/WebConsoleMessage.h" #include "third_party/WebKit/public/web/WebDocument.h" +#include "third_party/WebKit/public/web/WebElementCollection.h" #include "third_party/WebKit/public/web/WebFormControlElement.h" #include "third_party/WebKit/public/web/WebFormElement.h" #include "third_party/WebKit/public/web/WebInputElement.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" +#include "third_party/WebKit/public/web/WebNodeList.h" #include "third_party/WebKit/public/web/WebSelectElement.h" #include "third_party/WebKit/public/web/WebTextAreaElement.h" #include "ui/base/l10n/l10n_util.h" using blink::WebConsoleMessage; using blink::WebDocument; +using blink::WebElement; +using blink::WebElementCollection; using blink::WebFormControlElement; using blink::WebFormElement; using blink::WebFrame; using blink::WebInputElement; +using blink::WebNode; using blink::WebSelectElement; -using blink::WebTextAreaElement; using blink::WebString; +using blink::WebTextAreaElement; using blink::WebVector; namespace autofill { @@ -81,6 +87,31 @@ } } +bool IsElementInsideFormOrFieldSet(const WebElement& element) { + for (WebNode parent_node = element.parentNode(); + !parent_node.isNull(); + parent_node = parent_node.parentNode()) { + if (!parent_node.isElementNode()) + continue; + + WebElement cur_element = parent_node.to<WebElement>(); + if (cur_element.hasHTMLTagName("form") || + cur_element.hasHTMLTagName("fieldset")) { + return true; + } + } + return false; +} + +// To avoid overly expensive computation, we impose a minimum number of +// allowable fields. The corresponding maximum number of allowable fields +// is imposed by WebFormElementToFormData(). +bool ShouldIgnoreForm(size_t num_editable_elements, + size_t num_control_elements) { + return (num_editable_elements < kRequiredAutofillFields && + num_control_elements > 0); +} + } // namespace FormCache::FormCache() { @@ -89,44 +120,62 @@ FormCache::~FormCache() { } +// static +std::vector<WebFormControlElement> +FormCache::GetUnownedAutofillableFormFieldElements( + const WebElementCollection& elements, + std::vector<WebElement>* fieldsets) { + std::vector<WebFormControlElement> unowned_fieldset_children; + for (WebElement element = elements.firstItem(); + !element.isNull(); + element = elements.nextItem()) { + if (element.isFormControlElement()) { + WebFormControlElement control = element.to<WebFormControlElement>(); + if (control.form().isNull()) + unowned_fieldset_children.push_back(control); + } + + if (fieldsets && element.hasHTMLTagName("fieldset") && + !IsElementInsideFormOrFieldSet(element)) { + fieldsets->push_back(element); + } + } + return ExtractAutofillableElementsFromSet(unowned_fieldset_children, + REQUIRE_NONE); +} + std::vector<FormData> FormCache::ExtractNewForms(const WebFrame& frame) { std::vector<FormData> forms; WebDocument document = frame.document(); if (document.isNull()) return forms; - web_documents_.insert(document); + if (!ContainsKey(documents_to_synthetic_form_map_, document)) + documents_to_synthetic_form_map_[document] = FormData(); WebVector<WebFormElement> web_forms; document.forms(web_forms); // Log an error message for deprecated attributes, but only the first time // the form is parsed. - bool log_deprecation_messages = - parsed_forms_.find(&frame) == parsed_forms_.end(); + bool log_deprecation_messages = !ContainsKey(parsed_forms_, &frame); + + const ExtractMask extract_mask = + static_cast<ExtractMask>(EXTRACT_VALUE | EXTRACT_OPTIONS); size_t num_fields_seen = 0; for (size_t i = 0; i < web_forms.size(); ++i) { const WebFormElement& form_element = web_forms[i]; - std::vector<WebFormControlElement> control_elements; - ExtractAutofillableElements(form_element, autofill::REQUIRE_NONE, - &control_elements); + std::vector<WebFormControlElement> control_elements = + ExtractAutofillableElementsInForm(form_element, REQUIRE_NONE); size_t num_editable_elements = ScanFormControlElements(control_elements, log_deprecation_messages); - // To avoid overly expensive computation, we impose a minimum number of - // allowable fields. The corresponding maximum number of allowable fields - // is imposed by WebFormElementToFormData(). - if (num_editable_elements < kRequiredAutofillFields && - control_elements.size() > 0) { + if (ShouldIgnoreForm(num_editable_elements, control_elements.size())) continue; - } FormData form; - ExtractMask extract_mask = - static_cast<ExtractMask>(EXTRACT_VALUE | EXTRACT_OPTIONS); - if (!WebFormElementToFormData(form_element, WebFormControlElement(), REQUIRE_NONE, extract_mask, &form, NULL)) { continue; @@ -134,31 +183,56 @@ num_fields_seen += form.fields.size(); if (num_fields_seen > kMaxParseableFields) - break; + return forms; if (form.fields.size() >= kRequiredAutofillFields && - !parsed_forms_[&frame].count(form)) { + !ContainsKey(parsed_forms_[&frame], form)) { forms.push_back(form); parsed_forms_[&frame].insert(form); } } + + // Look for more parseable fields outside of forms. + std::vector<WebElement> fieldsets; + std::vector<WebFormControlElement> control_elements = + GetUnownedAutofillableFormFieldElements(document.all(), &fieldsets); + + size_t num_editable_elements = + ScanFormControlElements(control_elements, log_deprecation_messages); + + if (ShouldIgnoreForm(num_editable_elements, control_elements.size())) + return forms; + + FormData form; + if (!UnownedFormElementsAndFieldSetsToFormData(fieldsets, control_elements, + document.url(), extract_mask, + &form)) { + return forms; + } + + num_fields_seen += form.fields.size(); + if (num_fields_seen > kMaxParseableFields) + return forms; + + if (form.fields.size() >= kRequiredAutofillFields && + !parsed_forms_[&frame].count(form)) { + forms.push_back(form); + parsed_forms_[&frame].insert(form); + documents_to_synthetic_form_map_[document] = form; + } return forms; } void FormCache::ResetFrame(const WebFrame& frame) { std::vector<WebDocument> documents_to_delete; - for (std::set<WebDocument>::const_iterator it = web_documents_.begin(); - it != web_documents_.end(); ++it) { - const WebFrame* document_frame = it->frame(); + for (const auto& it : documents_to_synthetic_form_map_) { + const WebFrame* document_frame = it.first.frame(); if (!document_frame || document_frame == &frame) - documents_to_delete.push_back(*it); + documents_to_delete.push_back(it.first); } - for (std::vector<WebDocument>::const_iterator it = - documents_to_delete.begin(); - it != documents_to_delete.end(); ++it) { - web_documents_.erase(*it); - } + for (const auto& it : documents_to_delete) + documents_to_synthetic_form_map_.erase(it); parsed_forms_[&frame].clear(); RemoveOldElements(frame, &initial_select_values_); @@ -170,9 +244,8 @@ if (form_element.isNull()) return false; - std::vector<WebFormControlElement> control_elements; - ExtractAutofillableElements(form_element, autofill::REQUIRE_NONE, - &control_elements); + std::vector<WebFormControlElement> control_elements = + ExtractAutofillableElementsInForm(form_element, REQUIRE_NONE); for (size_t i = 0; i < control_elements.size(); ++i) { WebFormControlElement control_element = control_elements[i]; // Don't modify the value of disabled fields. @@ -224,40 +297,56 @@ bool FormCache::ShowPredictions(const FormDataPredictions& form) { DCHECK_EQ(form.data.fields.size(), form.fields.size()); - // Find the form. - bool found_form = false; - WebFormElement form_element; - for (std::set<WebDocument>::const_iterator it = web_documents_.begin(); - it != web_documents_.end() && !found_form; ++it) { - WebVector<WebFormElement> web_forms; - it->forms(web_forms); + std::vector<WebFormControlElement> control_elements; - for (size_t i = 0; i < web_forms.size(); ++i) { - form_element = web_forms[i]; + // First check the synthetic forms. + bool found_synthetic_form = false; + for (const auto& it : documents_to_synthetic_form_map_) { + const FormData& form_data = it.second; + if (!form_data.SameFormAs(form.data)) + continue; - // Note: matching on the form name here which is not guaranteed to be - // unique for the page, nor is it guaranteed to be non-empty. Ideally, we - // would have a way to uniquely identify the form cross-process. For now, - // we'll check form name and form action for identity. - // Also note that WebString() == WebString(string16()) does not evaluate - // to |true| -- WebKit distinguishes between a "null" string (lhs) and an - // "empty" string (rhs). We don't want that distinction, so forcing to - // string16. - base::string16 element_name = GetFormIdentifier(form_element); - GURL action(form_element.document().completeURL(form_element.action())); - if (element_name == form.data.name && action == form.data.action) { - found_form = true; - break; - } - } + found_synthetic_form = true; + WebDocument document = it.first; + control_elements = + GetUnownedAutofillableFormFieldElements(document.all(), nullptr); + break; } - if (!found_form) - return false; + if (!found_synthetic_form) { + // Find the real form by searching through the WebDocuments. + bool found_form = false; + WebFormElement form_element; + for (const auto& it : documents_to_synthetic_form_map_) { + WebVector<WebFormElement> web_forms; + it.first.forms(web_forms); - std::vector<WebFormControlElement> control_elements; - ExtractAutofillableElements(form_element, autofill::REQUIRE_NONE, - &control_elements); + for (size_t i = 0; i < web_forms.size(); ++i) { + form_element = web_forms[i]; + + // Note: matching on the form name here which is not guaranteed to be + // unique for the page, nor is it guaranteed to be non-empty. Ideally, + // we would have a way to uniquely identify the form cross-process. For + // now, we'll check form name and form action for identity. + // Also note that WebString() == WebString(string16()) does not evaluate + // to |true| -- WebKit distinguishes between a "null" string (lhs) and + // an "empty" string (rhs). We don't want that distinction, so forcing + // to string16. + base::string16 element_name = GetFormIdentifier(form_element); + GURL action(form_element.document().completeURL(form_element.action())); + if (element_name == form.data.name && action == form.data.action) { + found_form = true; + control_elements = + ExtractAutofillableElementsInForm(form_element, REQUIRE_NONE); + break; + } + } + } + + if (!found_form) + return false; + } + if (control_elements.size() != form.fields.size()) { // Keep things simple. Don't show predictions for forms that were modified // between page load and the server's response to our query. @@ -265,10 +354,9 @@ } for (size_t i = 0; i < control_elements.size(); ++i) { - WebFormControlElement* element = &control_elements[i]; + WebFormControlElement& element = control_elements[i]; - if (base::string16(element->nameForAutofill()) != - form.data.fields[i].name) { + if (base::string16(element.nameForAutofill()) != form.data.fields[i].name) { // Keep things simple. Don't show predictions for elements whose names // were modified between page load and the server's response to our query. continue; @@ -282,11 +370,11 @@ base::UTF8ToUTF16(form.fields[i].signature), base::UTF8ToUTF16(form.signature), base::UTF8ToUTF16(form.experiment_id)); - if (!element->hasAttribute("placeholder")) { - element->setAttribute("placeholder", - WebString(base::UTF8ToUTF16(placeholder))); + if (!element.hasAttribute("placeholder")) { + element.setAttribute("placeholder", + WebString(base::UTF8ToUTF16(placeholder))); } - element->setAttribute("title", WebString(title)); + element.setAttribute("title", WebString(title)); } return true;
diff --git a/components/autofill/content/renderer/form_cache.h b/components/autofill/content/renderer/form_cache.h index 39f0d20e..e659492 100644 --- a/components/autofill/content/renderer/form_cache.h +++ b/components/autofill/content/renderer/form_cache.h
@@ -13,6 +13,8 @@ namespace blink { class WebDocument; +class WebElement; +class WebElementCollection; class WebFormControlElement; class WebFrame; class WebInputElement; @@ -30,6 +32,15 @@ FormCache(); ~FormCache(); + // Get all form control elements from |elements| that are not part of a form. + // If |fieldsets| is not NULL, also append the fieldsets encountered that are + // not part of a form. + // Exposed for sharing with tests. + static std::vector<blink::WebFormControlElement> + GetUnownedAutofillableFormFieldElements( + const blink::WebElementCollection& elements, + std::vector<blink::WebElement>* fieldsets); + // Scans the DOM in |frame| extracting and storing forms that have not been // seen before. Returns the extracted forms. std::vector<FormData> ExtractNewForms(const blink::WebFrame& frame); @@ -56,8 +67,10 @@ const std::vector<blink::WebFormControlElement>& control_elements, bool log_deprecation_messages); - // The cached web frames. - std::set<blink::WebDocument> web_documents_; + // The cached web frames and their corresponding synthetic FormData. + // The synthetic FormData is for all the fieldsets in the document without a + // form owner. + std::map<blink::WebDocument, FormData> documents_to_synthetic_form_map_; // The cached forms per frame. Used to prevent re-extraction of forms. std::map<const blink::WebFrame*, std::set<FormData> > parsed_forms_;
diff --git a/components/autofill/content/renderer/page_click_tracker.cc b/components/autofill/content/renderer/page_click_tracker.cc index 590e7af..14ceda8 100644 --- a/components/autofill/content/renderer/page_click_tracker.cc +++ b/components/autofill/content/renderer/page_click_tracker.cc
@@ -75,6 +75,10 @@ PageClickTracker::~PageClickTracker() { } +void PageClickTracker::OnDestruct() { + // No-op. Don't delete |this|. +} + void PageClickTracker::DidHandleMouseEvent(const WebMouseEvent& event) { if (event.type != WebInputEvent::MouseDown || event.button != WebMouseEvent::ButtonLeft) {
diff --git a/components/autofill/content/renderer/page_click_tracker.h b/components/autofill/content/renderer/page_click_tracker.h index 7849b90..0bcc0f6 100644 --- a/components/autofill/content/renderer/page_click_tracker.h +++ b/components/autofill/content/renderer/page_click_tracker.h
@@ -23,7 +23,8 @@ // This is useful for password/form autofill where we want to trigger a // suggestion popup when a text input is clicked. // -// There is one PageClickTracker per RenderView. +// There is one PageClickTracker per AutofillAgent. +// TODO(estade): migrate to content::RenderFrameObserver. class PageClickTracker : public content::RenderViewObserver { public: // The |listener| will be notified when an element is clicked. It must @@ -34,6 +35,7 @@ private: // RenderView::Observer implementation. + void OnDestruct() override; void DidHandleMouseEvent(const blink::WebMouseEvent& event) override; void DidHandleGestureEvent(const blink::WebGestureEvent& event) override; void FocusedNodeChanged(const blink::WebNode& node) override;
diff --git a/components/autofill/content/renderer/password_autofill_agent.cc b/components/autofill/content/renderer/password_autofill_agent.cc index e500806..dfa7bf7 100644 --- a/components/autofill/content/renderer/password_autofill_agent.cc +++ b/components/autofill/content/renderer/password_autofill_agent.cc
@@ -18,6 +18,7 @@ #include "components/autofill/core/common/password_form_fill_data.h" #include "content/public/renderer/document_state.h" #include "content/public/renderer/navigation_state.h" +#include "content/public/renderer/render_frame.h" #include "content/public/renderer/render_view.h" #include "third_party/WebKit/public/platform/WebVector.h" #include "third_party/WebKit/public/web/WebAutofillClient.h" @@ -130,54 +131,47 @@ } // Helper to locate form elements identified by |data|. -void FindFormElements(blink::WebView* view, +void FindFormElements(content::RenderFrame* render_frame, const PasswordFormFillData& data, FormElementsList* results) { - DCHECK(view); DCHECK(results); - blink::WebFrame* main_frame = view->mainFrame(); - if (!main_frame) - return; GURL::Replacements rep; rep.ClearQuery(); rep.ClearRef(); - // Loop through each frame. - for (blink::WebFrame* f = main_frame; f; f = f->traverseNext(false)) { - blink::WebDocument doc = f->document(); - if (!doc.isHTMLDocument()) - continue; + blink::WebDocument doc = render_frame->GetWebFrame()->document(); + if (!doc.isHTMLDocument()) + return; - GURL full_origin(doc.url()); - if (data.origin != full_origin.ReplaceComponents(rep)) - continue; + GURL full_origin(doc.url()); + if (data.origin != full_origin.ReplaceComponents(rep)) + return; - blink::WebVector<blink::WebFormElement> forms; - doc.forms(forms); + blink::WebVector<blink::WebFormElement> forms; + doc.forms(forms); - for (size_t i = 0; i < forms.size(); ++i) { - blink::WebFormElement fe = forms[i]; + for (size_t i = 0; i < forms.size(); ++i) { + blink::WebFormElement fe = forms[i]; - GURL full_action(f->document().completeURL(fe.action())); - if (full_action.is_empty()) { - // The default action URL is the form's origin. - full_action = full_origin; - } - - // Action URL must match. - if (data.action != full_action.ReplaceComponents(rep)) - continue; - - scoped_ptr<FormElements> curr_elements(new FormElements); - if (!FindFormInputElements(&fe, data, curr_elements.get())) - continue; - - // We found the right element. - // Note: this assignment adds a reference to |fe|. - curr_elements->form_element = fe; - results->push_back(curr_elements.release()); + GURL full_action(doc.completeURL(fe.action())); + if (full_action.is_empty()) { + // The default action URL is the form's origin. + full_action = full_origin; } + + // Action URL must match. + if (data.action != full_action.ReplaceComponents(rep)) + continue; + + scoped_ptr<FormElements> curr_elements(new FormElements); + if (!FindFormInputElements(&fe, data, curr_elements.get())) + continue; + + // We found the right element. + // Note: this assignment adds a reference to |fe|. + curr_elements->form_element = fe; + results->push_back(curr_elements.release()); } } @@ -433,10 +427,10 @@ //////////////////////////////////////////////////////////////////////////////// // PasswordAutofillAgent, public: -PasswordAutofillAgent::PasswordAutofillAgent(content::RenderView* render_view) - : content::RenderViewObserver(render_view), +PasswordAutofillAgent::PasswordAutofillAgent(content::RenderFrame* render_frame) + : content::RenderFrameObserver(render_frame), + legacy_(render_frame->GetRenderView(), this), usernames_usage_(NOTHING_TO_AUTOFILL), - web_view_(render_view->GetWebView()), logging_state_active_(false), was_username_autofilled_(false), was_password_autofilled_(false), @@ -531,6 +525,8 @@ // TODO(vabr): Get a mutable argument instead. http://crbug.com/397083 blink::WebInputElement mutable_element = element; // We need a non-const. + DCHECK_EQ(element.document().frame(), render_frame()->GetWebFrame()); + if (element.isPasswordField()) { // Some login forms have event handlers that put a hash of the password into // a hidden field and then clear the password (http://crbug.com/28910, @@ -538,10 +534,7 @@ // handlers run, so save away a copy of the password in case it gets lost. // To honor the user having explicitly cleared the password, even an empty // password will be saved here. - if (blink::WebLocalFrame* element_frame = element.document().frame()) { - ProvisionallySavePassword( - element_frame, element.form(), RESTRICTION_NONE); - } + ProvisionallySavePassword(element.form(), RESTRICTION_NONE); PasswordToLoginMap::iterator iter = password_to_username_.find(element); if (iter != password_to_username_.end()) { @@ -702,16 +695,15 @@ return origin.canAccessPasswordManager(); } -void PasswordAutofillAgent::OnDynamicFormsSeen(blink::WebFrame* frame) { - SendPasswordForms(frame, false /* only_visible */); +void PasswordAutofillAgent::OnDynamicFormsSeen() { + SendPasswordForms(false /* only_visible */); } void PasswordAutofillAgent::FirstUserGestureObserved() { gatekeeper_.OnUserGesture(); } -void PasswordAutofillAgent::SendPasswordForms(blink::WebFrame* frame, - bool only_visible) { +void PasswordAutofillAgent::SendPasswordForms(bool only_visible) { scoped_ptr<RendererSavePasswordProgressLogger> logger; if (logging_state_active_) { logger.reset(new RendererSavePasswordProgressLogger(this, routing_id())); @@ -719,6 +711,7 @@ logger->LogBoolean(Logger::STRING_ONLY_VISIBLE, only_visible); } + blink::WebFrame* frame = render_frame()->GetWebFrame(); // Make sure that this security origin is allowed to use password manager. blink::WebSecurityOrigin origin = frame->document().securityOrigin(); if (logger) { @@ -795,29 +788,32 @@ return handled; } -void PasswordAutofillAgent::DidStartLoading() { - did_stop_loading_ = false; - if (usernames_usage_ != NOTHING_TO_AUTOFILL) { - UMA_HISTOGRAM_ENUMERATION("PasswordManager.OtherPossibleUsernamesUsage", - usernames_usage_, - OTHER_POSSIBLE_USERNAMES_MAX); - usernames_usage_ = NOTHING_TO_AUTOFILL; - } -} - -void PasswordAutofillAgent::DidFinishDocumentLoad(blink::WebLocalFrame* frame) { +void PasswordAutofillAgent::DidFinishDocumentLoad() { // The |frame| contents have been parsed, but not yet rendered. Let the // PasswordManager know that forms are loaded, even though we can't yet tell // whether they're visible. - SendPasswordForms(frame, false); + SendPasswordForms(false); } -void PasswordAutofillAgent::DidFinishLoad(blink::WebLocalFrame* frame) { +void PasswordAutofillAgent::DidFinishLoad() { // The |frame| contents have been rendered. Let the PasswordManager know // which of the loaded frames are actually visible to the user. This also // triggers the "Save password?" infobar if the user just submitted a password // form. - SendPasswordForms(frame, true); + SendPasswordForms(true); +} + +void PasswordAutofillAgent::FrameWillClose() { + FrameClosing(); +} + +void PasswordAutofillAgent::DidStartLoading() { + did_stop_loading_ = false; + if (usernames_usage_ != NOTHING_TO_AUTOFILL) { + UMA_HISTOGRAM_ENUMERATION("PasswordManager.OtherPossibleUsernamesUsage", + usernames_usage_, OTHER_POSSIBLE_USERNAMES_MAX); + usernames_usage_ = NOTHING_TO_AUTOFILL; + } } void PasswordAutofillAgent::DidStopLoading() { @@ -825,35 +821,36 @@ } void PasswordAutofillAgent::FrameDetached(blink::WebFrame* frame) { - FrameClosing(frame); -} - -void PasswordAutofillAgent::FrameWillClose(blink::WebFrame* frame) { - FrameClosing(frame); + if (frame == render_frame()->GetWebFrame()) + FrameClosing(); } void PasswordAutofillAgent::WillSendSubmitEvent( blink::WebLocalFrame* frame, const blink::WebFormElement& form) { + if (frame != render_frame()->GetWebFrame()) + return; // Forms submitted via XHR are not seen by WillSubmitForm if the default // onsubmit handler is overridden. Such submission first gets detected in // DidStartProvisionalLoad, which no longer knows about the particular form, - // and uses the candidate stored in |provisionally_saved_forms_|. + // and uses the candidate stored in |provisionally_saved_form_|. // - // User-typed password will get stored to |provisionally_saved_forms_| in + // User-typed password will get stored to |provisionally_saved_form_| in // TextDidChangeInTextField. Autofilled or JavaScript-copied passwords need to // be saved here. // // Only non-empty passwords are saved here. Empty passwords were likely // cleared by some scripts (http://crbug.com/28910, http://crbug.com/391693). - // Had the user cleared the password, |provisionally_saved_forms_| would + // Had the user cleared the password, |provisionally_saved_form_| would // already have been updated in TextDidChangeInTextField. - ProvisionallySavePassword(frame, form, RESTRICTION_NON_EMPTY_PASSWORD); + ProvisionallySavePassword(form, RESTRICTION_NON_EMPTY_PASSWORD); } void PasswordAutofillAgent::WillSubmitForm(blink::WebLocalFrame* frame, const blink::WebFormElement& form) { - DCHECK(frame); + if (frame != render_frame()->GetWebFrame()) + return; + scoped_ptr<RendererSavePasswordProgressLogger> logger; if (logging_state_active_) { logger.reset(new RendererSavePasswordProgressLogger(this, routing_id())); @@ -873,17 +870,16 @@ logger->LogPasswordForm(Logger::STRING_CREATED_PASSWORD_FORM, *submitted_form); } - if (ContainsNonNullEntryForNonNullKey( - provisionally_saved_forms_, static_cast<blink::WebFrame*>(frame)) && - submitted_form->action == provisionally_saved_forms_[frame]->action) { + if (provisionally_saved_form_ && + submitted_form->action == provisionally_saved_form_->action) { if (logger) logger->LogMessage(Logger::STRING_SUBMITTED_PASSWORD_REPLACED); submitted_form->password_value = - provisionally_saved_forms_[frame]->password_value; + provisionally_saved_form_->password_value; submitted_form->new_password_value = - provisionally_saved_forms_[frame]->new_password_value; + provisionally_saved_form_->new_password_value; submitted_form->username_value = - provisionally_saved_forms_[frame]->username_value; + provisionally_saved_form_->username_value; } // Some observers depend on sending this information now instead of when @@ -892,117 +888,80 @@ // we will never get to finish the load. Send(new AutofillHostMsg_PasswordFormSubmitted(routing_id(), *submitted_form)); - // Remove reference since we have already submitted this form. - provisionally_saved_forms_.erase(frame); + provisionally_saved_form_.reset(); } else if (logger) { logger->LogMessage(Logger::STRING_FORM_IS_NOT_PASSWORD); } } -blink::WebFrame* PasswordAutofillAgent::CurrentOrChildFrameWithSavedForms( - const blink::WebFrame* current_frame) { - for (FrameToPasswordFormMap::const_iterator it = - provisionally_saved_forms_.begin(); - it != provisionally_saved_forms_.end(); - ++it) { - blink::WebFrame* form_frame = it->first; - // The check that the returned frame is related to |current_frame| is mainly - // for double-checking. There should not be any unrelated frames in - // |provisionally_saved_forms_|, because the map is cleared after - // navigation. If there are reasons to remove this check in the future and - // keep just the first frame found, it might be a good idea to add a UMA - // statistic or a similar check on how many frames are here to choose from. - if (current_frame == form_frame || - current_frame->findChildByName(form_frame->assignedName())) { - return form_frame; - } - } - return NULL; -} - -void PasswordAutofillAgent::DidStartProvisionalLoad( - blink::WebLocalFrame* frame) { +void PasswordAutofillAgent::LegacyDidStartProvisionalLoad( + blink::WebLocalFrame* navigated_frame) { scoped_ptr<RendererSavePasswordProgressLogger> logger; if (logging_state_active_) { logger.reset(new RendererSavePasswordProgressLogger(this, routing_id())); logger->LogMessage(Logger::STRING_DID_START_PROVISIONAL_LOAD_METHOD); } - if (!frame->parent()) { - // If the navigation is not triggered by a user gesture, e.g. by some ajax - // callback, then inherit the submitted password form from the previous - // state. This fixes the no password save issue for ajax login, tracked in - // [http://crbug/43219]. Note that this still fails for sites that use - // synchonous XHR as isProcessingUserGesture() will return true. - blink::WebFrame* form_frame = CurrentOrChildFrameWithSavedForms(frame); - if (logger) { - logger->LogBoolean(Logger::STRING_FORM_FRAME_EQ_FRAME, - form_frame == frame); - } - // Bug fix for crbug.com/368690. isProcessingUserGesture() is false when - // the user is performing actions outside the page (e.g. typed url, - // history navigation). We don't want to trigger saving in these cases. - content::DocumentState* document_state = - content::DocumentState::FromDataSource( - frame->provisionalDataSource()); - content::NavigationState* navigation_state = - document_state->navigation_state(); - if (ui::PageTransitionIsWebTriggerable( - navigation_state->transition_type()) && - !blink::WebUserGestureIndicator::isProcessingUserGesture()) { - // If onsubmit has been called, try and save that form. - if (ContainsNonNullEntryForNonNullKey(provisionally_saved_forms_, - form_frame)) { - if (logger) { - logger->LogPasswordForm( - Logger::STRING_PROVISIONALLY_SAVED_FORM_FOR_FRAME, - *provisionally_saved_forms_[form_frame]); - } - Send(new AutofillHostMsg_PasswordFormSubmitted( - routing_id(), *provisionally_saved_forms_[form_frame])); - provisionally_saved_forms_.erase(form_frame); - } else { - // Loop through the forms on the page looking for one that has been - // filled out. If one exists, try and save the credentials. - blink::WebVector<blink::WebFormElement> forms; - frame->document().forms(forms); - - bool password_forms_found = false; - for (size_t i = 0; i < forms.size(); ++i) { - blink::WebFormElement form_element = forms[i]; - if (logger) { - LogHTMLForm( - logger.get(), Logger::STRING_FORM_FOUND_ON_PAGE, form_element); - } - scoped_ptr<PasswordForm> password_form( - CreatePasswordForm(form_element)); - if (password_form.get() && !password_form->username_value.empty() && - FormContainsNonDefaultPasswordValue( - *password_form, form_element)) { - password_forms_found = true; - if (logger) { - logger->LogPasswordForm( - Logger::STRING_PASSWORD_FORM_FOUND_ON_PAGE, *password_form); - } - Send(new AutofillHostMsg_PasswordFormSubmitted(routing_id(), - *password_form)); - } - } - if (!password_forms_found && logger) { - logger->LogMessage(Logger::STRING_PASSWORD_FORM_NOT_FOUND_ON_PAGE); - } - } - } - // Clear the whole map during main frame navigation. - provisionally_saved_forms_.clear(); - - // This is a new navigation, so require a new user gesture before filling in - // passwords. - gatekeeper_.Reset(); - } else { + if (navigated_frame->parent()) { if (logger) logger->LogMessage(Logger::STRING_FRAME_NOT_MAIN_FRAME); + return; } + + // Bug fix for crbug.com/368690. isProcessingUserGesture() is false when + // the user is performing actions outside the page (e.g. typed url, + // history navigation). We don't want to trigger saving in these cases. + content::DocumentState* document_state = + content::DocumentState::FromDataSource( + navigated_frame->provisionalDataSource()); + content::NavigationState* navigation_state = + document_state->navigation_state(); + if (ui::PageTransitionIsWebTriggerable(navigation_state->transition_type()) && + !blink::WebUserGestureIndicator::isProcessingUserGesture()) { + // If onsubmit has been called, try and save that form. + if (provisionally_saved_form_) { + if (logger) { + logger->LogPasswordForm( + Logger::STRING_PROVISIONALLY_SAVED_FORM_FOR_FRAME, + *provisionally_saved_form_); + } + Send(new AutofillHostMsg_PasswordFormSubmitted( + routing_id(), *provisionally_saved_form_)); + provisionally_saved_form_.reset(); + } else { + // Loop through the forms on the page looking for one that has been + // filled out. If one exists, try and save the credentials. + blink::WebVector<blink::WebFormElement> forms; + render_frame()->GetWebFrame()->document().forms(forms); + + bool password_forms_found = false; + for (size_t i = 0; i < forms.size(); ++i) { + blink::WebFormElement form_element = forms[i]; + if (logger) { + LogHTMLForm(logger.get(), Logger::STRING_FORM_FOUND_ON_PAGE, + form_element); + } + scoped_ptr<PasswordForm> password_form( + CreatePasswordForm(form_element)); + if (password_form.get() && !password_form->username_value.empty() && + FormContainsNonDefaultPasswordValue(*password_form, form_element)) { + password_forms_found = true; + if (logger) { + logger->LogPasswordForm(Logger::STRING_PASSWORD_FORM_FOUND_ON_PAGE, + *password_form); + } + Send(new AutofillHostMsg_PasswordFormSubmitted(routing_id(), + *password_form)); + } + } + if (!password_forms_found && logger) + logger->LogMessage(Logger::STRING_PASSWORD_FORM_NOT_FOUND_ON_PAGE); + } + } + + // This is a new navigation, so require a new user gesture before filling in + // passwords. + gatekeeper_.Reset(); } void PasswordAutofillAgent::OnFillPasswordForm( @@ -1017,7 +976,7 @@ FormElementsList forms; // We own the FormElements* in forms. - FindFormElements(render_view()->GetWebView(), form_data, &forms); + FindFormElements(render_frame(), form_data, &forms); FormElementsList::iterator iter; for (iter = forms.begin(); iter != forms.end(); ++iter) { scoped_ptr<FormElements> form_elements(*iter); @@ -1102,7 +1061,8 @@ login_to_password_info_key_.find(user_input); DCHECK(key_it != login_to_password_info_key_.end()); - float scale = web_view_->pageScaleFactor(); + float scale = + render_frame()->GetRenderView()->GetWebView()->pageScaleFactor(); gfx::RectF bounding_box_scaled(bounding_box.x() * scale, bounding_box.y() * scale, bounding_box.width() * scale, @@ -1155,27 +1115,13 @@ #endif } -void PasswordAutofillAgent::FrameClosing(const blink::WebFrame* frame) { - for (LoginToPasswordInfoMap::iterator iter = login_to_password_info_.begin(); - iter != login_to_password_info_.end();) { - // There may not be a username field, so get the frame from the password - // field. - if (iter->second.password_field.document().frame() == frame) { - login_to_password_info_key_.erase(iter->first); - password_to_username_.erase(iter->second.password_field); - login_to_password_info_.erase(iter++); - } else { - ++iter; - } +void PasswordAutofillAgent::FrameClosing() { + for (auto const& iter : login_to_password_info_) { + login_to_password_info_key_.erase(iter.first); + password_to_username_.erase(iter.second.password_field); } - for (FrameToPasswordFormMap::iterator iter = - provisionally_saved_forms_.begin(); - iter != provisionally_saved_forms_.end();) { - if (iter->first == frame) - provisionally_saved_forms_.erase(iter++); - else - ++iter; - } + login_to_password_info_.clear(); + provisionally_saved_form_.reset(); } bool PasswordAutofillAgent::FindLoginInfo(const blink::WebNode& node, @@ -1214,24 +1160,61 @@ } void PasswordAutofillAgent::ProvisionallySavePassword( - blink::WebLocalFrame* frame, const blink::WebFormElement& form, ProvisionallySaveRestriction restriction) { - // TODO(vabr): This is just to stop getting a NULL frame in - // |provisionally_saved_forms_|. Cases where we try to save password for a - // form in a NULL frame should not happen, and it's currently unclear how they - // happen (http://crbug.com/420519). This thing will be hopefully solved by - // migrating the PasswordAutofillAgent to observe frames directly - // (http://crbug.com/400186). - if (!frame) - return; scoped_ptr<PasswordForm> password_form(CreatePasswordForm(form)); if (!password_form || (restriction == RESTRICTION_NON_EMPTY_PASSWORD && password_form->password_value.empty() && password_form->new_password_value.empty())) { return; } - provisionally_saved_forms_[frame].reset(password_form.release()); + provisionally_saved_form_ = password_form.Pass(); +} + +// LegacyPasswordAutofillAgent ------------------------------------------------- + +PasswordAutofillAgent::LegacyPasswordAutofillAgent::LegacyPasswordAutofillAgent( + content::RenderView* render_view, + PasswordAutofillAgent* agent) + : content::RenderViewObserver(render_view), agent_(agent) { +} + +PasswordAutofillAgent::LegacyPasswordAutofillAgent:: + ~LegacyPasswordAutofillAgent() { +} + +void PasswordAutofillAgent::LegacyPasswordAutofillAgent::OnDestruct() { + // No op. Do not delete |this|. +} + +void PasswordAutofillAgent::LegacyPasswordAutofillAgent::DidStartLoading() { + agent_->DidStartLoading(); +} + +void PasswordAutofillAgent::LegacyPasswordAutofillAgent::DidStopLoading() { + agent_->DidStopLoading(); +} + +void PasswordAutofillAgent::LegacyPasswordAutofillAgent:: + DidStartProvisionalLoad(blink::WebLocalFrame* navigated_frame) { + agent_->LegacyDidStartProvisionalLoad(navigated_frame); +} + +void PasswordAutofillAgent::LegacyPasswordAutofillAgent::FrameDetached( + blink::WebFrame* frame) { + agent_->FrameDetached(frame); +} + +void PasswordAutofillAgent::LegacyPasswordAutofillAgent::WillSendSubmitEvent( + blink::WebLocalFrame* frame, + const blink::WebFormElement& form) { + agent_->WillSendSubmitEvent(frame, form); +} + +void PasswordAutofillAgent::LegacyPasswordAutofillAgent::WillSubmitForm( + blink::WebLocalFrame* frame, + const blink::WebFormElement& form) { + agent_->WillSubmitForm(frame, form); } } // namespace autofill
diff --git a/components/autofill/content/renderer/password_autofill_agent.h b/components/autofill/content/renderer/password_autofill_agent.h index 99f2a94..d03808f6 100644 --- a/components/autofill/content/renderer/password_autofill_agent.h +++ b/components/autofill/content/renderer/password_autofill_agent.h
@@ -8,9 +8,11 @@ #include <map> #include <vector> -#include "base/memory/linked_ptr.h" +#include "base/gtest_prod_util.h" +#include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "components/autofill/core/common/password_form_fill_data.h" +#include "content/public/renderer/render_frame_observer.h" #include "content/public/renderer/render_view_observer.h" #include "third_party/WebKit/public/web/WebInputElement.h" @@ -24,13 +26,12 @@ namespace autofill { // This class is responsible for filling password forms. -// There is one PasswordAutofillAgent per RenderView. -class PasswordAutofillAgent : public content::RenderViewObserver { +class PasswordAutofillAgent : public content::RenderFrameObserver { public: - explicit PasswordAutofillAgent(content::RenderView* render_view); + explicit PasswordAutofillAgent(content::RenderFrame* render_frame); ~PasswordAutofillAgent() override; - // WebViewClient editor related calls forwarded by the RenderView. + // WebFrameClient editor related calls forwarded by AutofillAgent. // If they return true, it indicates the event was consumed and should not // be used for any other autofill activity. bool TextFieldDidEndEditing(const blink::WebInputElement& element); @@ -54,6 +55,7 @@ // their previous filled state. Return false if no login information was // found for the form. bool DidClearAutofillSelection(const blink::WebNode& node); + // Shows an Autofill popup with username suggestions for |element|. If // |show_all| is |true|, will show all possible suggestions for that element, // otherwise shows suggestions based on current value of |element|. @@ -61,7 +63,7 @@ bool ShowSuggestions(const blink::WebInputElement& element, bool show_all); // Called when new form controls are inserted. - void OnDynamicFormsSeen(blink::WebFrame* frame); + void OnDynamicFormsSeen(); // Called when the user first interacts with the page after a load. This is a // signal to make autofilled values of password input elements accessible to @@ -100,8 +102,6 @@ typedef std::map<blink::WebElement, PasswordInfo> LoginToPasswordInfoMap; typedef std::map<blink::WebElement, int> LoginToPasswordInfoKeyMap; typedef std::map<blink::WebElement, blink::WebElement> PasswordToLoginMap; - typedef std::map<blink::WebFrame*, - linked_ptr<PasswordForm> > FrameToPasswordFormMap; // This class keeps track of autofilled password input elements and makes sure // the autofilled password value is not accessible to JavaScript code until @@ -132,19 +132,57 @@ DISALLOW_COPY_AND_ASSIGN(PasswordValueGatekeeper); }; - // RenderViewObserver: + // Thunk class for RenderViewObserver methods that haven't yet been migrated + // to RenderFrameObserver. Should eventually be removed. + // http://crbug.com/433486 + class LegacyPasswordAutofillAgent : public content::RenderViewObserver { + public: + LegacyPasswordAutofillAgent(content::RenderView* render_view, + PasswordAutofillAgent* agent); + ~LegacyPasswordAutofillAgent() override; + + // RenderViewObserver: + void OnDestruct() override; + void DidStartLoading() override; + void DidStopLoading() override; + void DidStartProvisionalLoad(blink::WebLocalFrame* frame) override; + void FrameDetached(blink::WebFrame* frame) override; + void WillSendSubmitEvent(blink::WebLocalFrame* frame, + const blink::WebFormElement& form) override; + void WillSubmitForm(blink::WebLocalFrame* frame, + const blink::WebFormElement& form) override; + + private: + PasswordAutofillAgent* agent_; + + DISALLOW_COPY_AND_ASSIGN(LegacyPasswordAutofillAgent); + }; + friend class LegacyPasswordAutofillAgent; + FRIEND_TEST_ALL_PREFIXES( + PasswordAutofillAgentTest, + RememberLastNonEmptyUsernameAndPasswordOnSubmit_ScriptCleared); + FRIEND_TEST_ALL_PREFIXES( + PasswordAutofillAgentTest, + RememberLastNonEmptyUsernameAndPasswordOnSubmit_UserCleared); + FRIEND_TEST_ALL_PREFIXES( + PasswordAutofillAgentTest, + RememberLastNonEmptyUsernameAndPasswordOnSubmit_New); + + // RenderFrameObserver: bool OnMessageReceived(const IPC::Message& message) override; - void DidStartProvisionalLoad(blink::WebLocalFrame* frame) override; - void DidStartLoading() override; - void DidFinishDocumentLoad(blink::WebLocalFrame* frame) override; - void DidFinishLoad(blink::WebLocalFrame* frame) override; - void DidStopLoading() override; - void FrameDetached(blink::WebFrame* frame) override; - void FrameWillClose(blink::WebFrame* frame) override; + void DidFinishDocumentLoad() override; + void DidFinishLoad() override; + void FrameWillClose() override; + + // Legacy RenderViewObserver: + void DidStartLoading(); + void DidStopLoading(); + void LegacyDidStartProvisionalLoad(blink::WebLocalFrame* frame); + void FrameDetached(blink::WebFrame* frame); void WillSendSubmitEvent(blink::WebLocalFrame* frame, - const blink::WebFormElement& form) override; + const blink::WebFormElement& form); void WillSubmitForm(blink::WebLocalFrame* frame, - const blink::WebFormElement& form) override; + const blink::WebFormElement& form); // RenderView IPC handlers: void OnFillPasswordForm(int key, const PasswordFormFillData& form_data); @@ -152,7 +190,7 @@ // Scans the given frame for password forms and sends them up to the browser. // If |only_visible| is true, only forms visible in the layout are sent. - void SendPasswordForms(blink::WebFrame* frame, bool only_visible); + void SendPasswordForms(bool only_visible); bool ShowSuggestionPopup(const PasswordFormFillData& fill_data, const blink::WebInputElement& user_input, @@ -165,9 +203,8 @@ const blink::WebInputElement& password, const PasswordFormFillData& fill_data); - // Invoked when the passed frame is closing. Gives us a chance to clear any - // reference we may have to elements in that frame. - void FrameClosing(const blink::WebFrame* frame); + // Invoked when the frame is closing. + void FrameClosing(); // Finds login information for a |node| that was previously filled. bool FindLoginInfo(const blink::WebNode& node, @@ -179,17 +216,14 @@ void ClearPreview(blink::WebInputElement* username, blink::WebInputElement* password); - // If |provisionally_saved_forms_| contains a form for |current_frame| or its - // children, return such frame. - blink::WebFrame* CurrentOrChildFrameWithSavedForms( - const blink::WebFrame* current_frame); - // Extracts a PasswordForm from |form| and saves it as - // |provisionally_saved_forms_[frame]|, as long as it satisfies |restriction|. - void ProvisionallySavePassword(blink::WebLocalFrame* frame, - const blink::WebFormElement& form, + // |provisionally_saved_form_|, as long as it satisfies |restriction|. + void ProvisionallySavePassword(const blink::WebFormElement& form, ProvisionallySaveRestriction restriction); + // Passes through |RenderViewObserver| method to |this|. + LegacyPasswordAutofillAgent legacy_; + // The logins we have filled so far with their associated info. LoginToPasswordInfoMap login_to_password_info_; // And the keys under which PasswordAutofillManager can find the same info. @@ -205,7 +239,7 @@ // Set if the user might be submitting a password form on the current page, // but the submit may still fail (i.e. doesn't pass JavaScript validation). - FrameToPasswordFormMap provisionally_saved_forms_; + scoped_ptr<PasswordForm> provisionally_saved_form_; PasswordValueGatekeeper gatekeeper_;
diff --git a/components/autofill/content/renderer/password_generation_agent.cc b/components/autofill/content/renderer/password_generation_agent.cc index 4585119..df2a7b56 100644 --- a/components/autofill/content/renderer/password_generation_agent.cc +++ b/components/autofill/content/renderer/password_generation_agent.cc
@@ -14,6 +14,7 @@ #include "components/autofill/core/common/form_data.h" #include "components/autofill/core/common/password_form.h" #include "components/autofill/core/common/password_generation_util.h" +#include "content/public/renderer/render_frame.h" #include "content/public/renderer/render_view.h" #include "google_apis/gaia/gaia_urls.h" #include "third_party/WebKit/public/platform/WebVector.h" @@ -104,9 +105,8 @@ } // namespace PasswordGenerationAgent::PasswordGenerationAgent( - content::RenderView* render_view) - : content::RenderViewObserver(render_view), - render_view_(render_view), + content::RenderFrame* render_frame) + : content::RenderFrameObserver(render_frame), password_is_generated_(false), password_edited_(false), generation_popup_shown_(false), @@ -116,8 +116,10 @@ } PasswordGenerationAgent::~PasswordGenerationAgent() {} -void PasswordGenerationAgent::DidFinishDocumentLoad( - blink::WebLocalFrame* frame) { +void PasswordGenerationAgent::DidFinishDocumentLoad() { + if (render_frame()->GetWebFrame()->parent()) + return; + // In every navigation, the IPC message sent by the password autofill manager // to query whether the current form is blacklisted or not happens when the // document load finishes, so we need to clear previous states here before we @@ -125,58 +127,55 @@ // as we don't want subframe loads to clear state that we have received from // the main frame. Note that we assume there is only one account creation // form, but there could be multiple password forms in each frame. - if (!frame->parent()) { - not_blacklisted_password_form_origins_.clear(); - generation_enabled_forms_.clear(); - generation_element_.reset(); - possible_account_creation_form_.reset(new PasswordForm()); + not_blacklisted_password_form_origins_.clear(); + generation_enabled_forms_.clear(); + generation_element_.reset(); + possible_account_creation_form_.reset(new PasswordForm()); - // Log statistics after navigation so that we only log once per page. - if (password_elements_.empty()) { - password_generation::LogPasswordGenerationEvent( - password_generation::NO_SIGN_UP_DETECTED); - } else { - password_generation::LogPasswordGenerationEvent( - password_generation::SIGN_UP_DETECTED); - } - password_elements_.clear(); - password_is_generated_ = false; - if (password_edited_) { - password_generation::LogPasswordGenerationEvent( - password_generation::PASSWORD_EDITED); - } - password_edited_ = false; - - if (generation_popup_shown_) { - password_generation::LogPasswordGenerationEvent( - password_generation::GENERATION_POPUP_SHOWN); - } - generation_popup_shown_ = false; - - if (editing_popup_shown_) { - password_generation::LogPasswordGenerationEvent( - password_generation::EDITING_POPUP_SHOWN); - } - editing_popup_shown_ = false; + // Log statistics after navigation so that we only log once per page. + if (password_elements_.empty()) { + password_generation::LogPasswordGenerationEvent( + password_generation::NO_SIGN_UP_DETECTED); + } else { + password_generation::LogPasswordGenerationEvent( + password_generation::SIGN_UP_DETECTED); } + password_elements_.clear(); + password_is_generated_ = false; + if (password_edited_) { + password_generation::LogPasswordGenerationEvent( + password_generation::PASSWORD_EDITED); + } + password_edited_ = false; + + if (generation_popup_shown_) { + password_generation::LogPasswordGenerationEvent( + password_generation::GENERATION_POPUP_SHOWN); + } + generation_popup_shown_ = false; + + if (editing_popup_shown_) { + password_generation::LogPasswordGenerationEvent( + password_generation::EDITING_POPUP_SHOWN); + } + editing_popup_shown_ = false; } -void PasswordGenerationAgent::OnDynamicFormsSeen(blink::WebLocalFrame* frame) { - FindPossibleGenerationForm(frame); +void PasswordGenerationAgent::OnDynamicFormsSeen() { + FindPossibleGenerationForm(); } -void PasswordGenerationAgent::DidFinishLoad(blink::WebLocalFrame* frame) { - FindPossibleGenerationForm(frame); +void PasswordGenerationAgent::DidFinishLoad() { + FindPossibleGenerationForm(); } -void PasswordGenerationAgent::FindPossibleGenerationForm( - blink::WebLocalFrame* frame) { +void PasswordGenerationAgent::FindPossibleGenerationForm() { if (!enabled_) return; // We don't want to generate passwords if the browser won't store or sync // them. - if (!ShouldAnalyzeDocument(frame->document())) + if (!ShouldAnalyzeDocument()) return; // If we have already found a signup form for this page, no need to continue. @@ -184,7 +183,7 @@ return; blink::WebVector<blink::WebFormElement> forms; - frame->document().forms(forms); + render_frame()->GetWebFrame()->document().forms(forms); for (size_t i = 0; i < forms.size(); ++i) { if (forms[i].isNull()) continue; @@ -216,11 +215,11 @@ } } -bool PasswordGenerationAgent::ShouldAnalyzeDocument( - const blink::WebDocument& document) const { +bool PasswordGenerationAgent::ShouldAnalyzeDocument() const { // Make sure that this security origin is allowed to use password manager. // Generating a password that can't be saved is a bad idea. - blink::WebSecurityOrigin origin = document.securityOrigin(); + blink::WebSecurityOrigin origin = + render_frame()->GetWebFrame()->document().securityOrigin(); if (!origin.canAccessPasswordManager()) { DVLOG(1) << "No PasswordManager access"; return false; @@ -260,7 +259,7 @@ it->setAutofilled(true); // Advance focus to the next input field. We assume password fields in // an account creation form are always adjacent. - render_view_->GetWebView()->advanceFocus(false); + render_frame()->GetRenderView()->GetWebView()->advanceFocus(false); } } @@ -379,9 +378,9 @@ } void PasswordGenerationAgent::ShowGenerationPopup() { - gfx::RectF bounding_box_scaled = - GetScaledBoundingBox(render_view_->GetWebView()->pageScaleFactor(), - &generation_element_); + gfx::RectF bounding_box_scaled = GetScaledBoundingBox( + render_frame()->GetRenderView()->GetWebView()->pageScaleFactor(), + &generation_element_); Send(new AutofillHostMsg_ShowPasswordGenerationPopup( routing_id(), @@ -393,9 +392,9 @@ } void PasswordGenerationAgent::ShowEditingPopup() { - gfx::RectF bounding_box_scaled = - GetScaledBoundingBox(render_view_->GetWebView()->pageScaleFactor(), - &generation_element_); + gfx::RectF bounding_box_scaled = GetScaledBoundingBox( + render_frame()->GetRenderView()->GetWebView()->pageScaleFactor(), + &generation_element_); Send(new AutofillHostMsg_ShowPasswordEditingPopup( routing_id(),
diff --git a/components/autofill/content/renderer/password_generation_agent.h b/components/autofill/content/renderer/password_generation_agent.h index 97c5527..667308c 100644 --- a/components/autofill/content/renderer/password_generation_agent.h +++ b/components/autofill/content/renderer/password_generation_agent.h
@@ -10,7 +10,7 @@ #include <vector> #include "base/memory/scoped_ptr.h" -#include "content/public/renderer/render_view_observer.h" +#include "content/public/renderer/render_frame_observer.h" #include "third_party/WebKit/public/web/WebInputElement.h" #include "url/gurl.h" @@ -26,9 +26,9 @@ // This class is responsible for controlling communication for password // generation between the browser (which shows the popup and generates // passwords) and WebKit (shows the generation icon in the password field). -class PasswordGenerationAgent : public content::RenderViewObserver { +class PasswordGenerationAgent : public content::RenderFrameObserver { public: - explicit PasswordGenerationAgent(content::RenderView* render_view); + explicit PasswordGenerationAgent(content::RenderFrame* render_frame); ~PasswordGenerationAgent() override; // Returns true if the field being changed is one where a generated password @@ -39,15 +39,15 @@ bool FocusedNodeHasChanged(const blink::WebNode& node); // Called when new form controls are inserted. - void OnDynamicFormsSeen(blink::WebLocalFrame* frame); + void OnDynamicFormsSeen(); // The length that a password can be before the UI is hidden. static const size_t kMaximumOfferSize = 5; protected: - // Returns true if this document is one that we should consider analyzing. - // Virtual so that it can be overriden during testing. - virtual bool ShouldAnalyzeDocument(const blink::WebDocument& document) const; + // Returns true if the document for |render_frame()| is one that we should + // consider analyzing. Virtual so that it can be overriden during testing. + virtual bool ShouldAnalyzeDocument() const; // RenderViewObserver: bool OnMessageReceived(const IPC::Message& message) override; @@ -56,9 +56,9 @@ void set_enabled(bool enabled) { enabled_ = enabled; } private: - // RenderViewObserver: - void DidFinishDocumentLoad(blink::WebLocalFrame* frame) override; - void DidFinishLoad(blink::WebLocalFrame* frame) override; + // RenderFrameObserver: + void DidFinishDocumentLoad() override; + void DidFinishLoad() override; // Message handlers. void OnFormNotBlacklisted(const PasswordForm& form); @@ -68,7 +68,7 @@ // Helper function that will try and populate |password_elements_| and // |possible_account_creation_form_|. - void FindPossibleGenerationForm(blink::WebLocalFrame* frame); + void FindPossibleGenerationForm(); // Helper function to decide if |passwords_| contains password fields for // an account creation form. Sets |generation_element_| to the field that @@ -84,8 +84,6 @@ // Hides a password generation popup if one exists. void HidePopup(); - content::RenderView* render_view_; - // Stores the origin of the account creation form we detected. scoped_ptr<PasswordForm> possible_account_creation_form_;
diff --git a/components/autofill/content/renderer/test_password_autofill_agent.cc b/components/autofill/content/renderer/test_password_autofill_agent.cc index af2a543..394279f 100644 --- a/components/autofill/content/renderer/test_password_autofill_agent.cc +++ b/components/autofill/content/renderer/test_password_autofill_agent.cc
@@ -7,8 +7,9 @@ namespace autofill { TestPasswordAutofillAgent::TestPasswordAutofillAgent( - content::RenderView* render_view) - : PasswordAutofillAgent(render_view) {} + content::RenderFrame* render_frame) + : PasswordAutofillAgent(render_frame) { +} TestPasswordAutofillAgent::~TestPasswordAutofillAgent() {}
diff --git a/components/autofill/content/renderer/test_password_autofill_agent.h b/components/autofill/content/renderer/test_password_autofill_agent.h index ee0196b..afa8d78 100644 --- a/components/autofill/content/renderer/test_password_autofill_agent.h +++ b/components/autofill/content/renderer/test_password_autofill_agent.h
@@ -11,7 +11,7 @@ class TestPasswordAutofillAgent : public PasswordAutofillAgent { public: - explicit TestPasswordAutofillAgent(content::RenderView* render_view); + explicit TestPasswordAutofillAgent(content::RenderFrame* render_frame); ~TestPasswordAutofillAgent() override; private:
diff --git a/components/autofill/content/renderer/test_password_generation_agent.cc b/components/autofill/content/renderer/test_password_generation_agent.cc index 2e4adb9..996211b3 100644 --- a/components/autofill/content/renderer/test_password_generation_agent.cc +++ b/components/autofill/content/renderer/test_password_generation_agent.cc
@@ -7,8 +7,8 @@ namespace autofill { TestPasswordGenerationAgent::TestPasswordGenerationAgent( - content::RenderView* render_view) - : PasswordGenerationAgent(render_view) { + content::RenderFrame* render_frame) + : PasswordGenerationAgent(render_frame) { // Always enable when testing. set_enabled(true); } @@ -20,8 +20,7 @@ return PasswordGenerationAgent::OnMessageReceived(message); } -bool TestPasswordGenerationAgent::ShouldAnalyzeDocument( - const blink::WebDocument& document) const { +bool TestPasswordGenerationAgent::ShouldAnalyzeDocument() const { return true; }
diff --git a/components/autofill/content/renderer/test_password_generation_agent.h b/components/autofill/content/renderer/test_password_generation_agent.h index 633acf94..731dffd 100644 --- a/components/autofill/content/renderer/test_password_generation_agent.h +++ b/components/autofill/content/renderer/test_password_generation_agent.h
@@ -15,10 +15,10 @@ class TestPasswordGenerationAgent : public PasswordGenerationAgent { public: - explicit TestPasswordGenerationAgent(content::RenderView* render_view); + explicit TestPasswordGenerationAgent(content::RenderFrame* render_frame); ~TestPasswordGenerationAgent() override; - // content::RenderViewObserver implementation: + // content::RenderFrameObserver implementation: bool OnMessageReceived(const IPC::Message& message) override; bool Send(IPC::Message* message) override; @@ -30,7 +30,7 @@ // PasswordGenreationAgent implementation: // Always return true to allow loading of data URLs. - bool ShouldAnalyzeDocument(const blink::WebDocument& document) const override; + bool ShouldAnalyzeDocument() const override; private: ScopedVector<IPC::Message> messages_;
diff --git a/components/autofill/core/browser/autofill_client.h b/components/autofill/core/browser/autofill_client.h index 452c793b..e99a28e 100644 --- a/components/autofill/core/browser/autofill_client.h +++ b/components/autofill/core/browser/autofill_client.h
@@ -12,6 +12,10 @@ #include "base/memory/weak_ptr.h" #include "base/strings/string16.h" +namespace content { +class RenderFrameHost; +} + namespace gfx { class Rect; class RectF; @@ -119,12 +123,16 @@ // Pass the form structures to the password generation manager to detect // account creation forms. virtual void DetectAccountCreationForms( + content::RenderFrameHost* rfh, const std::vector<autofill::FormStructure*>& forms) = 0; // Inform the client that the field has been filled. virtual void DidFillOrPreviewField( const base::string16& autofilled_value, const base::string16& profile_full_name) = 0; + + // Informs the client that a user gesture has been observed. + virtual void OnFirstUserGestureObserved() = 0; }; } // namespace autofill
diff --git a/components/autofill/core/browser/autofill_driver.h b/components/autofill/core/browser/autofill_driver.h index 748ad6e..b690191 100644 --- a/components/autofill/core/browser/autofill_driver.h +++ b/components/autofill/core/browser/autofill_driver.h
@@ -61,6 +61,11 @@ // Pings renderer. The renderer will return an IPC acknowledging the ping. virtual void PingRenderer() = 0; + // Pass the form structures to the password generation manager to detect + // account creation forms. + virtual void DetectAccountCreationForms( + const std::vector<autofill::FormStructure*>& forms) = 0; + // Sends the field type predictions specified in |forms| to the renderer. This // method is a no-op if the renderer is not available or the appropriate // command-line flag is not set.
diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc index b1f3ad6..be7ce13 100644 --- a/components/autofill/core/browser/autofill_manager.cc +++ b/components/autofill/core/browser/autofill_manager.cc
@@ -684,7 +684,7 @@ // Forward form structures to the password generation manager to detect // account creation forms. - client_->DetectAccountCreationForms(form_structures_.get()); + driver_->DetectAccountCreationForms(form_structures_.get()); // If the corresponding flag is set, annotate forms with the predicted types. driver_->SendAutofillTypePredictionsToRenderer(form_structures_.get());
diff --git a/components/autofill/core/browser/autofill_manager.h b/components/autofill/core/browser/autofill_manager.h index 326dd8b..44ddc3ab 100644 --- a/components/autofill/core/browser/autofill_manager.h +++ b/components/autofill/core/browser/autofill_manager.h
@@ -54,7 +54,7 @@ struct FormFieldData; // Manages saving and restoring the user's personal information entered into web -// forms. +// forms. One per frame; owned by the AutofillDriver. class AutofillManager : public AutofillDownloadManager::Observer { public: enum AutofillDownloadManagerState {
diff --git a/components/autofill/core/browser/test_autofill_client.cc b/components/autofill/core/browser/test_autofill_client.cc index 6a2b1ae..53adfd8c 100644 --- a/components/autofill/core/browser/test_autofill_client.cc +++ b/components/autofill/core/browser/test_autofill_client.cc
@@ -73,6 +73,7 @@ } void TestAutofillClient::DetectAccountCreationForms( + content::RenderFrameHost* rfh, const std::vector<autofill::FormStructure*>& forms) { } @@ -81,4 +82,7 @@ const base::string16& profile_full_name) { } +void TestAutofillClient::OnFirstUserGestureObserved() { +} + } // namespace autofill
diff --git a/components/autofill/core/browser/test_autofill_client.h b/components/autofill/core/browser/test_autofill_client.h index f3d8328..5266d8b 100644 --- a/components/autofill/core/browser/test_autofill_client.h +++ b/components/autofill/core/browser/test_autofill_client.h
@@ -45,12 +45,12 @@ const std::vector<base::string16>& labels) override; void HideAutofillPopup() override; bool IsAutocompleteEnabled() override; - void DetectAccountCreationForms( + content::RenderFrameHost* rfh, const std::vector<autofill::FormStructure*>& forms) override; - void DidFillOrPreviewField(const base::string16& autofilled_value, const base::string16& profile_full_name) override; + void OnFirstUserGestureObserved() override; void SetPrefs(scoped_ptr<PrefService> prefs) { prefs_ = prefs.Pass(); }
diff --git a/components/autofill/core/browser/test_autofill_driver.cc b/components/autofill/core/browser/test_autofill_driver.cc index f67c1b1..76bb9d5 100644 --- a/components/autofill/core/browser/test_autofill_driver.cc +++ b/components/autofill/core/browser/test_autofill_driver.cc
@@ -39,7 +39,12 @@ const FormData& form_data) { } -void TestAutofillDriver::PingRenderer() {} +void TestAutofillDriver::PingRenderer() { +} + +void TestAutofillDriver::DetectAccountCreationForms( + const std::vector<autofill::FormStructure*>& forms) { +} void TestAutofillDriver::SendAutofillTypePredictionsToRenderer( const std::vector<FormStructure*>& forms) {
diff --git a/components/autofill/core/browser/test_autofill_driver.h b/components/autofill/core/browser/test_autofill_driver.h index b1d2ccaf..11f06ff 100644 --- a/components/autofill/core/browser/test_autofill_driver.h +++ b/components/autofill/core/browser/test_autofill_driver.h
@@ -33,6 +33,8 @@ RendererFormDataAction action, const FormData& data) override; void PingRenderer() override; + void DetectAccountCreationForms( + const std::vector<autofill::FormStructure*>& forms) override; void SendAutofillTypePredictionsToRenderer( const std::vector<FormStructure*>& forms) override; void RendererShouldAcceptDataListSuggestion(
diff --git a/components/autofill/core/common/save_password_progress_logger.cc b/components/autofill/core/common/save_password_progress_logger.cc index d74997ad..ec7ffd3 100644 --- a/components/autofill/core/common/save_password_progress_logger.cc +++ b/components/autofill/core/common/save_password_progress_logger.cc
@@ -113,8 +113,6 @@ return "Submitted password replaced with the provisionally saved one"; case SavePasswordProgressLogger::STRING_DID_START_PROVISIONAL_LOAD_METHOD: return "PasswordAutofillAgent::DidStartProvisionalLoad"; - case SavePasswordProgressLogger::STRING_FORM_FRAME_EQ_FRAME: - return "form_frame == frame"; case SavePasswordProgressLogger::STRING_FRAME_NOT_MAIN_FRAME: return "|frame| is not the main frame"; case SavePasswordProgressLogger::STRING_PROVISIONALLY_SAVED_FORM_FOR_FRAME:
diff --git a/components/autofill/core/common/save_password_progress_logger.h b/components/autofill/core/common/save_password_progress_logger.h index c6c61d3..bfef6e39 100644 --- a/components/autofill/core/common/save_password_progress_logger.h +++ b/components/autofill/core/common/save_password_progress_logger.h
@@ -74,7 +74,6 @@ STRING_CREATED_PASSWORD_FORM, STRING_SUBMITTED_PASSWORD_REPLACED, STRING_DID_START_PROVISIONAL_LOAD_METHOD, - STRING_FORM_FRAME_EQ_FRAME, STRING_FRAME_NOT_MAIN_FRAME, STRING_PROVISIONALLY_SAVED_FORM_FOR_FRAME, STRING_PASSWORD_FORM_FOUND_ON_PAGE,
diff --git a/components/components_tests.gyp b/components/components_tests.gyp index 2f77866..4e798959 100644 --- a/components/components_tests.gyp +++ b/components/components_tests.gyp
@@ -189,6 +189,7 @@ 'password_manager/core/browser/password_form_manager_unittest.cc', 'password_manager/core/browser/password_generation_manager_unittest.cc', 'password_manager/core/browser/password_manager_unittest.cc', + 'password_manager/core/browser/password_manager_url_collection_experiment_unittest.cc', 'password_manager/core/browser/password_store_default_unittest.cc', 'password_manager/core/browser/password_store_unittest.cc', 'password_manager/core/browser/password_syncable_service_unittest.cc',
diff --git a/components/copresence/handlers/gcm_handler_impl.cc b/components/copresence/handlers/gcm_handler_impl.cc index 24b9d8c1..ccf7203 100644 --- a/components/copresence/handlers/gcm_handler_impl.cc +++ b/components/copresence/handlers/gcm_handler_impl.cc
@@ -47,14 +47,14 @@ : driver_(gcm_driver), directive_handler_(directive_handler), registration_callback_(base::Bind(&GCMHandlerImpl::RegistrationComplete, - AsWeakPtr())) { + base::Unretained(this))) { DCHECK(driver_); DCHECK(directive_handler_); driver_->AddAppHandler(kCopresenceAppId, this); driver_->Register(kCopresenceAppId, std::vector<std::string>(1, kCopresenceSenderId), - registration_callback_); + registration_callback_.callback()); } GCMHandlerImpl::~GCMHandlerImpl() {
diff --git a/components/copresence/handlers/gcm_handler_impl.h b/components/copresence/handlers/gcm_handler_impl.h index 3160d3e..6ce12b8f 100644 --- a/components/copresence/handlers/gcm_handler_impl.h +++ b/components/copresence/handlers/gcm_handler_impl.h
@@ -8,8 +8,8 @@ #include <string> #include <vector> -#include "base/callback.h" -#include "base/memory/weak_ptr.h" +#include "base/callback_forward.h" +#include "base/cancelable_callback.h" #include "components/copresence/handlers/gcm_handler.h" #include "components/gcm_driver/gcm_app_handler.h" #include "components/gcm_driver/gcm_client.h" @@ -24,8 +24,7 @@ // This class handles GCM messages from the Copresence server. class GCMHandlerImpl final : public GCMHandler, - public gcm::GCMAppHandler, - public base::SupportsWeakPtr<GCMHandlerImpl> { + public gcm::GCMAppHandler { public: // Callback to report that registration has completed. // Returns an empty ID if registration failed. @@ -67,13 +66,12 @@ gcm::GCMDriver* driver_; DirectiveHandler* const directive_handler_; - // TODO(ckehoe): Change this to a CancelableCallback. - base::Callback<void(const std::string&, - gcm::GCMClient::Result)> registration_callback_; - std::string gcm_id_; std::vector<RegistrationCallback> pending_id_requests_; + base::CancelableCallback<void(const std::string&, + gcm::GCMClient::Result)> registration_callback_; + DISALLOW_COPY_AND_ASSIGN(GCMHandlerImpl); };
diff --git a/components/copresence/mediums/audio/audio_manager_impl.cc b/components/copresence/mediums/audio/audio_manager_impl.cc index 281c037a..fadfdf9 100644 --- a/components/copresence/mediums/audio/audio_manager_impl.cc +++ b/components/copresence/mediums/audio/audio_manager_impl.cc
@@ -158,7 +158,7 @@ } const std::string AudioManagerImpl::GetToken(AudioType type) { - return playing_token_[type]; + return playing_[type] ? playing_token_[type] : ""; } bool AudioManagerImpl::IsRecording(AudioType type) {
diff --git a/components/copresence/mediums/audio/audio_recorder_unittest.cc b/components/copresence/mediums/audio/audio_recorder_unittest.cc index 08abe932..1884b81 100644 --- a/components/copresence/mediums/audio/audio_recorder_unittest.cc +++ b/components/copresence/mediums/audio/audio_recorder_unittest.cc
@@ -46,7 +46,7 @@ double GetMaxVolume() override { return 1.0; } void SetVolume(double volume) override {} double GetVolume() override { return 1.0; } - void SetAutomaticGainControl(bool enabled) override {} + bool SetAutomaticGainControl(bool enabled) override { return false; } bool GetAutomaticGainControl() override { return true; } bool IsMuted() override { return false; }
diff --git a/components/cronet/android/java/src/org/chromium/net/ChromiumUrlRequestContext.java b/components/cronet/android/java/src/org/chromium/net/ChromiumUrlRequestContext.java index dd0b426..07bcd9b 100644 --- a/components/cronet/android/java/src/org/chromium/net/ChromiumUrlRequestContext.java +++ b/components/cronet/android/java/src/org/chromium/net/ChromiumUrlRequestContext.java
@@ -82,10 +82,11 @@ } /** - * Starts NetLog logging to a file named |fileName| in the - * application temporary directory. |fileName| must not be empty. Log level - * is LOG_ALL_BUT_BYTES. If the file exists it is truncated before starting. - * If actively logging the call is ignored. + * Starts NetLog logging to a file. The NetLog log level used is + * LOG_ALL_BUT_BYTES. + * @param fileName The complete file path. It must not be empty. If file + * exists, it is truncated before starting. If actively logging, + * this method is ignored. */ public void startNetLogToFile(String fileName) { nativeStartNetLogToFile(mChromiumUrlRequestContextAdapter, fileName); @@ -93,7 +94,7 @@ /** * Stops NetLog logging and flushes file to disk. If a logging session is - * not in progress this call is ignored. + * not in progress, this call is ignored. */ public void stopNetLog() { nativeStopNetLog(mChromiumUrlRequestContextAdapter);
diff --git a/components/cronet/android/java/src/org/chromium/net/CronetUrlRequestContext.java b/components/cronet/android/java/src/org/chromium/net/CronetUrlRequestContext.java index 493004a9b..4c7afc6 100644 --- a/components/cronet/android/java/src/org/chromium/net/CronetUrlRequestContext.java +++ b/components/cronet/android/java/src/org/chromium/net/CronetUrlRequestContext.java
@@ -76,6 +76,16 @@ mUrlRequestContextAdapter = 0; } + @Override + public void startNetLogToFile(String fileName) { + nativeStartNetLogToFile(mUrlRequestContextAdapter, fileName); + } + + @Override + public void stopNetLog() { + nativeStopNetLog(mUrlRequestContextAdapter); + } + /** * Mark request as started to prevent shutdown when there are active * requests.
diff --git a/components/cronet/android/java/src/org/chromium/net/UrlRequestContext.java b/components/cronet/android/java/src/org/chromium/net/UrlRequestContext.java index e98e67b..54eee3f 100644 --- a/components/cronet/android/java/src/org/chromium/net/UrlRequestContext.java +++ b/components/cronet/android/java/src/org/chromium/net/UrlRequestContext.java
@@ -56,6 +56,21 @@ public abstract void shutdown(); /** + * Starts NetLog logging to a file. The NetLog log level used is + * LOG_ALL_BUT_BYTES. + * @param fileName The complete file path. It must not be empty. If file + * exists, it is truncated before starting. If actively logging, + * this method is ignored. + */ + public abstract void startNetLogToFile(String fileName); + + /** + * Stops NetLog logging and flushes file to disk. If a logging session is + * not in progress, this call is ignored. + */ + public abstract void stopNetLog(); + + /** * Create context with given config. If config.legacyMode is true, or * native library is not available, then creates HttpUrlConnection-based * context.
diff --git a/components/cronet/android/test/javatests/src/org/chromium/cronet_test_apk/CronetUrlRequestContextTest.java b/components/cronet/android/test/javatests/src/org/chromium/cronet_test_apk/CronetUrlRequestContextTest.java index 0964792..54230396 100644 --- a/components/cronet/android/test/javatests/src/org/chromium/cronet_test_apk/CronetUrlRequestContextTest.java +++ b/components/cronet/android/test/javatests/src/org/chromium/cronet_test_apk/CronetUrlRequestContextTest.java
@@ -6,6 +6,7 @@ import android.test.suitebuilder.annotation.SmallTest; +import org.chromium.base.PathUtils; import org.chromium.base.test.util.Feature; import org.chromium.cronet_test_apk.TestUrlRequestListener.FailureType; import org.chromium.cronet_test_apk.TestUrlRequestListener.ResponseStep; @@ -15,6 +16,7 @@ import org.chromium.net.UrlRequestContextConfig; import org.chromium.net.UrlRequestException; +import java.io.File; import java.nio.ByteBuffer; import java.util.Arrays; @@ -180,4 +182,102 @@ mActivity.mUrlRequestContext.shutdown(); } + + @SmallTest + @Feature({"Cronet"}) + public void testNetLog() throws Exception { + mActivity = launchCronetTestApp(); + waitForActiveShellToBeDoneLoading(); + File directory = new File(PathUtils.getDataDirectory( + getInstrumentation().getTargetContext())); + File file = File.createTempFile("cronet", "json", directory); + mActivity.mUrlRequestContext.startNetLogToFile(file.getPath()); + // Start a request. + TestUrlRequestListener listener = new TestUrlRequestListener(); + UrlRequest urlRequest = mActivity.mUrlRequestContext.createRequest( + TEST_URL, listener, listener.getExecutor()); + urlRequest.start(); + listener.blockForDone(); + mActivity.mUrlRequestContext.stopNetLog(); + assertTrue(file.exists()); + assertTrue(file.length() != 0); + assertTrue(file.delete()); + assertTrue(!file.exists()); + } + + @SmallTest + @Feature({"Cronet"}) + public void testNetLogAfterShutdown() throws Exception { + mActivity = launchCronetTestApp(); + waitForActiveShellToBeDoneLoading(); + TestUrlRequestListener listener = new TestUrlRequestListener(); + UrlRequest urlRequest = mActivity.mUrlRequestContext.createRequest( + TEST_URL, listener, listener.getExecutor()); + urlRequest.start(); + listener.blockForDone(); + mActivity.mUrlRequestContext.shutdown(); + + File directory = new File(PathUtils.getDataDirectory( + getInstrumentation().getTargetContext())); + File file = File.createTempFile("cronet", "json", directory); + mActivity.mUrlRequestContext.startNetLogToFile(file.getPath()); + mActivity.mUrlRequestContext.stopNetLog(); + assertTrue(file.exists()); + assertTrue(file.length() == 0); + assertTrue(file.delete()); + assertTrue(!file.exists()); + } + + @SmallTest + @Feature({"Cronet"}) + public void testNetLogStartMultipleTimes() throws Exception { + mActivity = launchCronetTestApp(); + waitForActiveShellToBeDoneLoading(); + File directory = new File(PathUtils.getDataDirectory( + getInstrumentation().getTargetContext())); + File file = File.createTempFile("cronet", "json", directory); + // Start NetLog multiple times. + mActivity.mUrlRequestContext.startNetLogToFile(file.getPath()); + mActivity.mUrlRequestContext.startNetLogToFile(file.getPath()); + mActivity.mUrlRequestContext.startNetLogToFile(file.getPath()); + mActivity.mUrlRequestContext.startNetLogToFile(file.getPath()); + // Start a request. + TestUrlRequestListener listener = new TestUrlRequestListener(); + UrlRequest urlRequest = mActivity.mUrlRequestContext.createRequest( + TEST_URL, listener, listener.getExecutor()); + urlRequest.start(); + listener.blockForDone(); + mActivity.mUrlRequestContext.stopNetLog(); + assertTrue(file.exists()); + assertTrue(file.length() != 0); + assertTrue(file.delete()); + assertTrue(!file.exists()); + } + + @SmallTest + @Feature({"Cronet"}) + public void testNetLogStopMultipleTimes() throws Exception { + mActivity = launchCronetTestApp(); + waitForActiveShellToBeDoneLoading(); + File directory = new File(PathUtils.getDataDirectory( + getInstrumentation().getTargetContext())); + File file = File.createTempFile("cronet", "json", directory); + mActivity.mUrlRequestContext.startNetLogToFile(file.getPath()); + // Start a request. + TestUrlRequestListener listener = new TestUrlRequestListener(); + UrlRequest urlRequest = mActivity.mUrlRequestContext.createRequest( + TEST_URL, listener, listener.getExecutor()); + urlRequest.start(); + listener.blockForDone(); + // Stop NetLog multiple times. + mActivity.mUrlRequestContext.stopNetLog(); + mActivity.mUrlRequestContext.stopNetLog(); + mActivity.mUrlRequestContext.stopNetLog(); + mActivity.mUrlRequestContext.stopNetLog(); + mActivity.mUrlRequestContext.stopNetLog(); + assertTrue(file.exists()); + assertTrue(file.length() != 0); + assertTrue(file.delete()); + assertTrue(!file.exists()); + } }
diff --git a/components/cronet/android/test/javatests/src/org/chromium/cronet_test_apk/CronetUrlTest.java b/components/cronet/android/test/javatests/src/org/chromium/cronet_test_apk/CronetUrlTest.java index 5ede19a..8cc6313 100644 --- a/components/cronet/android/test/javatests/src/org/chromium/cronet_test_apk/CronetUrlTest.java +++ b/components/cronet/android/test/javatests/src/org/chromium/cronet_test_apk/CronetUrlTest.java
@@ -6,6 +6,7 @@ import android.test.suitebuilder.annotation.SmallTest; +import org.chromium.base.PathUtils; import org.chromium.base.test.util.Feature; import org.chromium.net.HttpUrlRequest; import org.chromium.net.HttpUrlRequestFactoryConfig; @@ -72,15 +73,13 @@ @SmallTest @Feature({"Cronet"}) public void testNetLog() throws Exception { - CronetTestActivity activity = launchCronetTestAppWithUrl( - "127.0.0.1:8000"); - - // Make sure the activity was created as expected. - assertNotNull(activity); - + CronetTestActivity activity = launchCronetTestApp(); waitForActiveShellToBeDoneLoading(); - File file = File.createTempFile("cronet", "json"); + File directory = new File(PathUtils.getDataDirectory( + getInstrumentation().getTargetContext())); + File file = File.createTempFile("cronet", "json", directory); activity.mRequestFactory.startNetLogToFile(file.getPath()); + // Starts a request. activity.startWithURL(URL); Thread.sleep(5000); activity.mRequestFactory.stopNetLog();
diff --git a/components/data_reduction_proxy/core/common/chrome_proxy_header.txt b/components/data_reduction_proxy/core/common/chrome_proxy_header.txt new file mode 100644 index 0000000..5a6a81c --- /dev/null +++ b/components/data_reduction_proxy/core/common/chrome_proxy_header.txt
@@ -0,0 +1,114 @@ +The Chrome-Proxy header is used to convey client credentials and capabilities +to the Data Reduction Proxy and to receive instructions from it. + +Background +---------- + +The Data Reduction Proxy is operated by Google for Chrome. Chrome is +configured to connect to it via TLS at proxy.googlezip.net:443 and via HTTP +at compress.googlezip.net:80. The Data Reduction Proxy only proxies HTTP +traffic from non-incognito tabs. + +Chrome-Proxy Response Header +---------------------------- + +The Data Reduction Proxy uses the Chrome-Proxy response header to instruct +Chrome to bypass the proxy for a period of time and retry the request directly. +It may do so to shed load, when the requested URL is on a blacklist of +malicious or illegal resources, or when the request is for video, which the +proxy does not currently serve. Bypasses may be issued for other reasons as +well. + +In order to bypass a proxy and make decisions about when requests should be +proxied and which proxy they should use, some proxies serve PAC scripts +themselves with a low HTTP cache timeout, and dynamically update the scripts +to direct users. This is the current state of the art, but the approach has many +drawbacks. Some clients ignore the HTTP caching headers for the PAC script. The +client's performance suffers because new PAC scripts must be interpreted after +every invalidation. Clients must also store (large) blacklists. Server design is +complicated by needing to decouple a request from the mechanism that would +bypass it (a PAC). Bypass fidelity is coarse meaning that bypass decisions can't +be made on a per-request basis. And bypass decisions must be made before the +request is sent, which isn't always possible, e.g., for domains the proxy hasn't +served before. + +Instead, the Data Reduction Proxy sends one of a set of bypass directives in the +"Chrome-Proxy" header if it wants the client not to use it. Upon reception of +this header, the client may decide to retry the request with the proxy disabled +or cancel the request. Chrome cancels instead of retrying non-idempotent +requests. + +The "Chrome-Proxy" response header has the following format: + +chrome-proxy = "Chrome-Proxy" ":" 1#chrome-proxy-directive +chrome-proxy-directive = token [ "=" ( token / quoted-string ) ] + +The header uses the definition of 'token' and 'quoted-string' from +https://datatracker.ietf.org/doc/rfc7230/ + +The directives have the following meanings: + +bypass: Argument syntax: delta-seconds + delta-seconds = 1*DIGIT (see: 1.2.1 of rfc7234) + Bypass the currently configured proxy for specified number of + seconds. If zero is specified, Chrome should use its default + proxy bypass timeout, which is a random duration between 1 and 5 + minutes. If the TLS proxy is bypassed, Chrome will downgrade to + using HTTP to connect to the Data Reduction Proxy. If the HTTP + proxy is bypassed, Chrome will downgrade to using a DIRECT + connection. +block: Argument syntax: delta-seconds + Bypass all Data Reduction Proxies for the specified number of + seconds. If zero is specified, Chrome will use the default block + timeout, which is a random time between 1 and 5 minutes. +block-once: Bypass all Data Reductions Proxies for this request only. + +Currently, the directives are mutually exclusive, but the header format does +not require this. With "block-once", no token is expected. + +If more than one directive is contained the header, then Chrome reacts to only +the highest priority directive. Priorities from highest to lowest are: +block > bypass > block-once. + + +Examples that respectively bypass the current proxy for seven seconds, bypass +both the TLS and HTTP proxies for Chrome's default proxy bypass duration, and +bypass the TLS and HTTP proxies only for the current request: + +Chrome-Proxy: bypass=7 +Chrome-Proxy: block=0 +Chrome-Proxy: block-once + + +The Chrome-Proxy header is NOT hop-by-hop, and thus transparent proxies and +other intermediaries should not modify it. Further, only the Data Reduction +Proxy should add this header to responses. + +Chrome-Proxy Request Header +--------------------------- + +The Chrome-Proxy request header is used to specify client capabilities and +credentials. It has the same form as the response header. The directives have +the following names and meanings: + +ps: Argument syntax: token + A User-Agent-selected pseudorandom session ID. +sid: Argument syntax: token + A credential string. +b: Argument syntax: 1*DIGIT + The Chrome build number of the client +p: Argument syntax: 1*DIGIT + The Chrome patch number of the client +c: Argument syntax: "android" / "ios" / "mac" / "win" / "linux" / + "chromeos" / "webview" + The type of client. + +The values of the 'b', 'p', and 'c' directives can often be gleaned from the +user agent string, but not always, so they are sent explicitly. Each request +sent from Chrome to a Data Reduction Proxy contains a Chrome-Proxy header with +values for all five of these directives. + +For example, for Chrome 38 on Android with a version 38.0.2125.114 (note the +'ps' and 'sid' values are representative): + +Chrome-Proxy: ps=484343-123-4-9484, sid=he9wj3gjd03, b=2125, p=114, c=android
diff --git a/components/error_page/renderer/net_error_helper_core.cc b/components/error_page/renderer/net_error_helper_core.cc index 94abe60..1cc3005 100644 --- a/components/error_page/renderer/net_error_helper_core.cc +++ b/components/error_page/renderer/net_error_helper_core.cc
@@ -454,6 +454,7 @@ auto_reload_visible_only_(auto_reload_visible_only), auto_reload_timer_(new base::Timer(false, false)), auto_reload_paused_(false), + auto_reload_in_flight_(false), uncommitted_load_started_(false), // TODO(ellyjones): Make online_ accurate at object creation. online_(true), @@ -492,6 +493,7 @@ CancelPendingFetches(); uncommitted_load_started_ = false; auto_reload_count_ = 0; + auto_reload_in_flight_ = false; } void NetErrorHelperCore::OnWasShown() { @@ -525,6 +527,11 @@ if (frame_type != MAIN_FRAME) return; + // If a page is committing, either it's an error page and autoreload will be + // started again below, or it's a success page and we need to clear autoreload + // state. + auto_reload_in_flight_ = false; + // uncommitted_load_started_ could already be false, since RenderFrameImpl // calls OnCommitLoad once for each in-page navigation (like a fragment // change) with no corresponding OnStartLoad. @@ -825,7 +832,15 @@ } void NetErrorHelperCore::AutoReloadTimerFired() { + // AutoReloadTimerFired only runs if: + // 1. StartAutoReloadTimer was previously called, which requires that + // committed_error_page_info_ is populated; + // 2. No other page load has started since (1), since OnStartLoad stops the + // auto-reload timer. + DCHECK(committed_error_page_info_); + auto_reload_count_++; + auto_reload_in_flight_ = true; Reload(); } @@ -860,40 +875,16 @@ if (frame_type != MAIN_FRAME) return false; - if (!auto_reload_enabled_) + // If there's no auto reload attempt in flight, this error page didn't come + // from auto reload, so don't suppress it. + if (!auto_reload_in_flight_) return false; - // If there's no committed error page, this error page wasn't from an auto - // reload. - if (!committed_error_page_info_) - return false; - - // If the error page wasn't reloadable, display it. - if (!IsReloadableError(*committed_error_page_info_)) - return false; - - // If |auto_reload_timer_| is still running or is paused, this error page - // isn't from an auto reload. - if (auto_reload_timer_->IsRunning() || auto_reload_paused_) - return false; - - // If the error page was reloadable, and the timer isn't running or paused, an - // auto-reload has already been triggered. - DCHECK(committed_error_page_info_->auto_reload_triggered); - - GURL error_url = committed_error_page_info_->error.unreachableURL; - // TODO(ellyjones): also plumb the error code down to CCRC and check that - if (error_url != url) - return false; - - // Suppressed an error-page load; the previous uncommitted load was the error - // page load starting, so forget about it. uncommitted_load_started_ = false; - - // The first iteration of the timer is started by OnFinishLoad calling - // MaybeStartAutoReloadTimer, but since error pages for subsequent loads are - // suppressed in this function, subsequent iterations of the timer have to be - // started here. + // This serves to terminate the auto-reload in flight attempt. If + // ShouldSuppressErrorPage is called, the auto-reload yielded an error, which + // means the request was already sent. + auto_reload_in_flight_ = false; MaybeStartAutoReloadTimer(); return true; }
diff --git a/components/error_page/renderer/net_error_helper_core.h b/components/error_page/renderer/net_error_helper_core.h index ec00d33..4c16e25 100644 --- a/components/error_page/renderer/net_error_helper_core.h +++ b/components/error_page/renderer/net_error_helper_core.h
@@ -243,6 +243,9 @@ // offline->online network transition. bool auto_reload_paused_; + // Whether an auto-reload-initiated Reload() attempt is in flight. + bool auto_reload_in_flight_; + // True if there is an uncommitted-but-started load, error page or not. This // is used to inhibit starting auto-reload when an error page finishes, in // case this happens:
diff --git a/components/error_page/renderer/net_error_helper_core_unittest.cc b/components/error_page/renderer/net_error_helper_core_unittest.cc index 5015f836..b6a389f 100644 --- a/components/error_page/renderer/net_error_helper_core_unittest.cc +++ b/components/error_page/renderer/net_error_helper_core_unittest.cc
@@ -2196,12 +2196,14 @@ DoErrorLoad(net::ERR_CONNECTION_RESET); timer()->Fire(); + // Sub-frame load. EXPECT_FALSE(core()->ShouldSuppressErrorPage(NetErrorHelperCore::SUB_FRAME, GURL(kFailedUrl))); - EXPECT_FALSE(core()->ShouldSuppressErrorPage(NetErrorHelperCore::MAIN_FRAME, - GURL("http://some.other.url"))); EXPECT_TRUE(core()->ShouldSuppressErrorPage(NetErrorHelperCore::MAIN_FRAME, - GURL(kFailedUrl))); + GURL(kFailedUrl))); + // No auto-reload attempt in flight. + EXPECT_FALSE(core()->ShouldSuppressErrorPage(NetErrorHelperCore::MAIN_FRAME, + GURL(kFailedUrl))); } TEST_F(NetErrorHelperCoreAutoReloadTest, HiddenAndShown) { @@ -2244,6 +2246,15 @@ EXPECT_TRUE(timer()->IsRunning()); } +TEST_F(NetErrorHelperCoreAutoReloadTest, ManualReloadShowsError) { + SetUpCore(true, true, true); + DoErrorLoad(net::ERR_CONNECTION_RESET); + core()->OnStartLoad(NetErrorHelperCore::MAIN_FRAME, + NetErrorHelperCore::ERROR_PAGE); + EXPECT_FALSE(core()->ShouldSuppressErrorPage(NetErrorHelperCore::MAIN_FRAME, + GURL(kFailedUrl))); +} + class NetErrorHelperCoreHistogramTest : public NetErrorHelperCoreAutoReloadTest { public: @@ -2294,7 +2305,6 @@ timer()->Fire(); EXPECT_TRUE(core()->ShouldSuppressErrorPage(NetErrorHelperCore::MAIN_FRAME, default_url())); -// DoErrorLoad(net::ERR_CONNECTION_RESET); timer()->Fire(); DoSuccessLoad();
diff --git a/components/nacl/loader/nacl_listener.cc b/components/nacl/loader/nacl_listener.cc index 7eab603..5e7562e 100644 --- a/components/nacl/loader/nacl_listener.cc +++ b/components/nacl/loader/nacl_listener.cc
@@ -401,6 +401,7 @@ // https://code.google.com/p/nativeclient/issues/detail?id=3914. // Once done, this can be removed. args->irt_load_optional = 1; + args->pnacl_mode = 0; } #if defined(OS_LINUX) || defined(OS_MACOSX)
diff --git a/components/nacl/renderer/ppb_nacl_private_impl.cc b/components/nacl/renderer/ppb_nacl_private_impl.cc index 2df50bb..d923f2a 100644 --- a/components/nacl/renderer/ppb_nacl_private_impl.cc +++ b/components/nacl/renderer/ppb_nacl_private_impl.cc
@@ -161,9 +161,8 @@ // management. class ManifestServiceProxy : public ManifestServiceChannel::Delegate { public: - ManifestServiceProxy(PP_Instance pp_instance) - : pp_instance_(pp_instance) { - } + ManifestServiceProxy(PP_Instance pp_instance, bool is_helper_process) + : pp_instance_(pp_instance), is_helper_process_(is_helper_process) {} ~ManifestServiceProxy() override {} @@ -200,7 +199,8 @@ pnacl_options.translate = PP_FALSE; pnacl_options.is_debug = PP_FALSE; pnacl_options.opt_level = 2; - if (!ManifestResolveKey(pp_instance_, false, key, &url, &pnacl_options)) { + if (!ManifestResolveKey(pp_instance_, is_helper_process_, key, &url, + &pnacl_options)) { base::MessageLoop::current()->PostTask( FROM_HERE, base::Bind(callback, base::Passed(base::File()), 0, 0)); @@ -233,6 +233,7 @@ } PP_Instance pp_instance_; + bool is_helper_process_; DISALLOW_COPY_AND_ASSIGN(ManifestServiceProxy); }; @@ -309,33 +310,24 @@ CHECK(ppapi::PpapiGlobals::Get()->GetMainThreadMessageLoop()-> BelongsToCurrentThread()); NaClAppProcessType process_type = PP_ToNaClAppProcessType(pp_process_type); + bool is_helper_process = process_type == kPNaClTranslatorProcessType; // Create the manifest service proxy here, so on error case, it will be // destructed (without passing it to ManifestServiceChannel). scoped_ptr<ManifestServiceChannel::Delegate> manifest_service_proxy( - new ManifestServiceProxy(instance)); + new ManifestServiceProxy(instance, is_helper_process)); FileDescriptor result_socket; IPC::Sender* sender = content::RenderThread::Get(); DCHECK(sender); - int routing_id = 0; - // If the nexe uses ppapi APIs, we need a routing ID. - // To get the routing ID, we must be on the main thread. - // Some nexes do not use ppapi and launch from the background thread, - // so those nexes can skip finding a routing_id. Currently, that only - // applies to the PNaClTranslatorProcesses. - bool uses_ppapi = process_type != kPNaClTranslatorProcessType; - if (uses_ppapi) { - routing_id = GetRoutingID(instance); - if (!routing_id) { - if (nexe_file_info->handle != PP_kInvalidFileHandle) { - base::File closer(nexe_file_info->handle); - } - ppapi::PpapiGlobals::Get()->GetMainThreadMessageLoop()->PostTask( - FROM_HERE, - base::Bind(callback.func, callback.user_data, - static_cast<int32_t>(PP_ERROR_FAILED))); - return; + int routing_id = GetRoutingID(instance); + if (!routing_id) { + if (nexe_file_info->handle != PP_kInvalidFileHandle) { + base::File closer(nexe_file_info->handle); } + ppapi::PpapiGlobals::Get()->GetMainThreadMessageLoop()->PostTask( + FROM_HERE, base::Bind(callback.func, callback.user_data, + static_cast<int32_t>(PP_ERROR_FAILED))); + return; } InstanceInfo instance_info; @@ -439,11 +431,12 @@ // Create the manifest service handle as well. // For security hardening, disable the IPCs for open_resource() when they - // aren't needed. PNaCl doesn't expose open_resource(). + // aren't needed. PNaCl pexes can't use open_resource(), but general nexes + // and the PNaCl translator nexes may use it. if (load_manager && - process_type == kNativeNaClProcessType && - IsValidChannelHandle( - launch_result.manifest_service_ipc_channel_handle)) { + (process_type == kNativeNaClProcessType || + process_type == kPNaClTranslatorProcessType) && + IsValidChannelHandle(launch_result.manifest_service_ipc_channel_handle)) { scoped_ptr<ManifestServiceChannel> manifest_service_channel( new ManifestServiceChannel( launch_result.manifest_service_ipc_channel_handle, @@ -453,8 +446,8 @@ load_manager->set_manifest_service_channel( manifest_service_channel.Pass()); } else { - // Currently, manifest service works only on linux/non-SFI mode. - // On other platforms, the socket will not be created, and thus this + // The manifest service is not used for some cases like PNaCl pexes. + // In that case, the socket will not be created, and thus this // condition needs to be handled as success. PostPPCompletionCallback(callback, PP_OK); }
diff --git a/components/onc/onc_constants.cc b/components/onc/onc_constants.cc index 06342dfa..e9d19059 100644 --- a/components/onc/onc_constants.cc +++ b/components/onc/onc_constants.cc
@@ -279,6 +279,7 @@ const char kOpenVPN[] = "OpenVPN"; const char kPassword[] = "Password"; const char kSaveCredentials[] = "SaveCredentials"; +const char kThirdPartyVpn[] = "ThirdPartyVPN"; const char kTypeL2TP_IPsec[] = "L2TP-IPsec"; const char kType[] = "Type"; const char kUsername[] = "Username";
diff --git a/components/onc/onc_constants.h b/components/onc/onc_constants.h index 5e197e0e..89b193b 100644 --- a/components/onc/onc_constants.h +++ b/components/onc/onc_constants.h
@@ -297,6 +297,7 @@ ONC_EXPORT extern const char kOpenVPN[]; ONC_EXPORT extern const char kPassword[]; ONC_EXPORT extern const char kSaveCredentials[]; +ONC_EXPORT extern const char kThirdPartyVpn[]; ONC_EXPORT extern const char kTypeL2TP_IPsec[]; ONC_EXPORT extern const char kType[]; ONC_EXPORT extern const char kUsername[];
diff --git a/components/password_manager.gypi b/components/password_manager.gypi index 61766bcd..388609d 100644 --- a/components/password_manager.gypi +++ b/components/password_manager.gypi
@@ -50,6 +50,8 @@ 'password_manager/core/browser/password_manager_internals_service.h', 'password_manager/core/browser/password_manager_metrics_util.cc', 'password_manager/core/browser/password_manager_metrics_util.h', + 'password_manager/core/browser/password_manager_url_collection_experiment.cc', + 'password_manager/core/browser/password_manager_url_collection_experiment.h', 'password_manager/core/browser/password_store.cc', 'password_manager/core/browser/password_store.h', 'password_manager/core/browser/password_store_change.h', @@ -228,6 +230,8 @@ 'password_manager/content/browser/content_credential_manager_dispatcher.h', 'password_manager/content/browser/content_password_manager_driver.cc', 'password_manager/content/browser/content_password_manager_driver.h', + 'password_manager/content/browser/content_password_manager_driver_factory.cc', + 'password_manager/content/browser/content_password_manager_driver_factory.h', 'password_manager/content/browser/credential_manager_password_form_manager.cc', 'password_manager/content/browser/credential_manager_password_form_manager.h', 'password_manager/content/browser/password_manager_internals_service_factory.cc',
diff --git a/components/password_manager/content/browser/BUILD.gn b/components/password_manager/content/browser/BUILD.gn index e91db23..5a977ac 100644 --- a/components/password_manager/content/browser/BUILD.gn +++ b/components/password_manager/content/browser/BUILD.gn
@@ -8,6 +8,8 @@ "content_credential_manager_dispatcher.h", "content_password_manager_driver.cc", "content_password_manager_driver.h", + "content_password_manager_driver_factory.cc", + "content_password_manager_driver_factory.h", "credential_manager_password_form_manager.cc", "credential_manager_password_form_manager.h", "password_manager_internals_service_factory.cc",
diff --git a/components/password_manager/content/browser/content_credential_manager_dispatcher.cc b/components/password_manager/content/browser/content_credential_manager_dispatcher.cc index 94e95e1..aae4f34 100644 --- a/components/password_manager/content/browser/content_credential_manager_dispatcher.cc +++ b/components/password_manager/content/browser/content_credential_manager_dispatcher.cc
@@ -8,6 +8,8 @@ #include "base/strings/string16.h" #include "base/strings/utf_string_conversions.h" #include "components/autofill/core/common/password_form.h" +#include "components/password_manager/content/browser/content_password_manager_driver.h" +#include "components/password_manager/content/browser/content_password_manager_driver_factory.h" #include "components/password_manager/content/browser/credential_manager_password_form_manager.h" #include "components/password_manager/content/common/credential_manager_messages.h" #include "components/password_manager/content/common/credential_manager_types.h" @@ -24,8 +26,14 @@ PasswordManagerClient* client) : WebContentsObserver(web_contents), client_(client), + driver_(nullptr), pending_request_id_(0) { DCHECK(web_contents); + + ContentPasswordManagerDriverFactory* driver_factory = + ContentPasswordManagerDriverFactory::FromWebContents(web_contents); + if (driver_factory) + driver_ = driver_factory->GetDriverForFrame(web_contents->GetMainFrame()); } ContentCredentialManagerDispatcher::~ContentCredentialManagerDispatcher() {} @@ -68,7 +76,7 @@ // determine whether or not the credential exists, and calling UpdateLogin // accordingly. form_manager_.reset( - new CredentialManagerPasswordFormManager(client_, *form, this)); + new CredentialManagerPasswordFormManager(client_, driver_, *form, this)); web_contents()->GetRenderViewHost()->Send( new CredentialManagerMsg_AcknowledgeSignedIn(
diff --git a/components/password_manager/content/browser/content_credential_manager_dispatcher.h b/components/password_manager/content/browser/content_credential_manager_dispatcher.h index b508cef..fc8cac8 100644 --- a/components/password_manager/content/browser/content_credential_manager_dispatcher.h +++ b/components/password_manager/content/browser/content_credential_manager_dispatcher.h
@@ -25,6 +25,7 @@ class CredentialManagerPasswordFormManager; class PasswordManagerClient; +class PasswordManagerDriver; class PasswordStore; struct CredentialInfo; @@ -55,6 +56,11 @@ void OnGetPasswordStoreResults( const std::vector<autofill::PasswordForm*>& results) override; + // For testing only. + void set_password_manager_driver(PasswordManagerDriver* driver) { + driver_ = driver; + } + using CredentialCallback = base::Callback<void(const autofill::PasswordForm&)>; @@ -64,6 +70,7 @@ void SendCredential(int request_id, const CredentialInfo& info); PasswordManagerClient* client_; + PasswordManagerDriver* driver_; scoped_ptr<CredentialManagerPasswordFormManager> form_manager_; // When 'OnRequestCredential' is called, it in turn calls out to the
diff --git a/components/password_manager/content/browser/content_credential_manager_dispatcher_unittest.cc b/components/password_manager/content/browser/content_credential_manager_dispatcher_unittest.cc index fd148d0..f5950aa 100644 --- a/components/password_manager/content/browser/content_credential_manager_dispatcher_unittest.cc +++ b/components/password_manager/content/browser/content_credential_manager_dispatcher_unittest.cc
@@ -42,10 +42,6 @@ return store_; } - password_manager::PasswordManagerDriver* GetDriver() override { - return &driver_; - } - bool PromptUserToSavePassword( scoped_ptr<password_manager::PasswordFormManager> manager) override { did_prompt_user_to_save_ = true; @@ -78,7 +74,6 @@ bool did_prompt_user_to_save_; bool did_prompt_user_to_choose_; password_manager::PasswordStore* store_; - password_manager::StubPasswordManagerDriver driver_; scoped_ptr<password_manager::PasswordFormManager> manager_; }; @@ -104,6 +99,7 @@ client_.reset(new TestPasswordManagerClient(store_.get())); dispatcher_.reset( new ContentCredentialManagerDispatcher(web_contents(), client_.get())); + dispatcher_->set_password_manager_driver(&stub_driver_); NavigateAndCommit(GURL("https://example.com/test.html")); @@ -130,6 +126,7 @@ scoped_refptr<TestPasswordStore> store_; scoped_ptr<ContentCredentialManagerDispatcher> dispatcher_; scoped_ptr<TestPasswordManagerClient> client_; + StubPasswordManagerDriver stub_driver_; }; TEST_F(ContentCredentialManagerDispatcherTest,
diff --git a/components/password_manager/content/browser/content_password_manager_driver.cc b/components/password_manager/content/browser/content_password_manager_driver.cc index 62c20e6..2139c85 100644 --- a/components/password_manager/content/browser/content_password_manager_driver.cc +++ b/components/password_manager/content/browser/content_password_manager_driver.cc
@@ -5,14 +5,18 @@ #include "components/password_manager/content/browser/content_password_manager_driver.h" #include "components/autofill/content/browser/content_autofill_driver.h" +#include "components/autofill/content/browser/content_autofill_driver_factory.h" #include "components/autofill/content/common/autofill_messages.h" #include "components/autofill/core/common/form_data.h" #include "components/autofill/core/common/password_form.h" +#include "components/password_manager/content/browser/content_password_manager_driver_factory.h" #include "components/password_manager/core/browser/password_manager_client.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/navigation_details.h" #include "content/public/browser/navigation_entry.h" +#include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_view_host.h" +#include "content/public/browser/site_instance.h" #include "content/public/browser/web_contents.h" #include "content/public/common/ssl_status.h" #include "ipc/ipc_message_macros.h" @@ -21,37 +25,44 @@ namespace password_manager { ContentPasswordManagerDriver::ContentPasswordManagerDriver( - content::WebContents* web_contents, + content::RenderFrameHost* render_frame_host, PasswordManagerClient* client, autofill::AutofillClient* autofill_client) - : WebContentsObserver(web_contents), - password_manager_(client), - password_generation_manager_(client), - password_autofill_manager_(client, autofill_client), + : render_frame_host_(render_frame_host), + client_(client), + password_generation_manager_(client, this), + password_autofill_manager_(client, this, autofill_client), next_free_key_(0) { - DCHECK(web_contents); } ContentPasswordManagerDriver::~ContentPasswordManagerDriver() {} +// static +ContentPasswordManagerDriver* +ContentPasswordManagerDriver::GetForRenderFrameHost( + content::RenderFrameHost* render_frame_host) { + return ContentPasswordManagerDriverFactory::FromWebContents( + content::WebContents::FromRenderFrameHost(render_frame_host)) + ->GetDriverForFrame(render_frame_host); +} + void ContentPasswordManagerDriver::FillPasswordForm( const autofill::PasswordFormFillData& form_data) { const int key = next_free_key_++; password_autofill_manager_.OnAddPasswordFormMapping(key, form_data); - DCHECK(web_contents()); - web_contents()->GetRenderViewHost()->Send(new AutofillMsg_FillPasswordForm( - web_contents()->GetRenderViewHost()->GetRoutingID(), key, form_data)); + render_frame_host_->Send(new AutofillMsg_FillPasswordForm( + render_frame_host_->GetRoutingID(), key, form_data)); } void ContentPasswordManagerDriver::AllowPasswordGenerationForForm( const autofill::PasswordForm& form) { - content::RenderViewHost* host = web_contents()->GetRenderViewHost(); + content::RenderFrameHost* host = render_frame_host_; host->Send(new AutofillMsg_FormNotBlacklisted(host->GetRoutingID(), form)); } void ContentPasswordManagerDriver::AccountCreationFormsFound( const std::vector<autofill::FormData>& forms) { - content::RenderViewHost* host = web_contents()->GetRenderViewHost(); + content::RenderFrameHost* host = render_frame_host_; host->Send(new AutofillMsg_AccountCreationFormsDetected(host->GetRoutingID(), forms)); } @@ -59,7 +70,7 @@ void ContentPasswordManagerDriver::FillSuggestion( const base::string16& username, const base::string16& password) { - content::RenderViewHost* host = web_contents()->GetRenderViewHost(); + content::RenderFrameHost* host = render_frame_host_; host->Send( new AutofillMsg_FillPasswordSuggestion(host->GetRoutingID(), username, @@ -69,7 +80,7 @@ void ContentPasswordManagerDriver::PreviewSuggestion( const base::string16& username, const base::string16& password) { - content::RenderViewHost* host = web_contents()->GetRenderViewHost(); + content::RenderFrameHost* host = render_frame_host_; host->Send( new AutofillMsg_PreviewPasswordSuggestion(host->GetRoutingID(), username, @@ -77,36 +88,18 @@ } void ContentPasswordManagerDriver::ClearPreviewedForm() { - content::RenderViewHost* host = web_contents()->GetRenderViewHost(); + content::RenderFrameHost* host = render_frame_host_; host->Send( new AutofillMsg_ClearPreviewedForm(host->GetRoutingID())); } -bool ContentPasswordManagerDriver::DidLastPageLoadEncounterSSLErrors() { - DCHECK(web_contents()); - // TODO(vabr): This is a wrong entry to look at for HTTP basic auth, - // http://crbug.com/388246. - content::NavigationEntry* entry = - web_contents()->GetController().GetLastCommittedEntry(); - if (!entry) { - return false; - } - - return net::IsCertStatusError(entry->GetSSL().cert_status); -} - -bool ContentPasswordManagerDriver::IsOffTheRecord() { - DCHECK(web_contents()); - return web_contents()->GetBrowserContext()->IsOffTheRecord(); -} - PasswordGenerationManager* ContentPasswordManagerDriver::GetPasswordGenerationManager() { return &password_generation_manager_; } PasswordManager* ContentPasswordManagerDriver::GetPasswordManager() { - return &password_manager_; + return client_->GetPasswordManager(); } PasswordAutofillManager* @@ -114,41 +107,57 @@ return &password_autofill_manager_; } -void ContentPasswordManagerDriver::DidNavigateMainFrame( - const content::LoadCommittedDetails& details, - const content::FrameNavigateParams& params) { - password_manager_.DidNavigateMainFrame(details.is_in_page); -} - -bool ContentPasswordManagerDriver::OnMessageReceived( - const IPC::Message& message) { +bool ContentPasswordManagerDriver::HandleMessage(const IPC::Message& message) { bool handled = true; - IPC_BEGIN_MESSAGE_MAP(PasswordManager, message) - IPC_MESSAGE_FORWARD(AutofillHostMsg_PasswordFormsParsed, - &password_manager_, - PasswordManager::OnPasswordFormsParsed) - IPC_MESSAGE_FORWARD(AutofillHostMsg_PasswordFormsRendered, - &password_manager_, - PasswordManager::OnPasswordFormsRendered) - IPC_MESSAGE_FORWARD(AutofillHostMsg_PasswordFormSubmitted, - &password_manager_, - PasswordManager::OnPasswordFormSubmitted) + IPC_BEGIN_MESSAGE_MAP(ContentPasswordManagerDriver, message) + IPC_MESSAGE_HANDLER(AutofillHostMsg_PasswordFormsParsed, + OnPasswordFormsParsed) + IPC_MESSAGE_HANDLER(AutofillHostMsg_PasswordFormsRendered, + OnPasswordFormsRendered) + IPC_MESSAGE_HANDLER(AutofillHostMsg_PasswordFormSubmitted, + OnPasswordFormSubmitted) IPC_MESSAGE_FORWARD(AutofillHostMsg_ShowPasswordSuggestions, &password_autofill_manager_, PasswordAutofillManager::OnShowPasswordSuggestions) - IPC_MESSAGE_FORWARD(AutofillHostMsg_RecordSavePasswordProgress, - password_manager_.client(), + IPC_MESSAGE_FORWARD(AutofillHostMsg_RecordSavePasswordProgress, client_, PasswordManagerClient::LogSavePasswordProgress) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() - return handled; } +void ContentPasswordManagerDriver::OnPasswordFormsParsed( + const std::vector<autofill::PasswordForm>& forms) { + GetPasswordManager()->OnPasswordFormsParsed(this, forms); +} + +void ContentPasswordManagerDriver::OnPasswordFormsRendered( + const std::vector<autofill::PasswordForm>& visible_forms, + bool did_stop_loading) { + GetPasswordManager()->OnPasswordFormsRendered(this, visible_forms, + did_stop_loading); +} + +void ContentPasswordManagerDriver::OnPasswordFormSubmitted( + const autofill::PasswordForm& password_form) { + GetPasswordManager()->OnPasswordFormSubmitted(this, password_form); +} + +void ContentPasswordManagerDriver::DidNavigateFrame( + const content::LoadCommittedDetails& details, + const content::FrameNavigateParams& params) { + GetPasswordAutofillManager()->Reset(); + if (!render_frame_host_->GetParent()) + GetPasswordManager()->DidNavigateMainFrame(details.is_in_page); +} + autofill::AutofillManager* ContentPasswordManagerDriver::GetAutofillManager() { - autofill::ContentAutofillDriver* driver = - autofill::ContentAutofillDriver::FromWebContents(web_contents()); - return driver ? driver->autofill_manager() : NULL; + autofill::ContentAutofillDriverFactory* factory = + autofill::ContentAutofillDriverFactory::FromWebContents( + content::WebContents::FromRenderFrameHost(render_frame_host_)); + return factory + ? factory->DriverForFrame(render_frame_host_)->autofill_manager() + : nullptr; } } // namespace password_manager
diff --git a/components/password_manager/content/browser/content_password_manager_driver.h b/components/password_manager/content/browser/content_password_manager_driver.h index 3d454a6..f9b0dcf6 100644 --- a/components/password_manager/content/browser/content_password_manager_driver.h +++ b/components/password_manager/content/browser/content_password_manager_driver.h
@@ -11,7 +11,6 @@ #include "components/password_manager/core/browser/password_generation_manager.h" #include "components/password_manager/core/browser/password_manager.h" #include "components/password_manager/core/browser/password_manager_driver.h" -#include "content/public/browser/web_contents_observer.h" namespace autofill { class AutofillManager; @@ -19,24 +18,34 @@ } namespace content { +struct FrameNavigateParams; +struct LoadCommittedDetails; +class RenderFrameHost; class WebContents; } +namespace IPC { +class Message; +} + namespace password_manager { -class ContentPasswordManagerDriver : public PasswordManagerDriver, - public content::WebContentsObserver { +// There is one ContentPasswordManagerDriver per RenderFrameHost. +// The lifetime is managed by the ContentPasswordManagerDriverFactory. +class ContentPasswordManagerDriver : public PasswordManagerDriver { public: - ContentPasswordManagerDriver(content::WebContents* web_contents, + ContentPasswordManagerDriver(content::RenderFrameHost* render_frame_host, PasswordManagerClient* client, autofill::AutofillClient* autofill_client); ~ContentPasswordManagerDriver() override; + // Gets the driver for |render_frame_host|. + static ContentPasswordManagerDriver* GetForRenderFrameHost( + content::RenderFrameHost* render_frame_host); + // PasswordManagerDriver implementation. void FillPasswordForm( const autofill::PasswordFormFillData& form_data) override; - bool DidLastPageLoadEncounterSSLErrors() override; - bool IsOffTheRecord() override; void AllowPasswordGenerationForForm( const autofill::PasswordForm& form) override; void AccountCreationFormsFound( @@ -52,14 +61,20 @@ autofill::AutofillManager* GetAutofillManager() override; PasswordAutofillManager* GetPasswordAutofillManager() override; - // content::WebContentsObserver overrides. - bool OnMessageReceived(const IPC::Message& message) override; - void DidNavigateMainFrame( - const content::LoadCommittedDetails& details, - const content::FrameNavigateParams& params) override; + bool HandleMessage(const IPC::Message& message); + void DidNavigateFrame(const content::LoadCommittedDetails& details, + const content::FrameNavigateParams& params); + + // Pass-throughs to PasswordManager. + void OnPasswordFormsParsed(const std::vector<autofill::PasswordForm>& forms); + void OnPasswordFormsRendered( + const std::vector<autofill::PasswordForm>& visible_forms, + bool did_stop_loading); + void OnPasswordFormSubmitted(const autofill::PasswordForm& password_form); private: - PasswordManager password_manager_; + content::RenderFrameHost* render_frame_host_; + PasswordManagerClient* client_; PasswordGenerationManager password_generation_manager_; PasswordAutofillManager password_autofill_manager_;
diff --git a/components/password_manager/content/browser/content_password_manager_driver_factory.cc b/components/password_manager/content/browser/content_password_manager_driver_factory.cc new file mode 100644 index 0000000..28c56ea --- /dev/null +++ b/components/password_manager/content/browser/content_password_manager_driver_factory.cc
@@ -0,0 +1,114 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/password_manager/content/browser/content_password_manager_driver_factory.h" + +#include "base/bind.h" +#include "base/stl_util.h" +#include "components/autofill/content/browser/content_autofill_driver.h" +#include "components/autofill/content/browser/content_autofill_driver_factory.h" +#include "components/autofill/content/common/autofill_messages.h" +#include "components/autofill/core/common/form_data.h" +#include "components/autofill/core/common/password_form.h" +#include "components/password_manager/content/browser/content_password_manager_driver.h" +#include "components/password_manager/core/browser/password_manager_client.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/navigation_details.h" +#include "content/public/browser/navigation_entry.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/web_contents.h" +#include "content/public/common/ssl_status.h" +#include "ipc/ipc_message_macros.h" +#include "net/cert/cert_status_flags.h" + +namespace password_manager { + +namespace { + +const char kContentPasswordManagerDriverFactoryWebContentsUserDataKey[] = + "web_contents_password_manager_driver_factory"; + +} // namespace + +void ContentPasswordManagerDriverFactory::CreateForWebContents( + content::WebContents* web_contents, + PasswordManagerClient* password_client, + autofill::AutofillClient* autofill_client) { + if (FromWebContents(web_contents)) + return; + + web_contents->SetUserData( + kContentPasswordManagerDriverFactoryWebContentsUserDataKey, + new ContentPasswordManagerDriverFactory(web_contents, password_client, + autofill_client)); +} + +ContentPasswordManagerDriverFactory::ContentPasswordManagerDriverFactory( + content::WebContents* web_contents, + PasswordManagerClient* password_client, + autofill::AutofillClient* autofill_client) + : content::WebContentsObserver(web_contents), + password_client_(password_client), + autofill_client_(autofill_client) { + web_contents->ForEachFrame( + base::Bind(&ContentPasswordManagerDriverFactory::CreateDriverForFrame, + base::Unretained(this))); +} + +ContentPasswordManagerDriverFactory::~ContentPasswordManagerDriverFactory() { + STLDeleteContainerPairSecondPointers(frame_driver_map_.begin(), + frame_driver_map_.end()); + frame_driver_map_.clear(); +} + +// static +ContentPasswordManagerDriverFactory* +ContentPasswordManagerDriverFactory::FromWebContents( + content::WebContents* contents) { + return static_cast<ContentPasswordManagerDriverFactory*>( + contents->GetUserData( + kContentPasswordManagerDriverFactoryWebContentsUserDataKey)); +} + +ContentPasswordManagerDriver* +ContentPasswordManagerDriverFactory::GetDriverForFrame( + content::RenderFrameHost* render_frame_host) { + return frame_driver_map_[render_frame_host]; +} + +void ContentPasswordManagerDriverFactory::RenderFrameCreated( + content::RenderFrameHost* render_frame_host) { + // The driver for the main frame will have already been created. + if (!frame_driver_map_[render_frame_host]) + CreateDriverForFrame(render_frame_host); +} + +void ContentPasswordManagerDriverFactory::RenderFrameDeleted( + content::RenderFrameHost* render_frame_host) { + delete frame_driver_map_[render_frame_host]; + frame_driver_map_.erase(render_frame_host); +} + +bool ContentPasswordManagerDriverFactory::OnMessageReceived( + const IPC::Message& message, + content::RenderFrameHost* render_frame_host) { + return frame_driver_map_[render_frame_host]->HandleMessage(message); +} + +void ContentPasswordManagerDriverFactory::DidNavigateAnyFrame( + content::RenderFrameHost* render_frame_host, + const content::LoadCommittedDetails& details, + const content::FrameNavigateParams& params) { + frame_driver_map_[render_frame_host]->DidNavigateFrame(details, params); +} + +void ContentPasswordManagerDriverFactory::CreateDriverForFrame( + content::RenderFrameHost* render_frame_host) { + DCHECK(!frame_driver_map_[render_frame_host]); + frame_driver_map_[render_frame_host] = new ContentPasswordManagerDriver( + render_frame_host, password_client_, autofill_client_); +} + +} // namespace password_manager
diff --git a/components/password_manager/content/browser/content_password_manager_driver_factory.h b/components/password_manager/content/browser/content_password_manager_driver_factory.h new file mode 100644 index 0000000..9fb0573 --- /dev/null +++ b/components/password_manager/content/browser/content_password_manager_driver_factory.h
@@ -0,0 +1,75 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_PASSWORD_MANAGER_CONTENT_BROWSER_CONTENT_PASSWORD_MANAGER_DRIVER_FACTORY_H_ +#define COMPONENTS_PASSWORD_MANAGER_CONTENT_BROWSER_CONTENT_PASSWORD_MANAGER_DRIVER_FACTORY_H_ + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/supports_user_data.h" +#include "components/password_manager/core/browser/password_autofill_manager.h" +#include "components/password_manager/core/browser/password_generation_manager.h" +#include "components/password_manager/core/browser/password_manager.h" +#include "components/password_manager/core/browser/password_manager_driver.h" +#include "content/public/browser/web_contents_observer.h" + +namespace autofill { +class AutofillManager; +struct PasswordForm; +} + +namespace content { +class WebContents; +} + +namespace password_manager { + +class ContentPasswordManagerDriver; + +// Creates and owns ContentPasswordManagerDrivers. There is one +// factory per WebContents, and one driver per render frame. +class ContentPasswordManagerDriverFactory + : public content::WebContentsObserver, + public base::SupportsUserData::Data { + public: + static void CreateForWebContents(content::WebContents* web_contents, + PasswordManagerClient* client, + autofill::AutofillClient* autofill_client); + ~ContentPasswordManagerDriverFactory() override; + + static ContentPasswordManagerDriverFactory* FromWebContents( + content::WebContents* web_contents); + + ContentPasswordManagerDriver* GetDriverForFrame( + content::RenderFrameHost* render_frame_host); + + // content::WebContentsObserver: + bool OnMessageReceived(const IPC::Message& message, + content::RenderFrameHost* render_frame_host) override; + void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override; + void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override; + void DidNavigateAnyFrame(content::RenderFrameHost* render_frame_host, + const content::LoadCommittedDetails& details, + const content::FrameNavigateParams& params) override; + + private: + ContentPasswordManagerDriverFactory( + content::WebContents* web_contents, + PasswordManagerClient* client, + autofill::AutofillClient* autofill_client); + + void CreateDriverForFrame(content::RenderFrameHost* render_frame_host); + + std::map<content::RenderFrameHost*, ContentPasswordManagerDriver*> + frame_driver_map_; + + PasswordManagerClient* password_client_; + autofill::AutofillClient* autofill_client_; + + DISALLOW_COPY_AND_ASSIGN(ContentPasswordManagerDriverFactory); +}; + +} // namespace password_manager + +#endif // COMPONENTS_PASSWORD_MANAGER_CONTENT_BROWSER_CONTENT_PASSWORD_MANAGER_DRIVER_FACTORY_H_
diff --git a/components/password_manager/content/browser/credential_manager_password_form_manager.cc b/components/password_manager/content/browser/credential_manager_password_form_manager.cc index 6684ccd7..39243ee 100644 --- a/components/password_manager/content/browser/credential_manager_password_form_manager.cc +++ b/components/password_manager/content/browser/credential_manager_password_form_manager.cc
@@ -15,11 +15,12 @@ CredentialManagerPasswordFormManager::CredentialManagerPasswordFormManager( PasswordManagerClient* client, + PasswordManagerDriver* driver, const PasswordForm& observed_form, ContentCredentialManagerDispatcher* dispatcher) - : PasswordFormManager(client->GetDriver()->GetPasswordManager(), + : PasswordFormManager(driver->GetPasswordManager(), client, - client->GetDriver(), + driver, observed_form, true), dispatcher_(dispatcher) {
diff --git a/components/password_manager/content/browser/credential_manager_password_form_manager.h b/components/password_manager/content/browser/credential_manager_password_form_manager.h index d14aa3d..3a17f85b 100644 --- a/components/password_manager/content/browser/credential_manager_password_form_manager.h +++ b/components/password_manager/content/browser/credential_manager_password_form_manager.h
@@ -15,6 +15,7 @@ class ContentCredentialManagerDispatcher; class PasswordManagerClient; +class PasswordManagerDriver; // A PasswordFormManager built to handle PassworForm objects synthesized // by the Credential Manager API. @@ -28,6 +29,7 @@ // This class does not take ownership of |dispatcher|. CredentialManagerPasswordFormManager( PasswordManagerClient* client, + PasswordManagerDriver* driver, const autofill::PasswordForm& observed_form, ContentCredentialManagerDispatcher* dispatcher); ~CredentialManagerPasswordFormManager() override;
diff --git a/components/password_manager/core/browser/BUILD.gn b/components/password_manager/core/browser/BUILD.gn index 74ceca4c..3badcfd6 100644 --- a/components/password_manager/core/browser/BUILD.gn +++ b/components/password_manager/core/browser/BUILD.gn
@@ -42,6 +42,8 @@ "password_manager_internals_service.h", "password_manager_metrics_util.cc", "password_manager_metrics_util.h", + "password_manager_url_collection_experiment.cc", + "password_manager_url_collection_experiment.h", "password_store.cc", "password_store.h", "password_store_change.h",
diff --git a/components/password_manager/core/browser/login_database.cc b/components/password_manager/core/browser/login_database.cc index 60fa6fd..a3f1c9b2 100644 --- a/components/password_manager/core/browser/login_database.cc +++ b/components/password_manager/core/browser/login_database.cc
@@ -428,6 +428,9 @@ ENCRYPTION_RESULT_SUCCESS) return list; + // This logging is only temporary, to investigate http://crbug.com/423327. + VLOG(4) << "AddLogin with signon_realm = " << form.signon_realm; + // You *must* change LoginTableColumns if this query changes. sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE, "INSERT INTO logins " @@ -470,6 +473,9 @@ ENCRYPTION_RESULT_SUCCESS) return PasswordStoreChangeList(); + // This logging is only temporary, to investigate http://crbug.com/423327. + VLOG(4) << "UpdateLogin with signon_realm = " << form.signon_realm; + // Replacement is necessary to deal with updating imported credentials. See // crbug.com/349138 for details. sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE, @@ -532,6 +538,11 @@ } bool LoginDatabase::RemoveLogin(const PasswordForm& form) { + if (form.IsPublicSuffixMatch()) { + // Do not try to remove |form|. It is a modified copy of a password stored + // for a different origin, and it is not contained in the database. + return false; + } // Remove a login by UNIQUE-constrained fields. sql::Statement s(db_.GetCachedStatement(SQL_FROM_HERE, "DELETE FROM logins WHERE " @@ -682,12 +693,17 @@ } else { psl_domain_match_metric = PSL_DOMAIN_MATCH_NOT_USED; s.Assign(db_.GetCachedStatement(SQL_FROM_HERE, sql_query.c_str())); + // This logging is only temporary, to investigate http://crbug.com/423327. + VLOG(4) << "Executing SQL query [" << sql_query << "] with realm [" + << form.signon_realm << "]"; s.BindString(0, form.signon_realm); } while (s.Step()) { scoped_ptr<PasswordForm> new_form(new PasswordForm()); EncryptionResult result = InitPasswordFormFromStatement(new_form.get(), s); + // This logging is only temporary, to investigate http://crbug.com/423327. + VLOG(4) << "Encryption result = " << result; if (result == ENCRYPTION_RESULT_SERVICE_FAILURE) return false; if (result == ENCRYPTION_RESULT_ITEM_FAILURE) @@ -717,6 +733,8 @@ new_form->action = form.action; } } + // This logging is only temporary, to investigate http://crbug.com/423327. + VLOG(4) << "Found form with username " << new_form->username_value; forms->push_back(new_form.release()); } UMA_HISTOGRAM_ENUMERATION("PasswordManager.PslDomainMatchTriggering",
diff --git a/components/password_manager/core/browser/login_database_unittest.cc b/components/password_manager/core/browser/login_database_unittest.cc index 5ec0e2ed..a434891 100644 --- a/components/password_manager/core/browser/login_database_unittest.cc +++ b/components/password_manager/core/browser/login_database_unittest.cc
@@ -305,6 +305,14 @@ EXPECT_EQ(1U, result.size()); EXPECT_EQ("https://mobile.foo.com/", result[0]->signon_realm); EXPECT_EQ("https://foo.com/", result[0]->original_signon_realm); + + // Try to remove PSL matched form + EXPECT_FALSE(db_.RemoveLogin(*result[0])); + delete result[0]; + result.clear(); + // Ensure that the original form is still there + EXPECT_TRUE(db_.GetLogins(form, &result)); + EXPECT_EQ(1U, result.size()); delete result[0]; result.clear(); }
diff --git a/components/password_manager/core/browser/password_autofill_manager.cc b/components/password_manager/core/browser/password_autofill_manager.cc index 810e09dc..87524328 100644 --- a/components/password_manager/core/browser/password_autofill_manager.cc +++ b/components/password_manager/core/browser/password_autofill_manager.cc
@@ -59,8 +59,10 @@ PasswordAutofillManager::PasswordAutofillManager( PasswordManagerClient* password_manager_client, + PasswordManagerDriver* password_manager_driver, autofill::AutofillClient* autofill_client) : password_manager_client_(password_manager_client), + password_manager_driver_(password_manager_driver), autofill_client_(autofill_client), weak_ptr_factory_(this) { } @@ -74,8 +76,7 @@ base::string16 password; if (FindLoginInfo(key, &fill_data) && GetPasswordForUsername(username, fill_data, &password)) { - PasswordManagerDriver* driver = password_manager_client_->GetDriver(); - driver->FillSuggestion(username, password); + password_manager_driver_->FillSuggestion(username, password); return true; } return false; @@ -88,8 +89,7 @@ base::string16 password; if (FindLoginInfo(key, &fill_data) && GetPasswordForUsername(username, fill_data, &password)) { - PasswordManagerDriver* driver = password_manager_client_->GetDriver(); - driver->PreviewSuggestion(username, password); + password_manager_driver_->PreviewSuggestion(username, password); return true; } return false; @@ -184,8 +184,7 @@ } void PasswordAutofillManager::ClearPreviewedForm() { - PasswordManagerDriver* driver = password_manager_client_->GetDriver(); - driver->ClearPreviewedForm(); + password_manager_driver_->ClearPreviewedForm(); } ////////////////////////////////////////////////////////////////////////////////
diff --git a/components/password_manager/core/browser/password_autofill_manager.h b/components/password_manager/core/browser/password_autofill_manager.h index 4ad14b9..4da59ef9 100644 --- a/components/password_manager/core/browser/password_autofill_manager.h +++ b/components/password_manager/core/browser/password_autofill_manager.h
@@ -20,11 +20,13 @@ namespace password_manager { class PasswordManagerClient; +class PasswordManagerDriver; // This class is responsible for filling password forms. class PasswordAutofillManager : public autofill::AutofillPopupDelegate { public: PasswordAutofillManager(PasswordManagerClient* password_manager_client, + PasswordManagerDriver* password_manager_driver, autofill::AutofillClient* autofill_client); virtual ~PasswordAutofillManager(); @@ -92,6 +94,9 @@ // Provides embedder-level operations on passwords. Must outlive |this|. PasswordManagerClient* const password_manager_client_; // weak + // The driver that owns |this|. + PasswordManagerDriver* password_manager_driver_; + autofill::AutofillClient* const autofill_client_; // weak base::WeakPtrFactory<PasswordAutofillManager> weak_ptr_factory_;
diff --git a/components/password_manager/core/browser/password_autofill_manager_unittest.cc b/components/password_manager/core/browser/password_autofill_manager_unittest.cc index e8b5bd2..374081eb 100644 --- a/components/password_manager/core/browser/password_autofill_manager_unittest.cc +++ b/components/password_manager/core/browser/password_autofill_manager_unittest.cc
@@ -46,8 +46,6 @@ class TestPasswordManagerClient : public StubPasswordManagerClient { public: - PasswordManagerDriver* GetDriver() override { return &driver_; } - MockPasswordManagerDriver* mock_driver() { return &driver_; } private: @@ -90,10 +88,10 @@ } void InitializePasswordAutofillManager( - PasswordManagerClient* client, + TestPasswordManagerClient* client, autofill::AutofillClient* autofill_client) { - password_autofill_manager_.reset( - new PasswordAutofillManager(client, autofill_client)); + password_autofill_manager_.reset(new PasswordAutofillManager( + client, client->mock_driver(), autofill_client)); password_autofill_manager_->OnAddPasswordFormMapping(fill_data_id_, fill_data_); }
diff --git a/components/password_manager/core/browser/password_form_manager.cc b/components/password_manager/core/browser/password_form_manager.cc index 88bc8fb..7cff94c 100644 --- a/components/password_manager/core/browser/password_form_manager.cc +++ b/components/password_manager/core/browser/password_form_manager.cc
@@ -355,7 +355,7 @@ void PasswordFormManager::Save() { DCHECK_EQ(state_, POST_MATCHING_PHASE); - DCHECK(!driver_->IsOffTheRecord()); + DCHECK(!client_->IsOffTheRecord()); if (IsNewLogin()) SaveAsNewLogin(true); @@ -516,16 +516,15 @@ // Note that we provide the choices but don't actually prefill a value if: // (1) we are in Incognito mode, (2) the ACTION paths don't match, // or (3) if it matched using public suffix domain matching. - bool wait_for_username = - driver_->IsOffTheRecord() || - observed_form_.action.GetWithEmptyPath() != - preferred_match_->action.GetWithEmptyPath() || - preferred_match_->IsPublicSuffixMatch(); + bool wait_for_username = client_->IsOffTheRecord() || + observed_form_.action.GetWithEmptyPath() != + preferred_match_->action.GetWithEmptyPath() || + preferred_match_->IsPublicSuffixMatch(); if (wait_for_username) manager_action_ = kManagerActionNone; else manager_action_ = kManagerActionAutofilled; - password_manager_->Autofill(observed_form_, best_matches_, + password_manager_->Autofill(driver_, observed_form_, best_matches_, *preferred_match_, wait_for_username); } @@ -574,7 +573,7 @@ // new_form contains the same basic data as observed_form_ (because its the // same form), but with the newly added credentials. - DCHECK(!driver_->IsOffTheRecord()); + DCHECK(!client_->IsOffTheRecord()); PasswordStore* password_store = client_->GetPasswordStore(); if (!password_store) { @@ -648,7 +647,7 @@ // username, or the user selected one of the non-preferred matches, // thus requiring a swap of preferred bits. DCHECK(!IsNewLogin() && pending_credentials_.preferred); - DCHECK(!driver_->IsOffTheRecord()); + DCHECK(!client_->IsOffTheRecord()); PasswordStore* password_store = client_->GetPasswordStore(); if (!password_store) {
diff --git a/components/password_manager/core/browser/password_form_manager_unittest.cc b/components/password_manager/core/browser/password_form_manager_unittest.cc index f81bfbd..4096d9b 100644 --- a/components/password_manager/core/browser/password_form_manager_unittest.cc +++ b/components/password_manager/core/browser/password_form_manager_unittest.cc
@@ -107,7 +107,6 @@ virtual PrefService* GetPrefs() override { return &prefs_; } virtual PasswordStore* GetPasswordStore() override { return password_store_; } - virtual PasswordManagerDriver* GetDriver() override { return &driver_; } void SetFormToFilter(const autofill::PasswordForm& form) { form_to_filter_ = form; @@ -125,10 +124,11 @@ class TestPasswordManager : public PasswordManager { public: - explicit TestPasswordManager(PasswordManagerClient* client) + explicit TestPasswordManager(TestPasswordManagerClient* client) : PasswordManager(client) {} - void Autofill(const autofill::PasswordForm& form_for_autofill, + void Autofill(password_manager::PasswordManagerDriver* driver, + const autofill::PasswordForm& form_for_autofill, const autofill::PasswordFormMap& best_matches, const autofill::PasswordForm& preferred_match, bool wait_for_username) const override { @@ -344,11 +344,9 @@ .WillRepeatedly(Return(false)); TestPasswordManager manager(&client_with_store); - PasswordFormManager form_manager(&manager, - &client_with_store, + PasswordFormManager form_manager(&manager, &client_with_store, client_with_store.mock_driver(), - *observed_form(), - false); + *observed_form(), false); // The suggestion needs to be PSL-matched. saved_match()->original_signon_realm = "www.example.org"; @@ -470,10 +468,8 @@ saved_match()->submit_element.clear(); TestPasswordManagerClient client_with_store(mock_store()); - PasswordFormManager manager(NULL, - &client_with_store, - client_with_store.GetDriver(), - *observed_form(), + PasswordFormManager manager(NULL, &client_with_store, + client_with_store.mock_driver(), *observed_form(), false); EXPECT_CALL(*client_with_store.mock_driver(), IsOffTheRecord()) .WillRepeatedly(Return(false)); @@ -592,10 +588,8 @@ TestPasswordManagerClient client_with_store(password_store.get()); TestPasswordManager password_manager(&client_with_store); - PasswordFormManager manager(&password_manager, - &client_with_store, - client_with_store.GetDriver(), - *observed_form(), + PasswordFormManager manager(&password_manager, &client_with_store, + client_with_store.mock_driver(), *observed_form(), false); EXPECT_CALL(*client_with_store.mock_driver(), AllowPasswordGenerationForForm(_)).Times(1); @@ -630,11 +624,9 @@ .other_possible_usernames.size()); // This time use an alternate username - PasswordFormManager manager_alt(&password_manager, - &client_with_store, - client_with_store.GetDriver(), - *observed_form(), - false); + PasswordFormManager manager_alt(&password_manager, &client_with_store, + client_with_store.mock_driver(), + *observed_form(), false); EXPECT_CALL(*client_with_store.mock_driver(), AllowPasswordGenerationForForm(_)).Times(1); password_store->Clear(); @@ -754,11 +746,9 @@ TEST_F(PasswordFormManagerTest, TestSendNotBlacklistedMessage) { TestPasswordManager password_manager(client()); - PasswordFormManager manager_no_creds(&password_manager, - client(), - client()->GetDriver(), - *observed_form(), - false); + PasswordFormManager manager_no_creds(&password_manager, client(), + client()->mock_driver(), + *observed_form(), false); // First time sign-up attempt. Password store does not contain matching // credentials. AllowPasswordGenerationForForm should be called to send the @@ -773,10 +763,8 @@ // Signing up on a previously visited site. Credentials are found in the // password store, and are not blacklisted. AllowPasswordGenerationForForm // should be called to send the "not blacklisted" message. - PasswordFormManager manager_creds(&password_manager, - client(), - client()->GetDriver(), - *observed_form(), + PasswordFormManager manager_creds(&password_manager, client(), + client()->mock_driver(), *observed_form(), false); EXPECT_CALL(*(client()->mock_driver()), AllowPasswordGenerationForForm(_)) .Times(1); @@ -794,11 +782,8 @@ PasswordForm signup_form(*observed_form()); signup_form.new_password_element = base::ASCIIToUTF16("new_password_field"); - PasswordFormManager manager_dropped_creds(&password_manager, - client(), - client()->GetDriver(), - signup_form, - false); + PasswordFormManager manager_dropped_creds( + &password_manager, client(), client()->mock_driver(), signup_form, false); EXPECT_CALL(*(client()->mock_driver()), AllowPasswordGenerationForForm(_)) .Times(1); EXPECT_CALL(*(client()->mock_driver()), IsOffTheRecord()) @@ -812,11 +797,9 @@ // Signing up on a previously visited site. Credentials are found in the // password store, but they are blacklisted. AllowPasswordGenerationForForm // should not be called and no "not blacklisted" message sent. - PasswordFormManager manager_blacklisted(&password_manager, - client(), - client()->GetDriver(), - *observed_form(), - false); + PasswordFormManager manager_blacklisted(&password_manager, client(), + client()->mock_driver(), + *observed_form(), false); EXPECT_CALL(*(client()->mock_driver()), AllowPasswordGenerationForForm(_)) .Times(0); SimulateFetchMatchingLoginsFromPasswordStore(&manager_blacklisted); @@ -831,10 +814,8 @@ // with different HTML tags for elements. Because of scoring differences, // only the first form will be sent to Autofill(). TestPasswordManager password_manager(client()); - PasswordFormManager manager_match(&password_manager, - client(), - client()->GetDriver(), - *observed_form(), + PasswordFormManager manager_match(&password_manager, client(), + client()->mock_driver(), *observed_form(), false); EXPECT_CALL(*(client()->mock_driver()), AllowPasswordGenerationForForm(_)) .Times(1); @@ -854,11 +835,9 @@ // Same thing, except this time the credentials that don't match quite as // well are generated. They should now be sent to Autofill(). - PasswordFormManager manager_no_match(&password_manager, - client(), - client()->GetDriver(), - *observed_form(), - false); + PasswordFormManager manager_no_match(&password_manager, client(), + client()->mock_driver(), + *observed_form(), false); EXPECT_CALL(*(client()->mock_driver()), AllowPasswordGenerationForForm(_)) .Times(1); @@ -1144,11 +1123,9 @@ second.preferred = false; password_store->AddLogin(second); - PasswordFormManager storing_manager(&password_manager, - &client_with_store, - client_with_store.GetDriver(), - *observed_form(), - false); + PasswordFormManager storing_manager(&password_manager, &client_with_store, + client_with_store.mock_driver(), + *observed_form(), false); storing_manager.FetchMatchingLoginsFromPasswordStore( PasswordStore::ALLOW_PROMPT); RunAllPendingTasks(); @@ -1169,11 +1146,9 @@ storing_manager.Save(); RunAllPendingTasks(); - PasswordFormManager retrieving_manager(&password_manager, - &client_with_store, - client_with_store.GetDriver(), - *observed_form(), - false); + PasswordFormManager retrieving_manager(&password_manager, &client_with_store, + client_with_store.mock_driver(), + *observed_form(), false); retrieving_manager.FetchMatchingLoginsFromPasswordStore( PasswordStore::ALLOW_PROMPT); @@ -1192,11 +1167,9 @@ .WillRepeatedly(Return(false)); // For newly saved passwords, upload a vote for autofill::PASSWORD. - PasswordFormManager form_manager(&password_manager, - &client_with_store, - client_with_store.GetDriver(), - *saved_match(), - false); + PasswordFormManager form_manager(&password_manager, &client_with_store, + client_with_store.mock_driver(), + *saved_match(), false); SimulateMatchingPhase(&form_manager, RESULT_NO_MATCH); PasswordForm form_to_save(*saved_match()); @@ -1213,11 +1186,9 @@ Mock::VerifyAndClearExpectations(&form_manager); // Do not upload a vote if the user is blacklisting the form. - PasswordFormManager blacklist_form_manager(&password_manager, - &client_with_store, - client_with_store.GetDriver(), - *saved_match(), - false); + PasswordFormManager blacklist_form_manager( + &password_manager, &client_with_store, client_with_store.mock_driver(), + *saved_match(), false); SimulateMatchingPhase(&blacklist_form_manager, RESULT_NO_MATCH); EXPECT_CALL(*client_with_store.mock_driver()->mock_autofill_manager(), @@ -1245,10 +1216,8 @@ field.form_control_type = "password"; form.form_data.fields.push_back(field); - PasswordFormManager form_manager(&password_manager, - &client_with_store, - client_with_store.GetDriver(), - form, + PasswordFormManager form_manager(&password_manager, &client_with_store, + client_with_store.mock_driver(), form, false); std::vector<PasswordForm*> result; result.push_back(CreateSavedMatch(false)); @@ -1301,11 +1270,9 @@ form.password_value = ASCIIToUTF16("password"); form.preferred = true; - PasswordFormManager storing_manager(&password_manager, - &client_with_store, - client_with_store.GetDriver(), - *observed_form(), - false); + PasswordFormManager storing_manager(&password_manager, &client_with_store, + client_with_store.mock_driver(), + *observed_form(), false); storing_manager.FetchMatchingLoginsFromPasswordStore( PasswordStore::ALLOW_PROMPT); RunAllPendingTasks(); @@ -1317,11 +1284,9 @@ storing_manager.Save(); RunAllPendingTasks(); - PasswordFormManager retrieving_manager(&password_manager, - &client_with_store, - client_with_store.GetDriver(), - *observed_form(), - false); + PasswordFormManager retrieving_manager(&password_manager, &client_with_store, + client_with_store.mock_driver(), + *observed_form(), false); retrieving_manager.FetchMatchingLoginsFromPasswordStore( PasswordStore::ALLOW_PROMPT);
diff --git a/components/password_manager/core/browser/password_generation_manager.cc b/components/password_manager/core/browser/password_generation_manager.cc index 18e119a..57772506 100644 --- a/components/password_manager/core/browser/password_generation_manager.cc +++ b/components/password_manager/core/browser/password_generation_manager.cc
@@ -15,9 +15,10 @@ namespace password_manager { PasswordGenerationManager::PasswordGenerationManager( - PasswordManagerClient* client) - : client_(client), - driver_(client->GetDriver()) {} + PasswordManagerClient* client, + PasswordManagerDriver* driver) + : client_(client), driver_(driver) { +} PasswordGenerationManager::~PasswordGenerationManager() {}
diff --git a/components/password_manager/core/browser/password_generation_manager.h b/components/password_manager/core/browser/password_generation_manager.h index e3f1bae..da68f76 100644 --- a/components/password_manager/core/browser/password_generation_manager.h +++ b/components/password_manager/core/browser/password_generation_manager.h
@@ -33,7 +33,8 @@ // generate a password. class PasswordGenerationManager { public: - explicit PasswordGenerationManager(PasswordManagerClient* client); + PasswordGenerationManager(PasswordManagerClient* client, + PasswordManagerDriver* driver); virtual ~PasswordGenerationManager(); // Detect account creation forms from forms with autofill type annotated.
diff --git a/components/password_manager/core/browser/password_generation_manager_unittest.cc b/components/password_manager/core/browser/password_generation_manager_unittest.cc index e67620f3..49697522 100644 --- a/components/password_manager/core/browser/password_generation_manager_unittest.cc +++ b/components/password_manager/core/browser/password_generation_manager_unittest.cc
@@ -33,13 +33,11 @@ public: TestPasswordManagerDriver(PasswordManagerClient* client) : password_manager_(client), - password_generation_manager_(client), - password_autofill_manager_(client, NULL), - is_off_the_record_(false) {} + password_generation_manager_(client, this), + password_autofill_manager_(client, this, NULL) {} ~TestPasswordManagerDriver() override {} // PasswordManagerDriver implementation. - bool IsOffTheRecord() override { return is_off_the_record_; } PasswordGenerationManager* GetPasswordGenerationManager() override { return &password_generation_manager_; } @@ -56,16 +54,12 @@ const std::vector<autofill::FormData>& GetFoundAccountCreationForms() { return found_account_creation_forms_; } - void set_is_off_the_record(bool is_off_the_record) { - is_off_the_record_ = is_off_the_record; - } private: PasswordManager password_manager_; PasswordGenerationManager password_generation_manager_; PasswordAutofillManager password_autofill_manager_; std::vector<autofill::FormData> found_account_creation_forms_; - bool is_off_the_record_; }; class TestPasswordManagerClient : public StubPasswordManagerClient { @@ -74,15 +68,16 @@ : prefs_(prefs.Pass()), store_(new TestPasswordStore), driver_(this), - is_sync_enabled_(false) {} + is_sync_enabled_(false), + is_off_the_record_(false) {} ~TestPasswordManagerClient() override { store_->Shutdown(); } + bool IsOffTheRecord() override { return is_off_the_record_; } PasswordStore* GetPasswordStore() override { return store_.get(); } PrefService* GetPrefs() override { return prefs_.get(); } - PasswordManagerDriver* GetDriver() override { return &driver_; } bool IsPasswordSyncEnabled(CustomPassphraseState state) override { return is_sync_enabled_; } @@ -91,11 +86,15 @@ is_sync_enabled_ = enabled; } + TestPasswordManagerDriver* test_driver() { return &driver_; } + void set_is_off_the_record(bool is_otr) { is_off_the_record_ = is_otr; } + private: scoped_ptr<PrefService> prefs_; scoped_refptr<TestPasswordStore> store_; TestPasswordManagerDriver driver_; bool is_sync_enabled_; + bool is_off_the_record_; }; // Unlike the base AutofillMetrics, exposes copy and assignment constructors, @@ -124,12 +123,10 @@ void TearDown() override { client_.reset(); } PasswordGenerationManager* GetGenerationManager() { - return client_->GetDriver()->GetPasswordGenerationManager(); + return client_->test_driver()->GetPasswordGenerationManager(); } - TestPasswordManagerDriver* GetTestDriver() { - return static_cast<TestPasswordManagerDriver*>(client_->GetDriver()); - } + TestPasswordManagerDriver* GetTestDriver() { return client_->test_driver(); } bool IsGenerationEnabled() { return GetGenerationManager()->IsGenerationEnabled(); @@ -217,7 +214,7 @@ // Disable password manager by going incognito. Even though password // syncing is enabled, generation should still // be disabled. - GetTestDriver()->set_is_off_the_record(true); + client_->set_is_off_the_record(true); PrefService* prefs = client_->GetPrefs(); prefs->SetBoolean(prefs::kPasswordManagerSavingEnabled, true); client_->set_is_password_sync_enabled(true);
diff --git a/components/password_manager/core/browser/password_manager.cc b/components/password_manager/core/browser/password_manager.cc index 0db0b4b..7c16d6e3 100644 --- a/components/password_manager/core/browser/password_manager.cc +++ b/components/password_manager/core/browser/password_manager.cc
@@ -126,9 +126,8 @@ #endif PasswordManager::PasswordManager(PasswordManagerClient* client) - : client_(client), driver_(client->GetDriver()) { + : client_(client) { DCHECK(client_); - DCHECK(driver_); saving_passwords_enabled_.Init(prefs::kPasswordManagerSavingEnabled, client_->GetPrefs()); @@ -139,7 +138,9 @@ FOR_EACH_OBSERVER(LoginModelObserver, observers_, OnLoginModelDestroying()); } -void PasswordManager::SetFormHasGeneratedPassword(const PasswordForm& form) { +void PasswordManager::SetFormHasGeneratedPassword( + password_manager::PasswordManagerDriver* driver, + const PasswordForm& form) { DCHECK(IsSavingEnabledForCurrentPage()); for (ScopedVector<PasswordFormManager>::iterator iter = @@ -157,14 +158,14 @@ // ability to detect forms. bool ssl_valid = form.origin.SchemeIsSecure(); PasswordFormManager* manager = - new PasswordFormManager(this, client_, driver_, form, ssl_valid); + new PasswordFormManager(this, client_, driver, form, ssl_valid); pending_login_managers_.push_back(manager); manager->SetHasGeneratedPassword(); // TODO(gcasto): Add UMA stats to track this. } bool PasswordManager::IsEnabledForCurrentPage() const { - bool ssl_errors = driver_->DidLastPageLoadEncounterSSLErrors(); + bool ssl_errors = client_->DidLastPageLoadEncounterSSLErrors(); bool client_check = client_->IsPasswordManagerEnabledForCurrentPage(); scoped_ptr<BrowserSavePasswordProgressLogger> logger; @@ -179,7 +180,7 @@ } bool PasswordManager::IsSavingEnabledForCurrentPage() const { - return *saving_passwords_enabled_ && !driver_->IsOffTheRecord() && + return *saving_passwords_enabled_ && !client_->IsOffTheRecord() && IsEnabledForCurrentPage(); } @@ -194,7 +195,7 @@ form); logger->LogBoolean(Logger::STRING_IS_SAVING_ENABLED, is_saving_enabled); logger->LogBoolean(Logger::STRING_SSL_ERRORS_PRESENT, - driver_->DidLastPageLoadEncounterSSLErrors()); + client_->DidLastPageLoadEncounterSSLErrors()); } if (!is_saving_enabled) { @@ -291,7 +292,7 @@ PasswordForm provisionally_saved_form(form); provisionally_saved_form.ssl_valid = form.origin.SchemeIsSecure() && - !driver_->DidLastPageLoadEncounterSSLErrors(); + !client_->DidLastPageLoadEncounterSSLErrors(); provisionally_saved_form.preferred = true; if (logger) { logger->LogPasswordForm(Logger::STRING_PROVISIONALLY_SAVED_FORM, @@ -324,6 +325,9 @@ failure, MAX_FAILURE_VALUE); } + if (failure == NO_MATCHING_FORM && client_->ShouldAskUserToSubmitURL()) { + client_->AskUserAndMaybeReportURL(form_origin); + } if (logger) { switch (failure) { @@ -372,15 +376,12 @@ void PasswordManager::DidNavigateMainFrame(bool is_in_page) { // Clear data after main frame navigation if the navigation was to a // different page. - if (!is_in_page) { + if (!is_in_page) pending_login_managers_.clear(); - // There is no PasswordAutofillManager on iOS. - if (driver_->GetPasswordAutofillManager()) - driver_->GetPasswordAutofillManager()->Reset(); - } } void PasswordManager::OnPasswordFormSubmitted( + password_manager::PasswordManagerDriver* driver, const PasswordForm& password_form) { ProvisionallySavePassword(password_form); for (size_t i = 0; i < submission_callbacks_.size(); ++i) { @@ -391,11 +392,13 @@ } void PasswordManager::OnPasswordFormsParsed( + password_manager::PasswordManagerDriver* driver, const std::vector<PasswordForm>& forms) { - CreatePendingLoginManagers(forms); + CreatePendingLoginManagers(driver, forms); } void PasswordManager::CreatePendingLoginManagers( + password_manager::PasswordManagerDriver* driver, const std::vector<PasswordForm>& forms) { scoped_ptr<BrowserSavePasswordProgressLogger> logger; if (client_->IsLoggingActive()) { @@ -435,7 +438,7 @@ bool ssl_valid = iter->origin.SchemeIsSecure(); PasswordFormManager* manager = - new PasswordFormManager(this, client_, driver_, *iter, ssl_valid); + new PasswordFormManager(this, client_, driver, *iter, ssl_valid); pending_login_managers_.push_back(manager); PasswordStore::AuthorizationPromptPolicy prompt_policy = @@ -458,9 +461,10 @@ } void PasswordManager::OnPasswordFormsRendered( + password_manager::PasswordManagerDriver* driver, const std::vector<PasswordForm>& visible_forms, bool did_stop_loading) { - CreatePendingLoginManagers(visible_forms); + CreatePendingLoginManagers(driver, visible_forms); scoped_ptr<BrowserSavePasswordProgressLogger> logger; if (client_->IsLoggingActive()) { logger.reset(new BrowserSavePasswordProgressLogger(client_)); @@ -593,7 +597,8 @@ kOtherPossibleUsernamesExperiment) == "Enabled"; } -void PasswordManager::Autofill(const PasswordForm& form_for_autofill, +void PasswordManager::Autofill(password_manager::PasswordManagerDriver* driver, + const PasswordForm& form_for_autofill, const PasswordFormMap& best_matches, const PasswordForm& preferred_match, bool wait_for_username) const { @@ -617,7 +622,7 @@ &fill_data); if (logger) logger->LogBoolean(Logger::STRING_WAIT_FOR_USERNAME, wait_for_username); - driver_->FillPasswordForm(fill_data); + driver->FillPasswordForm(fill_data); break; } default:
diff --git a/components/password_manager/core/browser/password_manager.h b/components/password_manager/core/browser/password_manager.h index c89e6e5..bf0fd63 100644 --- a/components/password_manager/core/browser/password_manager.h +++ b/components/password_manager/core/browser/password_manager.h
@@ -63,7 +63,8 @@ // Called by a PasswordFormManager when it decides a form can be autofilled // on the page. - virtual void Autofill(const autofill::PasswordForm& form_for_autofill, + virtual void Autofill(password_manager::PasswordManagerDriver* driver, + const autofill::PasswordForm& form_for_autofill, const autofill::PasswordFormMap& best_matches, const autofill::PasswordForm& preferred_match, bool wait_for_username) const; @@ -73,7 +74,9 @@ void RemoveObserver(LoginModelObserver* observer) override; // Mark this form as having a generated password. - void SetFormHasGeneratedPassword(const autofill::PasswordForm& form); + void SetFormHasGeneratedPassword( + password_manager::PasswordManagerDriver* driver, + const autofill::PasswordForm& form); // TODO(isherman): This should not be public, but is currently being used by // the LoginPrompt code. @@ -86,16 +89,18 @@ void DidNavigateMainFrame(bool is_in_page); // Handles password forms being parsed. - void OnPasswordFormsParsed( - const std::vector<autofill::PasswordForm>& forms); + void OnPasswordFormsParsed(password_manager::PasswordManagerDriver* driver, + const std::vector<autofill::PasswordForm>& forms); // Handles password forms being rendered. void OnPasswordFormsRendered( + password_manager::PasswordManagerDriver* driver, const std::vector<autofill::PasswordForm>& visible_forms, bool did_stop_loading); // Handles a password form being submitted. virtual void OnPasswordFormSubmitted( + password_manager::PasswordManagerDriver* driver, const autofill::PasswordForm& password_form); PasswordManagerClient* client() { return client_; } @@ -147,6 +152,7 @@ // Checks for every from in |forms| whether |pending_login_managers_| already // contain a manager for that form. If not, adds a manager for each such form. void CreatePendingLoginManagers( + password_manager::PasswordManagerDriver* driver, const std::vector<autofill::PasswordForm>& forms); // Note about how a PasswordFormManager can transition from @@ -176,9 +182,6 @@ // The embedder-level client. Must outlive this class. PasswordManagerClient* const client_; - // The platform-level driver. Must outlive this class. - PasswordManagerDriver* const driver_; - // Set to false to disable password saving (will no longer ask if you // want to save passwords but will continue to fill passwords). BooleanPrefMember saving_passwords_enabled_;
diff --git a/components/password_manager/core/browser/password_manager_client.cc b/components/password_manager/core/browser/password_manager_client.cc index 9c32995..c914e4e 100644 --- a/components/password_manager/core/browser/password_manager_client.cc +++ b/components/password_manager/core/browser/password_manager_client.cc
@@ -20,6 +20,10 @@ return 0; } +void PasswordManagerClient::AskUserAndMaybeReportURL( + const std::string& url) const { +} + bool PasswordManagerClient::IsPasswordSyncEnabled(CustomPassphraseState state) { return false; } @@ -36,6 +40,10 @@ return false; } +bool PasswordManagerClient::ShouldAskUserToSubmitURL() { + return false; +} + bool PasswordManagerClient::WasLastNavigationHTTPError() const { return false; } @@ -56,4 +64,16 @@ return PasswordStore::DISALLOW_PROMPT; } +bool PasswordManagerClient::DidLastPageLoadEncounterSSLErrors() { + return false; +} + +bool PasswordManagerClient::IsOffTheRecord() { + return false; +} + +PasswordManager* PasswordManagerClient::GetPasswordManager() { + return nullptr; +} + } // namespace password_manager
diff --git a/components/password_manager/core/browser/password_manager_client.h b/components/password_manager/core/browser/password_manager_client.h index 4953eed..085ade8 100644 --- a/components/password_manager/core/browser/password_manager_client.h +++ b/components/password_manager/core/browser/password_manager_client.h
@@ -16,6 +16,7 @@ struct CredentialInfo; class PasswordFormManager; +class PasswordManager; class PasswordManagerDriver; class PasswordStore; @@ -41,6 +42,11 @@ // always returns true. virtual bool IsPasswordManagerEnabledForCurrentPage() const; + // Return true if "Allow to collect URL?" should be shown. + // TODO(vabr): If http://crbug.com/437528 gets fixed, make this a const + // method. + virtual bool ShouldAskUserToSubmitURL(); + // Return true if |form| should not be available for autofill. virtual bool ShouldFilterAutofillResult( const autofill::PasswordForm& form) = 0; @@ -54,6 +60,11 @@ virtual bool IsSyncAccountCredential( const std::string& username, const std::string& origin) const = 0; + // This should be called if the password manager encounters a problem on + // |url|. The implementation should show the "Allow to collect URL?" bubble + // and, if the user confirms, report the |url|. + virtual void AskUserAndMaybeReportURL(const std::string& url) const; + // Called when all autofill results have been computed. Client can use // this signal to report statistics. Default implementation is a noop. virtual void AutofillResultsComputed() {} @@ -99,9 +110,6 @@ // Returns the PasswordStore associated with this instance. virtual PasswordStore* GetPasswordStore() = 0; - // Returns the PasswordManagerDriver instance associated with this instance. - virtual PasswordManagerDriver* GetDriver() = 0; - // Returns the probability that the experiment identified by |experiment_name| // should be enabled. The default implementation returns 0. virtual base::FieldTrial::Probability GetProbabilityForExperiment( @@ -133,6 +141,16 @@ virtual PasswordStore::AuthorizationPromptPolicy GetAuthorizationPromptPolicy( const autofill::PasswordForm& form); + // Returns whether any SSL certificate errors were encountered as a result of + // the last page load. + virtual bool DidLastPageLoadEncounterSSLErrors(); + + // If this browsing session should not be persisted. + virtual bool IsOffTheRecord(); + + // Returns the PasswordManager associated with this client. + virtual PasswordManager* GetPasswordManager(); + private: DISALLOW_COPY_AND_ASSIGN(PasswordManagerClient); };
diff --git a/components/password_manager/core/browser/password_manager_driver.h b/components/password_manager/core/browser/password_manager_driver.h index 6e01c55..9d5ca68 100644 --- a/components/password_manager/core/browser/password_manager_driver.h +++ b/components/password_manager/core/browser/password_manager_driver.h
@@ -34,13 +34,6 @@ virtual void FillPasswordForm( const autofill::PasswordFormFillData& form_data) = 0; - // Returns whether any SSL certificate errors were encountered as a result of - // the last page load. - virtual bool DidLastPageLoadEncounterSSLErrors() = 0; - - // If this browsing session should not be persisted. - virtual bool IsOffTheRecord() = 0; - // Informs the driver that |form| can be used for password generation. virtual void AllowPasswordGenerationForForm( const autofill::PasswordForm& form) = 0;
diff --git a/components/password_manager/core/browser/password_manager_unittest.cc b/components/password_manager/core/browser/password_manager_unittest.cc index 11560795..a68ca3b 100644 --- a/components/password_manager/core/browser/password_manager_unittest.cc +++ b/components/password_manager/core/browser/password_manager_unittest.cc
@@ -46,6 +46,7 @@ MOCK_METHOD0(GetPasswordStore, PasswordStore*()); MOCK_METHOD0(GetPrefs, PrefService*()); MOCK_METHOD0(GetDriver, PasswordManagerDriver*()); + MOCK_METHOD0(DidLastPageLoadEncounterSSLErrors, bool()); // Workaround for scoped_ptr<> lacking a copy constructor. virtual bool PromptUserToSavePassword( @@ -64,7 +65,6 @@ MOCK_METHOD1(FillPasswordForm, void(const autofill::PasswordFormFillData&)); MOCK_METHOD0(GetPasswordManager, PasswordManager*()); MOCK_METHOD0(GetPasswordAutofillManager, PasswordAutofillManager*()); - MOCK_METHOD0(DidLastPageLoadEncounterSSLErrors, bool()); }; ACTION_P(InvokeConsumer, forms) { arg0->OnGetPasswordStoreResults(forms); } @@ -104,13 +104,13 @@ manager_.reset(new TestPasswordManager(&client_)); password_autofill_manager_.reset( - new PasswordAutofillManager(&client_, NULL)); + new PasswordAutofillManager(&client_, client_.GetDriver(), NULL)); EXPECT_CALL(driver_, GetPasswordManager()) .WillRepeatedly(Return(manager_.get())); EXPECT_CALL(driver_, GetPasswordAutofillManager()) .WillRepeatedly(Return(password_autofill_manager_.get())); - EXPECT_CALL(driver_, DidLastPageLoadEncounterSSLErrors()) + EXPECT_CALL(client_, DidLastPageLoadEncounterSSLErrors()) .WillRepeatedly(Return(false)); } @@ -209,7 +209,7 @@ TestPasswordManager* manager() { return manager_.get(); } void OnPasswordFormSubmitted(const autofill::PasswordForm& form) { - manager()->OnPasswordFormSubmitted(form); + manager()->OnPasswordFormSubmitted(&driver_, form); } PasswordManager::PasswordSubmittedCallback SubmissionCallback() { @@ -249,8 +249,10 @@ std::vector<PasswordForm> observed; PasswordForm form(MakeSimpleForm()); observed.push_back(form); - manager()->OnPasswordFormsParsed(observed); // The initial load. - manager()->OnPasswordFormsRendered(observed, true); // The initial layout. + // The initial load. + manager()->OnPasswordFormsParsed(&driver_, observed); + // The initial layout. + manager()->OnPasswordFormsRendered(&driver_, observed, true); // And the form submit contract is to call ProvisionallySavePassword. manager()->ProvisionallySavePassword(form); @@ -261,9 +263,10 @@ // Now the password manager waits for the navigation to complete. observed.clear(); - manager()->OnPasswordFormsParsed(observed); // The post-navigation load. - manager()->OnPasswordFormsRendered(observed, - true); // The post-navigation layout. + // The post-navigation load. + manager()->OnPasswordFormsParsed(&driver_, observed); + // The post-navigation layout. + manager()->OnPasswordFormsRendered(&driver_, observed, true); ASSERT_TRUE(form_to_save.get()); EXPECT_CALL(*store_.get(), AddLogin(FormMatches(form))); @@ -283,8 +286,8 @@ std::vector<PasswordForm> observed; PasswordForm form(MakeFormWithOnlyNewPasswordField()); observed.push_back(form); - manager()->OnPasswordFormsParsed(observed); - manager()->OnPasswordFormsRendered(observed, true); + manager()->OnPasswordFormsParsed(&driver_, observed); + manager()->OnPasswordFormsRendered(&driver_, observed, true); // And the form submit contract is to call ProvisionallySavePassword. manager()->ProvisionallySavePassword(form); @@ -295,8 +298,8 @@ // Now the password manager waits for the navigation to complete. observed.clear(); - manager()->OnPasswordFormsParsed(observed); - manager()->OnPasswordFormsRendered(observed, true); + manager()->OnPasswordFormsParsed(&driver_, observed); + manager()->OnPasswordFormsRendered(&driver_, observed, true); ASSERT_TRUE(form_to_save.get()); @@ -327,11 +330,13 @@ std::vector<PasswordForm> observed; PasswordForm form(MakeSimpleForm()); observed.push_back(form); - manager()->OnPasswordFormsParsed(observed); // The initial load. - manager()->OnPasswordFormsRendered(observed, true); // The initial layout. + // The initial load. + manager()->OnPasswordFormsParsed(&driver_, observed); + // The initial layout. + manager()->OnPasswordFormsRendered(&driver_, observed, true); // Simulate the user generating the password and submitting the form. - manager()->SetFormHasGeneratedPassword(form); + manager()->SetFormHasGeneratedPassword(&driver_, form); manager()->ProvisionallySavePassword(form); // The user should not be presented with an infobar as they have already given @@ -346,8 +351,9 @@ // Now the password manager waits for the navigation to complete. observed.clear(); - manager()->OnPasswordFormsParsed(observed); // The post-navigation load. - manager()->OnPasswordFormsRendered(observed, + manager()->OnPasswordFormsParsed(&driver_, + observed); // The post-navigation load. + manager()->OnPasswordFormsRendered(&driver_, observed, true); // The post-navigation layout. } @@ -366,8 +372,9 @@ std::vector<PasswordForm> observed; PasswordForm form(MakeSimpleForm()); observed.push_back(form); - manager()->OnPasswordFormsParsed(observed); // The initial load. - manager()->OnPasswordFormsRendered(observed, true); // The initial layout. + manager()->OnPasswordFormsParsed(&driver_, observed); // The initial load. + manager()->OnPasswordFormsRendered(&driver_, observed, + true); // The initial layout. manager()->ProvisionallySavePassword(form); // We still expect an add, since we didn't have a good match. @@ -377,8 +384,9 @@ // Now the password manager waits for the navigation to complete. observed.clear(); - manager()->OnPasswordFormsParsed(observed); // The post-navigation load. - manager()->OnPasswordFormsRendered(observed, + manager()->OnPasswordFormsParsed(&driver_, + observed); // The post-navigation load. + manager()->OnPasswordFormsRendered(&driver_, observed, true); // The post-navigation layout. ASSERT_TRUE(form_to_save.get()); @@ -396,15 +404,17 @@ std::vector<PasswordForm> observed; PasswordForm form(MakeSimpleForm()); observed.push_back(form); - manager()->OnPasswordFormsParsed(observed); // The initial load. - manager()->OnPasswordFormsRendered(observed, true); // The initial layout. + manager()->OnPasswordFormsParsed(&driver_, observed); // The initial load. + manager()->OnPasswordFormsRendered(&driver_, observed, + true); // The initial layout. // No message from the renderer that a password was submitted. No // expected calls. EXPECT_CALL(client_, PromptUserToSavePasswordPtr(_)).Times(0); observed.clear(); - manager()->OnPasswordFormsParsed(observed); // The post-navigation load. - manager()->OnPasswordFormsRendered(observed, + manager()->OnPasswordFormsParsed(&driver_, + observed); // The post-navigation load. + manager()->OnPasswordFormsRendered(&driver_, observed, true); // The post-navigation layout. } @@ -418,8 +428,9 @@ std::vector<PasswordForm> observed; PasswordForm form(MakeSimpleForm()); observed.push_back(form); - manager()->OnPasswordFormsParsed(observed); // The initial load. - manager()->OnPasswordFormsRendered(observed, true); // The initial layout. + manager()->OnPasswordFormsParsed(&driver_, observed); // The initial load. + manager()->OnPasswordFormsRendered(&driver_, observed, + true); // The initial layout. // Simulate navigating in the page. manager()->DidNavigateMainFrame(true); @@ -433,8 +444,9 @@ .WillOnce(WithArg<0>(SaveToScopedPtr(&form_to_save))); observed.clear(); - manager()->OnPasswordFormsParsed(observed); // The post-navigation load. - manager()->OnPasswordFormsRendered(observed, + manager()->OnPasswordFormsParsed(&driver_, + observed); // The post-navigation load. + manager()->OnPasswordFormsRendered(&driver_, observed, true); // The post-navigation layout. ASSERT_FALSE(NULL == form_to_save.get()); @@ -462,9 +474,9 @@ // Pretend that the form is hidden on the first page. std::vector<PasswordForm> observed; observed.push_back(first_form); - manager()->OnPasswordFormsParsed(observed); + manager()->OnPasswordFormsParsed(&driver_, observed); observed.clear(); - manager()->OnPasswordFormsRendered(observed, true); + manager()->OnPasswordFormsRendered(&driver_, observed, true); // Now navigate to a second page. manager()->DidNavigateMainFrame(false); @@ -472,8 +484,8 @@ // This page contains a form with the same markup, but on a different // URL. observed.push_back(second_form); - manager()->OnPasswordFormsParsed(observed); - manager()->OnPasswordFormsRendered(observed, true); + manager()->OnPasswordFormsParsed(&driver_, observed); + manager()->OnPasswordFormsRendered(&driver_, observed, true); // Now submit this form OnPasswordFormSubmitted(second_form); @@ -483,8 +495,8 @@ EXPECT_CALL(client_, PromptUserToSavePasswordPtr(_)) .WillOnce(WithArg<0>(SaveToScopedPtr(&form_to_save))); observed.clear(); - manager()->OnPasswordFormsParsed(observed); - manager()->OnPasswordFormsRendered(observed, true); + manager()->OnPasswordFormsParsed(&driver_, observed); + manager()->OnPasswordFormsRendered(&driver_, observed, true); // Make sure that the saved form matches the second form, not the first. ASSERT_TRUE(form_to_save.get()); @@ -502,15 +514,16 @@ std::vector<PasswordForm> observed; PasswordForm form(MakeSimpleForm()); observed.push_back(form); - manager()->OnPasswordFormsParsed(observed); // The initial load. - manager()->OnPasswordFormsRendered(observed, true); // The initial layout. + manager()->OnPasswordFormsParsed(&driver_, observed); // The initial load. + manager()->OnPasswordFormsRendered(&driver_, observed, + true); // The initial layout. manager()->ProvisionallySavePassword(form); // The form reappears, and is visible in the layout: // No expected calls to the PasswordStore... - manager()->OnPasswordFormsParsed(observed); - manager()->OnPasswordFormsRendered(observed, true); + manager()->OnPasswordFormsParsed(&driver_, observed); + manager()->OnPasswordFormsRendered(&driver_, observed, true); } TEST_F(PasswordManagerTest, FormSubmitInvisibleLogin) { @@ -523,8 +536,9 @@ std::vector<PasswordForm> observed; PasswordForm form(MakeSimpleForm()); observed.push_back(form); - manager()->OnPasswordFormsParsed(observed); // The initial load. - manager()->OnPasswordFormsRendered(observed, true); // The initial layout. + manager()->OnPasswordFormsParsed(&driver_, observed); // The initial load. + manager()->OnPasswordFormsRendered(&driver_, observed, + true); // The initial layout. manager()->ProvisionallySavePassword(form); @@ -534,9 +548,9 @@ .WillOnce(WithArg<0>(SaveToScopedPtr(&form_to_save))); // The form reappears, but is not visible in the layout: - manager()->OnPasswordFormsParsed(observed); + manager()->OnPasswordFormsParsed(&driver_, observed); observed.clear(); - manager()->OnPasswordFormsRendered(observed, true); + manager()->OnPasswordFormsRendered(&driver_, observed, true); ASSERT_TRUE(form_to_save.get()); EXPECT_CALL(*store_.get(), AddLogin(FormMatches(form))); @@ -556,12 +570,14 @@ std::vector<PasswordForm> observed; PasswordForm form(MakeSimpleForm()); observed.push_back(form); - manager()->OnPasswordFormsParsed(observed); // The initial load. + manager()->OnPasswordFormsParsed(&driver_, observed); // The initial load. observed.clear(); - manager()->OnPasswordFormsRendered(observed, true); // The initial layout. + manager()->OnPasswordFormsRendered(&driver_, observed, + true); // The initial layout. - manager()->OnPasswordFormsParsed(observed); // The post-navigation load. - manager()->OnPasswordFormsRendered(observed, + manager()->OnPasswordFormsParsed(&driver_, + observed); // The post-navigation load. + manager()->OnPasswordFormsRendered(&driver_, observed, true); // The post-navigation layout. } @@ -591,7 +607,7 @@ std::vector<PasswordForm> observed; PasswordForm form(MakeSimpleForm()); observed.push_back(form); - manager()->OnPasswordFormsParsed(observed); + manager()->OnPasswordFormsParsed(&driver_, observed); } TEST_F(PasswordManagerTest, FormSavedWithAutocompleteOff) { @@ -605,8 +621,9 @@ PasswordForm form(MakeSimpleForm()); form.password_autocomplete_set = false; observed.push_back(form); - manager()->OnPasswordFormsParsed(observed); // The initial load. - manager()->OnPasswordFormsRendered(observed, true); // The initial layout. + manager()->OnPasswordFormsParsed(&driver_, observed); // The initial load. + manager()->OnPasswordFormsRendered(&driver_, observed, + true); // The initial layout. // And the form submit contract is to call ProvisionallySavePassword. manager()->ProvisionallySavePassword(form); @@ -619,8 +636,9 @@ // Now the password manager waits for the navigation to complete. observed.clear(); - manager()->OnPasswordFormsParsed(observed); // The post-navigation load. - manager()->OnPasswordFormsRendered(observed, + manager()->OnPasswordFormsParsed(&driver_, + observed); // The post-navigation load. + manager()->OnPasswordFormsRendered(&driver_, observed, true); // The post-navigation layout. ASSERT_TRUE(form_to_save.get()); @@ -637,11 +655,12 @@ PasswordForm form(MakeSimpleForm()); form.password_autocomplete_set = false; observed.push_back(form); - manager()->OnPasswordFormsParsed(observed); // The initial load. - manager()->OnPasswordFormsRendered(observed, true); // The initial layout. + manager()->OnPasswordFormsParsed(&driver_, observed); // The initial load. + manager()->OnPasswordFormsRendered(&driver_, observed, + true); // The initial layout. // Simulate the user generating the password and submitting the form. - manager()->SetFormHasGeneratedPassword(form); + manager()->SetFormHasGeneratedPassword(&driver_, form); manager()->ProvisionallySavePassword(form); // The user should not be presented with an infobar as they have already given @@ -656,8 +675,9 @@ // Now the password manager waits for the navigation to complete. observed.clear(); - manager()->OnPasswordFormsParsed(observed); // The post-navigation load. - manager()->OnPasswordFormsRendered(observed, + manager()->OnPasswordFormsParsed(&driver_, + observed); // The post-navigation load. + manager()->OnPasswordFormsRendered(&driver_, observed, true); // The post-navigation layout. } @@ -680,8 +700,9 @@ std::vector<PasswordForm> observed; PasswordForm login_form(MakeTwitterLoginForm()); observed.push_back(login_form); - manager()->OnPasswordFormsParsed(observed); // The initial load. - manager()->OnPasswordFormsRendered(observed, true); // The initial layout. + manager()->OnPasswordFormsParsed(&driver_, observed); // The initial load. + manager()->OnPasswordFormsRendered(&driver_, observed, + true); // The initial layout. manager()->ProvisionallySavePassword(login_form); @@ -690,12 +711,12 @@ observed.push_back(failed_login_form); // A PasswordForm appears, and is visible in the layout: // No expected calls to the PasswordStore... - manager()->OnPasswordFormsParsed(observed); - manager()->OnPasswordFormsRendered(observed, true); + manager()->OnPasswordFormsParsed(&driver_, observed); + manager()->OnPasswordFormsRendered(&driver_, observed, true); } TEST_F(PasswordManagerTest, SavingNotEnabledOnSSLErrors) { - EXPECT_CALL(driver_, DidLastPageLoadEncounterSSLErrors()) + EXPECT_CALL(client_, DidLastPageLoadEncounterSSLErrors()) .WillRepeatedly(Return(true)); EXPECT_FALSE(manager()->IsSavingEnabledForCurrentPage()); } @@ -703,7 +724,7 @@ TEST_F(PasswordManagerTest, AutofillingNotEnabledOnSSLErrors) { // Test that in the presence of SSL errors, the password manager does not // attempt to autofill forms found on a website. - EXPECT_CALL(driver_, DidLastPageLoadEncounterSSLErrors()) + EXPECT_CALL(client_, DidLastPageLoadEncounterSSLErrors()) .WillRepeatedly(Return(true)); // Let us pretend some forms were found on a website. @@ -713,7 +734,7 @@ // Feed those forms to |manager()| and check that it does not try to find // matching saved credentials for the forms. EXPECT_CALL(*store_.get(), GetLogins(_, _, _)).Times(Exactly(0)); - manager()->OnPasswordFormsParsed(forms); + manager()->OnPasswordFormsParsed(&driver_, forms); } TEST_F(PasswordManagerTest, SavingDisabledIfManagerDisabled) { @@ -733,7 +754,7 @@ // Feed those forms to |manager()| and check that it does not try to find // matching saved credentials for the forms. EXPECT_CALL(*store_.get(), GetLogins(_, _, _)).Times(Exactly(0)); - manager()->OnPasswordFormsParsed(forms); + manager()->OnPasswordFormsParsed(&driver_, forms); } TEST_F(PasswordManagerTest, SyncCredentialsNotSaved) { @@ -749,8 +770,9 @@ PasswordForm form(MakeSimpleForm()); form.password_autocomplete_set = false; observed.push_back(form); - manager()->OnPasswordFormsParsed(observed); // The initial load. - manager()->OnPasswordFormsRendered(observed, true); // The initial layout. + manager()->OnPasswordFormsParsed(&driver_, observed); // The initial load. + manager()->OnPasswordFormsRendered(&driver_, observed, + true); // The initial layout. // User should not be prompted and password should not be saved. EXPECT_CALL(client_, PromptUserToSavePasswordPtr(_)).Times(Exactly(0)); @@ -759,8 +781,8 @@ // Submit form and finish navigation. manager()->ProvisionallySavePassword(form); observed.clear(); - manager()->OnPasswordFormsParsed(observed); - manager()->OnPasswordFormsRendered(observed, true); + manager()->OnPasswordFormsParsed(&driver_, observed); + manager()->OnPasswordFormsRendered(&driver_, observed, true); } // On failed login attempts, the retry-form can have action scheme changed from @@ -784,8 +806,8 @@ std::vector<PasswordForm> observed; observed.push_back(first_form); - manager()->OnPasswordFormsParsed(observed); - manager()->OnPasswordFormsRendered(observed, true); + manager()->OnPasswordFormsParsed(&driver_, observed); + manager()->OnPasswordFormsRendered(&driver_, observed, true); observed.clear(); // Now submit the |first_form|. @@ -797,8 +819,8 @@ // Verify that no prompt to save the password is shown. EXPECT_CALL(client_, PromptUserToSavePasswordPtr(_)).Times(Exactly(0)); - manager()->OnPasswordFormsParsed(observed); - manager()->OnPasswordFormsRendered(observed, true); + manager()->OnPasswordFormsParsed(&driver_, observed); + manager()->OnPasswordFormsRendered(&driver_, observed, true); observed.clear(); } @@ -813,8 +835,9 @@ form.new_password_element = ASCIIToUTF16("new_password_element"); form.new_password_value.clear(); observed.push_back(form); - manager()->OnPasswordFormsParsed(observed); // The initial load. - manager()->OnPasswordFormsRendered(observed, true); // The initial layout. + manager()->OnPasswordFormsParsed(&driver_, observed); // The initial load. + manager()->OnPasswordFormsRendered(&driver_, observed, + true); // The initial layout. // And the form submit contract is to call ProvisionallySavePassword. OnPasswordFormSubmitted(form); @@ -824,8 +847,9 @@ // Now the password manager waits for the login to complete successfully. observed.clear(); - manager()->OnPasswordFormsParsed(observed); // The post-navigation load. - manager()->OnPasswordFormsRendered(observed, + manager()->OnPasswordFormsParsed(&driver_, + observed); // The post-navigation load. + manager()->OnPasswordFormsRendered(&driver_, observed, true); // The post-navigation layout. } @@ -842,8 +866,9 @@ // Loads passsword form without username input field. PasswordForm form(MakeSimpleFormWithOnlyPasswordField()); observed.push_back(form); - manager()->OnPasswordFormsParsed(observed); // The initial load. - manager()->OnPasswordFormsRendered(observed, true); // The initial layout. + manager()->OnPasswordFormsParsed(&driver_, observed); // The initial load. + manager()->OnPasswordFormsRendered(&driver_, observed, + true); // The initial layout. // And the form submit contract is to call ProvisionallySavePassword. manager()->ProvisionallySavePassword(form); @@ -854,8 +879,9 @@ // Now the password manager waits for the navigation to complete. observed.clear(); - manager()->OnPasswordFormsParsed(observed); // The post-navigation load. - manager()->OnPasswordFormsRendered(observed, + manager()->OnPasswordFormsParsed(&driver_, + observed); // The post-navigation load. + manager()->OnPasswordFormsRendered(&driver_, observed, true); // The post-navigation layout. ASSERT_TRUE(form_to_save.get());
diff --git a/components/password_manager/core/browser/password_manager_url_collection_experiment.cc b/components/password_manager/core/browser/password_manager_url_collection_experiment.cc new file mode 100644 index 0000000..b8d66c5e --- /dev/null +++ b/components/password_manager/core/browser/password_manager_url_collection_experiment.cc
@@ -0,0 +1,18 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/prefs/pref_service.h" +#include "components/password_manager/core/browser/password_manager_url_collection_experiment.h" + +namespace password_manager { +namespace urls_collection_experiment { + +bool ShouldShowBubble(PrefService* prefs) { + // TODO(melandory) Make descision based on Finch experiment. + // "Do not show" is the default case. + return false; +} + +} // namespace urls_collection_experiment +} // namespace password_manager
diff --git a/components/password_manager/core/browser/password_manager_url_collection_experiment.h b/components/password_manager/core/browser/password_manager_url_collection_experiment.h new file mode 100644 index 0000000..96f7c28 --- /dev/null +++ b/components/password_manager/core/browser/password_manager_url_collection_experiment.h
@@ -0,0 +1,23 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_MANAGER_URL_COLLECTION_EXPERIMENT_H_ +#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_MANAGER_URL_COLLECTION_EXPERIMENT_H_ + +class PrefService; + +// These functions implement the algorithms according to which the "Allow to +// collect URL?" bubble is shown to user. +namespace password_manager { +namespace urls_collection_experiment { + +// Based on |prefs| and experiment settings, decides whether to show the +// "Allow to collect URL?" bubble and should be called before showing it. +// The default value is false. +bool ShouldShowBubble(PrefService* prefs); + +} // namespace urls_collection_experiment +} // namespace password_manager + +#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_MANAGER_URL_COLLECTION_EXPERIMENT_H_
diff --git a/components/password_manager/core/browser/password_manager_url_collection_experiment_unittest.cc b/components/password_manager/core/browser/password_manager_url_collection_experiment_unittest.cc new file mode 100644 index 0000000..12a4c04f --- /dev/null +++ b/components/password_manager/core/browser/password_manager_url_collection_experiment_unittest.cc
@@ -0,0 +1,27 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/password_manager/core/browser/password_manager_url_collection_experiment.h" + +#include "base/files/scoped_temp_dir.h" +#include "base/prefs/pref_service.h" +#include "base/prefs/testing_pref_service.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +class PasswordManagerUrlsCollectionExperimentTest : public testing::Test { + public: + PrefService* prefs() { return &pref_service_; } + + private: + TestingPrefServiceSimple pref_service_; +}; + +TEST_F(PasswordManagerUrlsCollectionExperimentTest, TestDefault) { + EXPECT_FALSE( + password_manager::urls_collection_experiment::ShouldShowBubble(prefs())); +} + +} // namespace
diff --git a/components/password_manager/core/browser/stub_password_manager_client.cc b/components/password_manager/core/browser/stub_password_manager_client.cc index 3145bc2..e64c8a8 100644 --- a/components/password_manager/core/browser/stub_password_manager_client.cc +++ b/components/password_manager/core/browser/stub_password_manager_client.cc
@@ -47,6 +47,4 @@ PasswordStore* StubPasswordManagerClient::GetPasswordStore() { return NULL; } -PasswordManagerDriver* StubPasswordManagerClient::GetDriver() { return NULL; } - } // namespace password_manager
diff --git a/components/password_manager/core/browser/stub_password_manager_client.h b/components/password_manager/core/browser/stub_password_manager_client.h index 38666c5..b32ff87 100644 --- a/components/password_manager/core/browser/stub_password_manager_client.h +++ b/components/password_manager/core/browser/stub_password_manager_client.h
@@ -32,7 +32,6 @@ scoped_ptr<PasswordFormManager> saved_manager) override; PrefService* GetPrefs() override; PasswordStore* GetPasswordStore() override; - PasswordManagerDriver* GetDriver() override; private: DISALLOW_COPY_AND_ASSIGN(StubPasswordManagerClient);
diff --git a/components/password_manager/core/browser/stub_password_manager_driver.cc b/components/password_manager/core/browser/stub_password_manager_driver.cc index a883a84a..9565582 100644 --- a/components/password_manager/core/browser/stub_password_manager_driver.cc +++ b/components/password_manager/core/browser/stub_password_manager_driver.cc
@@ -16,14 +16,6 @@ const autofill::PasswordFormFillData& form_data) { } -bool StubPasswordManagerDriver::DidLastPageLoadEncounterSSLErrors() { - return false; -} - -bool StubPasswordManagerDriver::IsOffTheRecord() { - return false; -} - void StubPasswordManagerDriver::AllowPasswordGenerationForForm( const autofill::PasswordForm& form) { }
diff --git a/components/password_manager/core/browser/stub_password_manager_driver.h b/components/password_manager/core/browser/stub_password_manager_driver.h index 09ae441..91797727 100644 --- a/components/password_manager/core/browser/stub_password_manager_driver.h +++ b/components/password_manager/core/browser/stub_password_manager_driver.h
@@ -20,8 +20,6 @@ // PasswordManagerDriver: void FillPasswordForm( const autofill::PasswordFormFillData& form_data) override; - bool DidLastPageLoadEncounterSSLErrors() override; - bool IsOffTheRecord() override; void AllowPasswordGenerationForForm( const autofill::PasswordForm& form) override; void AccountCreationFormsFound(
diff --git a/components/plugins/renderer/plugin_placeholder.cc b/components/plugins/renderer/plugin_placeholder.cc index 1dcdf2a..9570b501 100644 --- a/components/plugins/renderer/plugin_placeholder.cc +++ b/components/plugins/renderer/plugin_placeholder.cc
@@ -13,6 +13,7 @@ #include "base/values.h" #include "content/public/common/content_constants.h" #include "content/public/common/context_menu_params.h" +#include "content/public/renderer/plugin_power_saver_helper.h" #include "content/public/renderer/render_frame.h" #include "content/public/renderer/render_thread.h" #include "gin/object_template_builder.h" @@ -41,6 +42,18 @@ gin::WrapperInfo PluginPlaceholder::kWrapperInfo = {gin::kEmbedderNativeGin}; +#if defined(ENABLE_PLUGINS) +void PluginPlaceholder::BlockForPowerSaver() { + DCHECK(!is_blocked_for_power_saver_); + is_blocked_for_power_saver_ = true; + + render_frame()->GetPluginPowerSaverHelper()->RegisterPeripheralPlugin( + GURL(plugin_params_.url).GetOrigin(), + base::Bind(&PluginPlaceholder::UnblockForPowerSaver, + weak_factory_.GetWeakPtr())); +} +#endif + PluginPlaceholder::PluginPlaceholder(content::RenderFrame* render_frame, WebLocalFrame* frame, const WebPluginParams& params, @@ -54,12 +67,23 @@ html_data, placeholderDataUrl)), is_blocked_for_prerendering_(false), + is_blocked_for_power_saver_(false), allow_loading_(false), hidden_(false), - finished_loading_(false) {} + finished_loading_(false), + weak_factory_(this) { +} PluginPlaceholder::~PluginPlaceholder() {} +#if defined(ENABLE_PLUGINS) +void PluginPlaceholder::UnblockForPowerSaver() { + is_blocked_for_power_saver_ = false; + if (!is_blocked_for_prerendering_) + LoadPlugin(content::RenderFrame::CREATE_PLUGIN_GESTURE_NO_USER_GESTURE); +} +#endif + gin::ObjectTemplateBuilder PluginPlaceholder::GetObjectTemplateBuilder( v8::Isolate* isolate) { return gin::Wrappable<PluginPlaceholder>::GetObjectTemplateBuilder(isolate) @@ -185,18 +209,21 @@ return; RenderThread::Get()->RecordAction(UserMetricsAction("Plugin_Load_UI")); - LoadPlugin(); + LoadPlugin(content::RenderFrame::CREATE_PLUGIN_GESTURE_NO_USER_GESTURE); } void PluginPlaceholder::OnSetIsPrerendering(bool is_prerendering) { // Prerendering can only be enabled prior to a RenderView's first navigation, // so no BlockedPlugin should see the notification that enables prerendering. DCHECK(!is_prerendering); - if (is_blocked_for_prerendering_ && !is_prerendering) - LoadPlugin(); + if (is_blocked_for_prerendering_ && !is_prerendering && + !is_blocked_for_power_saver_) { + LoadPlugin(content::RenderFrame::CREATE_PLUGIN_GESTURE_NO_USER_GESTURE); + } } -void PluginPlaceholder::LoadPlugin() { +void PluginPlaceholder::LoadPlugin( + content::RenderFrame::CreatePluginGesture gesture) { // This is not strictly necessary but is an important defense in case the // event propagation changes between "close" vs. "click-to-play". if (hidden_) @@ -211,15 +238,14 @@ // TODO(mmenke): In the case of prerendering, feed into // ChromeContentRendererClient::CreatePlugin instead, to // reduce the chance of future regressions. - WebPlugin* plugin = render_frame()->CreatePlugin( - frame_, plugin_info_, plugin_params_, - content::RenderFrame::CREATE_PLUGIN_GESTURE_HAS_USER_GESTURE); + WebPlugin* plugin = render_frame()->CreatePlugin(frame_, plugin_info_, + plugin_params_, gesture); ReplacePlugin(plugin); } void PluginPlaceholder::LoadCallback() { RenderThread::Get()->RecordAction(UserMetricsAction("Plugin_Load_Click")); - LoadPlugin(); + LoadPlugin(content::RenderFrame::CREATE_PLUGIN_GESTURE_HAS_USER_GESTURE); } void PluginPlaceholder::HideCallback() {
diff --git a/components/plugins/renderer/plugin_placeholder.h b/components/plugins/renderer/plugin_placeholder.h index a5f2564..b21f007 100644 --- a/components/plugins/renderer/plugin_placeholder.h +++ b/components/plugins/renderer/plugin_placeholder.h
@@ -5,9 +5,11 @@ #ifndef COMPONENTS_PLUGINS_RENDERER_PLUGIN_PLACEHOLDER_H_ #define COMPONENTS_PLUGINS_RENDERER_PLUGIN_PLACEHOLDER_H_ +#include "base/memory/weak_ptr.h" #include "components/plugins/renderer/webview_plugin.h" #include "content/public/common/webplugininfo.h" #include "content/public/renderer/context_menu_client.h" +#include "content/public/renderer/render_frame.h" #include "content/public/renderer/render_frame_observer.h" #include "content/public/renderer/render_process_observer.h" #include "gin/wrappable.h" @@ -32,6 +34,10 @@ is_blocked_for_prerendering_ = blocked_for_prerendering; } +#if defined(ENABLE_PLUGINS) + void BlockForPowerSaver(); +#endif + void set_allow_loading(bool allow_loading) { allow_loading_ = allow_loading; } protected: @@ -45,6 +51,10 @@ ~PluginPlaceholder() override; +#if defined(ENABLE_PLUGINS) + void UnblockForPowerSaver(); +#endif + void OnLoadBlockedPlugins(const std::string& identifier); void OnSetIsPrerendering(bool is_prerendering); @@ -64,7 +74,7 @@ void HidePlugin(); // Load the blocked plugin. - void LoadPlugin(); + void LoadPlugin(content::RenderFrame::CreatePluginGesture gesture); // gin::Wrappable method: gin::ObjectTemplateBuilder GetObjectTemplateBuilder( @@ -98,15 +108,21 @@ base::string16 message_; - // True iff the plugin was blocked because the page was being prerendered. - // Plugin will automatically be loaded when the page is displayed. + // True if the plugin was blocked because the page was being prerendered. + // Plugin may be automatically be loaded when the page is displayed. bool is_blocked_for_prerendering_; + + // True if the plugin load is deferred due to a Power Saver poster. + bool is_blocked_for_power_saver_; + bool allow_loading_; bool hidden_; bool finished_loading_; std::string identifier_; + base::WeakPtrFactory<PluginPlaceholder> weak_factory_; + DISALLOW_COPY_AND_ASSIGN(PluginPlaceholder); };
diff --git a/components/policy/OWNERS b/components/policy/OWNERS index 32e8aae..78c3a59 100644 --- a/components/policy/OWNERS +++ b/components/policy/OWNERS
@@ -1,6 +1,4 @@ mnissler@chromium.org -pastarmovj@chromium.org -joaodasilva@chromium.org bartfab@chromium.org atwilson@chromium.org pneubeck@chromium.org
diff --git a/components/policy/core/browser/browser_policy_connector.cc b/components/policy/core/browser/browser_policy_connector.cc index 6ac544c6..c057a8f 100644 --- a/components/policy/core/browser/browser_policy_connector.cc +++ b/components/policy/core/browser/browser_policy_connector.cc
@@ -53,12 +53,12 @@ L"aol\\.com", L"googlemail\\.com", L"gmail\\.com", - L"hotmail(\\.co|\\.com|)\\.[^.]+", // hotmail.com, hotmail.it, hotmail.co.uk + L"hotmail(\\.co|\\.com|)\\.[^.]+", // hotmail.com, hotmail.it, hotmail.co.uk L"live\\.com", L"mail\\.ru", L"msn\\.com", L"qq\\.com", - L"yahoo(\\.co|\\.com|)\\.[^.]+", // yahoo.com, yahoo.co.uk, yahoo.com.tw + L"yahoo(\\.co|\\.com|)\\.[^.]+", // yahoo.com, yahoo.co.uk, yahoo.com.tw L"yandex\\.ru", };
diff --git a/components/policy/core/browser/policy_error_map.cc b/components/policy/core/browser/policy_error_map.cc index 60ec8751..04411b6d 100644 --- a/components/policy/core/browser/policy_error_map.cc +++ b/components/policy/core/browser/policy_error_map.cc
@@ -110,7 +110,7 @@ const std::string& error_path, const std::string& replacement) : SimplePendingError(policy_name, -1, replacement), - error_path_(error_path) {}; + error_path_(error_path) {} ~SchemaValidatingPendingError() override {} base::string16 GetMessage() const override {
diff --git a/components/policy/core/common/cloud/cloud_external_data_manager.h b/components/policy/core/common/cloud/cloud_external_data_manager.h index a5b8eca..9a7e368 100644 --- a/components/policy/core/common/cloud/cloud_external_data_manager.h +++ b/components/policy/core/common/cloud/cloud_external_data_manager.h
@@ -67,6 +67,7 @@ base::WeakPtrFactory<CloudExternalDataManager> weak_factory_; + private: DISALLOW_COPY_AND_ASSIGN(CloudExternalDataManager); };
diff --git a/components/policy/core/common/cloud/cloud_policy_client_unittest.cc b/components/policy/core/common/cloud/cloud_policy_client_unittest.cc index 905b0e1..767f1b8 100644 --- a/components/policy/core/common/cloud/cloud_policy_client_unittest.cc +++ b/components/policy/core/common/cloud/cloud_policy_client_unittest.cc
@@ -504,6 +504,7 @@ policy_response_.policy_response().response(0)); expected_namespaces.insert(key); key.first = dm_protocol::kChromeExtensionPolicyType; + expected_namespaces.insert(key); for (size_t i = 0; i < arraysize(kExtensions); ++i) { key.second = kExtensions[i]; em::PolicyData policy_data; @@ -512,7 +513,6 @@ expected_responses[key].set_policy_data(policy_data.SerializeAsString()); policy_response_.mutable_policy_response()->add_response()->CopyFrom( expected_responses[key]); - expected_namespaces.insert(key); } // Make a policy fetch. @@ -527,26 +527,21 @@ .WillOnce(SaveArg<6>(&policy_request_)); EXPECT_CALL(observer_, OnPolicyFetched(_)); EXPECT_CALL(*status_provider_, OnSubmittedSuccessfully()); - for (size_t i = 0; i < arraysize(kExtensions); ++i) { - client_->AddPolicyTypeToFetch(dm_protocol::kChromeExtensionPolicyType, - kExtensions[i]); - } + client_->AddPolicyTypeToFetch(dm_protocol::kChromeExtensionPolicyType, + std::string()); client_->FetchPolicy(); // Verify that the request includes the expected namespaces. ASSERT_TRUE(policy_request_.has_policy_request()); const em::DevicePolicyRequest& policy_request = policy_request_.policy_request(); - ASSERT_EQ(static_cast<int>(1 + arraysize(kExtensions)), - policy_request.request_size()); + ASSERT_EQ(2, policy_request.request_size()); for (int i = 0; i < policy_request.request_size(); ++i) { const em::PolicyFetchRequest& fetch_request = policy_request.request(i); ASSERT_TRUE(fetch_request.has_policy_type()); - std::string entity_id; - if (fetch_request.has_settings_entity_id()) - entity_id = fetch_request.settings_entity_id(); + EXPECT_FALSE(fetch_request.has_settings_entity_id()); std::pair<std::string, std::string> key(fetch_request.policy_type(), - entity_id); + std::string()); EXPECT_EQ(1u, expected_namespaces.erase(key)); } EXPECT_TRUE(expected_namespaces.empty());
diff --git a/components/policy/core/common/cloud/cloud_policy_manager.cc b/components/policy/core/common/cloud/cloud_policy_manager.cc index 2e039dc..32ffbae7 100644 --- a/components/policy/core/common/cloud/cloud_policy_manager.cc +++ b/components/policy/core/common/cloud/cloud_policy_manager.cc
@@ -108,12 +108,16 @@ void CloudPolicyManager::CreateComponentCloudPolicyService( const base::FilePath& policy_cache_path, - const scoped_refptr<net::URLRequestContextGetter>& request_context) { + const scoped_refptr<net::URLRequestContextGetter>& request_context, + CloudPolicyClient* client) { #if !defined(OS_ANDROID) && !defined(OS_IOS) // Init() must have been called. - DCHECK(schema_registry()); + CHECK(schema_registry()); // Called at most once. - DCHECK(!component_policy_service_); + CHECK(!component_policy_service_); + // The core can't be connected yet. + // See the comments on ComponentCloudPolicyService for the details. + CHECK(!core()->client()); if (CommandLine::ForCurrentProcess()->HasSwitch( switches::kDisableComponentCloudPolicy) || @@ -130,6 +134,7 @@ this, schema_registry(), core(), + client, resource_cache.Pass(), request_context, file_task_runner_,
diff --git a/components/policy/core/common/cloud/cloud_policy_manager.h b/components/policy/core/common/cloud/cloud_policy_manager.h index f8baebd..256ec80 100644 --- a/components/policy/core/common/cloud/cloud_policy_manager.h +++ b/components/policy/core/common/cloud/cloud_policy_manager.h
@@ -84,7 +84,8 @@ void CreateComponentCloudPolicyService( const base::FilePath& policy_cache_path, - const scoped_refptr<net::URLRequestContextGetter>& request_context); + const scoped_refptr<net::URLRequestContextGetter>& request_context, + CloudPolicyClient* client); void ClearAndDestroyComponentCloudPolicyService();
diff --git a/components/policy/core/common/cloud/component_cloud_policy_service.cc b/components/policy/core/common/cloud/component_cloud_policy_service.cc index ab2c6be1..56558f3 100644 --- a/components/policy/core/common/cloud/component_cloud_policy_service.cc +++ b/components/policy/core/common/cloud/component_cloud_policy_service.cc
@@ -8,6 +8,7 @@ #include "base/bind.h" #include "base/bind_helpers.h" +#include "base/containers/scoped_ptr_hash_map.h" #include "base/location.h" #include "base/logging.h" #include "base/message_loop/message_loop_proxy.h" @@ -25,10 +26,20 @@ namespace em = enterprise_management; +typedef base::ScopedPtrHashMap<policy::PolicyNamespace, em::PolicyFetchResponse> + ScopedResponseMap; + namespace policy { namespace { +bool NotInResponseMap(const ScopedResponseMap& map, + const std::string& component_id) { + // This helper only works for POLICY_DOMAIN_EXTENSIONS for now. Parameterize + // this and update SetCurrentPolicies() below later if appropriate. + return !map.contains(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, component_id)); +} + bool NotInSchemaMap(const scoped_refptr<SchemaMap> schema_map, PolicyDomain domain, const std::string& component_id) { @@ -72,9 +83,12 @@ // Loads the |store_| and starts downloading updates. void Init(scoped_refptr<SchemaMap> schema_map); - // Passes a policy protobuf to the backend, to start its validation and - // eventual download of the policy data on the background thread. - void UpdateExternalPolicy(scoped_ptr<em::PolicyFetchResponse> response); + // Passes a map with all the PolicyFetchResponses for components currently + // set at the server. Any components without an entry in |responses| + // will have their cache purged after this call. + // Otherwise the backend will start the validation and eventual download of + // the policy data for each PolicyFetchResponse in |responses|. + void SetCurrentPolicies(scoped_ptr<ScopedResponseMap> responses); // ComponentCloudPolicyStore::Delegate implementation: void OnComponentCloudPolicyStoreUpdated() override; @@ -163,9 +177,16 @@ initialized_ = true; } -void ComponentCloudPolicyService::Backend::UpdateExternalPolicy( - scoped_ptr<em::PolicyFetchResponse> response) { - updater_->UpdateExternalPolicy(response.Pass()); +void ComponentCloudPolicyService::Backend::SetCurrentPolicies( + scoped_ptr<ScopedResponseMap> responses) { + // Purge any components that don't have a policy configured at the server. + store_.Purge(POLICY_DOMAIN_EXTENSIONS, + base::Bind(&NotInResponseMap, base::ConstRef(*responses))); + + for (ScopedResponseMap::iterator it = responses->begin(); + it != responses->end(); ++it) { + updater_->UpdateExternalPolicy(responses->take(it)); + } } void ComponentCloudPolicyService::Backend:: @@ -205,6 +226,7 @@ Delegate* delegate, SchemaRegistry* schema_registry, CloudPolicyCore* core, + CloudPolicyClient* client, scoped_ptr<ResourceCache> cache, scoped_refptr<net::URLRequestContextGetter> request_context, scoped_refptr<base::SequencedTaskRunner> backend_task_runner, @@ -221,6 +243,8 @@ loaded_initial_policy_(false), is_registered_for_cloud_policy_(false), weak_ptr_factory_(this) { + CHECK(!core_->client()); + external_policy_data_fetcher_backend_.reset( new ExternalPolicyDataFetcherBackend(io_task_runner_, request_context)); @@ -244,8 +268,11 @@ // Start observing the core and tracking the state of the client. core_->AddObserver(this); - if (core_->client()) - OnCoreConnected(core_); + client->AddObserver(this); + + // Register the supported policy domains at the client. + client->AddPolicyTypeToFetch(dm_protocol::kChromeExtensionPolicyType, + std::string()); } ComponentCloudPolicyService::~ComponentCloudPolicyService() { @@ -302,13 +329,6 @@ void ComponentCloudPolicyService::OnCoreConnected(CloudPolicyCore* core) { DCHECK(CalledOnValidThread()); DCHECK_EQ(core_, core); - - core_->client()->AddObserver(this); - - // Register the supported policy domains at the client. - core_->client()->AddPolicyTypeToFetch( - dm_protocol::kChromeExtensionPolicyType, std::string()); - // Immediately load any PolicyFetchResponses that the client may already // have if the backend is ready. if (loaded_initial_policy_) @@ -394,23 +414,34 @@ return; } - // Pass each PolicyFetchResponse whose policy type is registered to the - // Backend. + if (core_->client()->responses().empty()) { + // The client's responses will be empty if it hasn't fetched policy from the + // DMServer yet. Make sure we don't purge the caches in this case. + return; + } + + // Pass a complete list of all the currently managed extensions to the + // backend. The cache will purge the storage for any extensions that are not + // in this list. + scoped_ptr<ScopedResponseMap> valid_responses(new ScopedResponseMap()); + const CloudPolicyClient::ResponseMap& responses = core_->client()->responses(); for (auto it = responses.begin(); it != responses.end(); ++it) { PolicyNamespace ns; - if (ToPolicyNamespace(it->first, &ns) && - current_schema_map_->GetSchema(ns)) { - scoped_ptr<em::PolicyFetchResponse> response( - new em::PolicyFetchResponse(*it->second)); - backend_task_runner_->PostTask( - FROM_HERE, - base::Bind(&Backend::UpdateExternalPolicy, - base::Unretained(backend_.get()), - base::Passed(&response))); + if (!ToPolicyNamespace(it->first, &ns) || + !current_schema_map_->GetSchema(ns)) { + continue; } + valid_responses->set( + ns, make_scoped_ptr(new em::PolicyFetchResponse(*it->second))); } + + backend_task_runner_->PostTask( + FROM_HERE, + base::Bind(&Backend::SetCurrentPolicies, + base::Unretained(backend_.get()), + base::Passed(&valid_responses))); } void ComponentCloudPolicyService::OnRegistrationStateChanged(
diff --git a/components/policy/core/common/cloud/component_cloud_policy_service.h b/components/policy/core/common/cloud/component_cloud_policy_service.h index 6112cbee..aa9f11f5 100644 --- a/components/policy/core/common/cloud/component_cloud_policy_service.h +++ b/components/policy/core/common/cloud/component_cloud_policy_service.h
@@ -65,6 +65,12 @@ // and registration credentials; the client will be used to fetch cloud // policy. It must outlive this object. // + // The |core| MUST not be connected yet when this service is created; + // |client| must be the client that will be connected to the |core|. This + // is important to make sure that this service appends any necessary policy + // fetch types to the |client| before the |core| gets connected and before + // the initial policy fetch request is sent out. + // // |cache| is used to load and store local copies of the downloaded policies. // // Download scheduling, validation and caching of policies are done via the @@ -76,6 +82,7 @@ Delegate* delegate, SchemaRegistry* schema_registry, CloudPolicyCore* core, + CloudPolicyClient* client, #if !defined(OS_ANDROID) && !defined(OS_IOS) scoped_ptr<ResourceCache> cache, #endif
diff --git a/components/policy/core/common/cloud/component_cloud_policy_service_stub.cc b/components/policy/core/common/cloud/component_cloud_policy_service_stub.cc index 1926eac..2ab8239 100644 --- a/components/policy/core/common/cloud/component_cloud_policy_service_stub.cc +++ b/components/policy/core/common/cloud/component_cloud_policy_service_stub.cc
@@ -15,6 +15,7 @@ Delegate* delegate, SchemaRegistry* schema_registry, CloudPolicyCore* core, + CloudPolicyClient* client, scoped_refptr<net::URLRequestContextGetter> request_context, scoped_refptr<base::SequencedTaskRunner> backend_task_runner, scoped_refptr<base::SequencedTaskRunner> io_task_runner)
diff --git a/components/policy/core/common/cloud/component_cloud_policy_service_unittest.cc b/components/policy/core/common/cloud/component_cloud_policy_service_unittest.cc index 8224c7b..6ffdd13 100644 --- a/components/policy/core/common/cloud/component_cloud_policy_service_unittest.cc +++ b/components/policy/core/common/cloud/component_cloud_policy_service_unittest.cc
@@ -106,7 +106,10 @@ class ComponentCloudPolicyServiceTest : public testing::Test { protected: ComponentCloudPolicyServiceTest() - : client_(nullptr), + : request_context_( + new TestURLRequestContextGetter(loop_.message_loop_proxy())), + cache_(nullptr), + client_(nullptr), core_(GetChromeUserPolicyType(), std::string(), &store_, @@ -115,17 +118,9 @@ void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - cache_ = new ResourceCache(temp_dir_.path(), loop_.message_loop_proxy()); - request_context_ = - new TestURLRequestContextGetter(loop_.message_loop_proxy()); - service_.reset(new ComponentCloudPolicyService( - &delegate_, - ®istry_, - &core_, - make_scoped_ptr(cache_), - request_context_, - loop_.message_loop_proxy(), - loop_.message_loop_proxy())); + owned_cache_.reset( + new ResourceCache(temp_dir_.path(), loop_.message_loop_proxy())); + cache_ = owned_cache_.get(); builder_.policy_data().set_policy_type( dm_protocol::kChromeExtensionPolicyType); @@ -155,17 +150,22 @@ base::RunLoop().RunUntilIdle(); } - void Connect(size_t expected_namespaces_in_client) { + void Connect() { client_ = new MockCloudPolicyClient(); + service_.reset(new ComponentCloudPolicyService( + &delegate_, + ®istry_, + &core_, + client_, + owned_cache_.Pass(), + request_context_, + loop_.message_loop_proxy(), + loop_.message_loop_proxy())); + client_->SetDMToken(ComponentPolicyBuilder::kFakeToken); - EXPECT_EQ(0u, client_->types_to_fetch_.size()); - + EXPECT_EQ(1u, client_->types_to_fetch_.size()); core_.Connect(scoped_ptr<CloudPolicyClient>(client_)); - - // |expected_namespaces_in_client| is the expected number of components - // that the ComponentCloudPolicyService will set at the |client_| at - // OnCoreConnected. - EXPECT_EQ(expected_namespaces_in_client, client_->types_to_fetch_.size()); + EXPECT_EQ(2u, client_->types_to_fetch_.size()); // Also initialize the refresh scheduler, so that calls to // core()->RefreshSoon() trigger a FetchPolicy() call on the mock |client_|. @@ -234,6 +234,7 @@ MockComponentCloudPolicyDelegate delegate_; // |cache_| is owned by the |service_| and is invalid once the |service_| // is destroyed. + scoped_ptr<ResourceCache> owned_cache_; ResourceCache* cache_; MockCloudPolicyClient* client_; MockCloudPolicyStore store_; @@ -244,36 +245,8 @@ PolicyMap expected_policy_; }; -TEST_F(ComponentCloudPolicyServiceTest, InitializedAtConstructionTime) { - service_.reset(); - Connect(1u); - LoadStore(); - InitializeRegistry(); - - cache_ = new ResourceCache(temp_dir_.path(), loop_.message_loop_proxy()); - service_.reset(new ComponentCloudPolicyService(&delegate_, - ®istry_, - &core_, - make_scoped_ptr(cache_), - request_context_, - loop_.message_loop_proxy(), - loop_.message_loop_proxy())); - EXPECT_FALSE(service_->is_initialized()); - - EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()); - EXPECT_CALL(*client_, FetchPolicy()).Times(0); - RunUntilIdle(); - Mock::VerifyAndClearExpectations(&client_); - Mock::VerifyAndClearExpectations(&delegate_); - - EXPECT_TRUE(service_->is_initialized()); - EXPECT_EQ(2u, client_->types_to_fetch_.size()); - const PolicyBundle empty_bundle; - EXPECT_TRUE(service_->policy().Equals(empty_bundle)); -} - TEST_F(ComponentCloudPolicyServiceTest, InitializeStoreThenRegistry) { - Connect(2u); + Connect(); EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()).Times(0); EXPECT_CALL(*client_, FetchPolicy()).Times(0); @@ -295,7 +268,7 @@ } TEST_F(ComponentCloudPolicyServiceTest, InitializeRegistryThenStore) { - Connect(2u); + Connect(); EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()).Times(0); EXPECT_CALL(*client_, FetchPolicy()).Times(0); @@ -318,7 +291,7 @@ TEST_F(ComponentCloudPolicyServiceTest, InitializeWithCachedPolicy) { PopulateCache(); - Connect(2u); + Connect(); EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()); EXPECT_CALL(*client_, FetchPolicy()).Times(0); @@ -343,7 +316,7 @@ } TEST_F(ComponentCloudPolicyServiceTest, FetchPolicy) { - Connect(2u); + Connect(); // Initialize the store and create the backend. // A refresh is not needed, because no components are registered yet. EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()); @@ -392,7 +365,7 @@ } TEST_F(ComponentCloudPolicyServiceTest, LoadAndPurgeCache) { - Connect(2u); + Connect(); // Insert data in the cache. PopulateCache(); registry_.RegisterComponent( @@ -439,23 +412,20 @@ // Initialize the store without credentials. EXPECT_FALSE(store_.is_initialized()); - EXPECT_FALSE(service_->is_initialized()); - EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()); store_.NotifyStoreLoaded(); RunUntilIdle(); - Mock::VerifyAndClearExpectations(&delegate_); - EXPECT_TRUE(service_->is_initialized()); // Register an extension. - EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()); registry_.RegisterComponent( PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kTestExtension), CreateTestSchema()); RunUntilIdle(); - Mock::VerifyAndClearExpectations(&delegate_); - // Now signin. A fetch will be requested for the new extension. - Connect(2u); + // Now signin. The service will finish loading its backend (which is empty + // for now, because there are no credentials) and issue a notification. + EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()); + Connect(); + Mock::VerifyAndClearExpectations(&delegate_); // Send the response to the service. The response data will be ignored, // because the store doesn't have the updated credentials yet. @@ -505,7 +475,7 @@ // The initial, cached policy will be served once the backend is initialized. EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()); - RunUntilIdle(); + Connect(); Mock::VerifyAndClearExpectations(&delegate_); PolicyBundle expected_bundle; const PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, kTestExtension); @@ -515,9 +485,6 @@ cache_->LoadAllSubkeys("extension-policy", &contents); ASSERT_EQ(1u, contents.size()); - // Now sign in. - Connect(2u); - // Signing out removes all of the component policies from the service and // from the cache. It does not trigger a refresh. EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()); @@ -547,7 +514,7 @@ // The initial, cached policy will be served once the backend is initialized. EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()); - RunUntilIdle(); + Connect(); Mock::VerifyAndClearExpectations(&delegate_); PolicyBundle expected_bundle; @@ -560,4 +527,63 @@ EXPECT_TRUE(service_->policy().Equals(expected_bundle)); } +TEST_F(ComponentCloudPolicyServiceTest, PurgeWhenServerRemovesPolicy) { + // Initialize with cached policy. + PopulateCache(); + Connect(); + + EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()); + EXPECT_CALL(*client_, FetchPolicy()).Times(0); + registry_.RegisterComponent( + PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kTestExtension2), + CreateTestSchema()); + InitializeRegistry(); + LoadStore(); + Mock::VerifyAndClearExpectations(client_); + Mock::VerifyAndClearExpectations(&delegate_); + + EXPECT_TRUE(service_->is_initialized()); + EXPECT_EQ(2u, client_->types_to_fetch_.size()); + + // Verify that policy for 2 extensions has been loaded from the cache. + std::map<std::string, std::string> contents; + cache_->LoadAllSubkeys("extension-policy", &contents); + ASSERT_EQ(2u, contents.size()); + EXPECT_TRUE(ContainsKey(contents, kTestExtension)); + EXPECT_TRUE(ContainsKey(contents, kTestExtension2)); + + PolicyBundle expected_bundle; + const PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, kTestExtension); + expected_bundle.Get(ns).CopyFrom(expected_policy_); + const PolicyNamespace ns2(POLICY_DOMAIN_EXTENSIONS, kTestExtension2); + expected_bundle.Get(ns2).CopyFrom(expected_policy_); + EXPECT_TRUE(service_->policy().Equals(expected_bundle)); + + // Receive an updated fetch response from the server. There is no response for + // extension 2, so it will be dropped from the cache. This triggers an + // immediate notification to the delegate. + EXPECT_CALL(delegate_, OnComponentCloudPolicyUpdated()); + client_->SetPolicy(dm_protocol::kChromeExtensionPolicyType, kTestExtension, + *CreateResponse()); + service_->OnPolicyFetched(client_); + RunUntilIdle(); + Mock::VerifyAndClearExpectations(&delegate_); + + // That should have triggered the download fetch for the first extension. + net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0); + ASSERT_TRUE(fetcher); + + // The cache should have dropped the entries for the second extension. + contents.clear(); + cache_->LoadAllSubkeys("extension-policy", &contents); + ASSERT_EQ(1u, contents.size()); + EXPECT_TRUE(ContainsKey(contents, kTestExtension)); + EXPECT_FALSE(ContainsKey(contents, kTestExtension2)); + + // And the service isn't publishing policy for the second extension anymore. + expected_bundle.Clear(); + expected_bundle.Get(ns).CopyFrom(expected_policy_); + EXPECT_TRUE(service_->policy().Equals(expected_bundle)); +} + } // namespace policy
diff --git a/components/policy/core/common/cloud/device_management_service_unittest.cc b/components/policy/core/common/cloud/device_management_service_unittest.cc index 85a80d8..67df6ffb 100644 --- a/components/policy/core/common/cloud/device_management_service_unittest.cc +++ b/components/policy/core/common/cloud/device_management_service_unittest.cc
@@ -595,7 +595,7 @@ scoped_ptr<DeviceManagementRequestJob> request_job(StartRegistrationJob()); net::TestURLFetcher* fetcher = GetFetcher(); ASSERT_TRUE(fetcher); - EXPECT_TRUE((fetcher->GetLoadFlags() & net::LOAD_BYPASS_PROXY) == 0); + EXPECT_EQ(0, fetcher->GetLoadFlags() & net::LOAD_BYPASS_PROXY); const GURL original_url(fetcher->GetOriginalURL()); const std::string upload_data(fetcher->upload_data()); @@ -620,7 +620,7 @@ scoped_ptr<DeviceManagementRequestJob> request_job(StartRegistrationJob()); net::TestURLFetcher* fetcher = GetFetcher(); ASSERT_TRUE(fetcher); - EXPECT_TRUE((fetcher->GetLoadFlags() & net::LOAD_BYPASS_PROXY) == 0); + EXPECT_EQ(0, fetcher->GetLoadFlags() & net::LOAD_BYPASS_PROXY); const GURL original_url(fetcher->GetOriginalURL()); const std::string upload_data(fetcher->upload_data()); fetcher->set_was_fetched_via_proxy(true); @@ -637,7 +637,7 @@ // Verify that a new URLFetcher was started that bypasses the proxy. fetcher = GetFetcher(); ASSERT_TRUE(fetcher); - EXPECT_TRUE((fetcher->GetLoadFlags() & net::LOAD_BYPASS_PROXY) != 0); + EXPECT_NE(0, fetcher->GetLoadFlags() & net::LOAD_BYPASS_PROXY); EXPECT_EQ(original_url, fetcher->GetOriginalURL()); EXPECT_EQ(upload_data, fetcher->upload_data()); }
diff --git a/components/policy/core/common/cloud/external_policy_data_fetcher_unittest.cc b/components/policy/core/common/cloud/external_policy_data_fetcher_unittest.cc index a2b43b05..41eb63b 100644 --- a/components/policy/core/common/cloud/external_policy_data_fetcher_unittest.cc +++ b/components/policy/core/common/cloud/external_policy_data_fetcher_unittest.cc
@@ -61,6 +61,7 @@ ExternalPolicyDataFetcher::Result callback_result_; scoped_ptr<std::string> callback_data_; + private: DISALLOW_COPY_AND_ASSIGN(ExternalPolicyDataFetcherTest); };
diff --git a/components/policy/core/common/cloud/policy_header_io_helper.cc b/components/policy/core/common/cloud/policy_header_io_helper.cc index a5d15a2..268ca01 100644 --- a/components/policy/core/common/cloud/policy_header_io_helper.cc +++ b/components/policy/core/common/cloud/policy_header_io_helper.cc
@@ -55,7 +55,6 @@ FROM_HERE, base::Bind(&PolicyHeaderIOHelper::SetServerURLOnIOThread, base::Unretained(this), server_url)); - } void PolicyHeaderIOHelper::SetServerURLOnIOThread(
diff --git a/components/policy/core/common/cloud/user_cloud_policy_manager.cc b/components/policy/core/common/cloud/user_cloud_policy_manager.cc index 223644c7d..0ff9669 100644 --- a/components/policy/core/common/cloud/user_cloud_policy_manager.cc +++ b/components/policy/core/common/cloud/user_cloud_policy_manager.cc
@@ -53,15 +53,14 @@ PrefService* local_state, scoped_refptr<net::URLRequestContextGetter> request_context, scoped_ptr<CloudPolicyClient> client) { + CreateComponentCloudPolicyService(component_policy_cache_path_, + request_context, client.get()); core()->Connect(client.Pass()); core()->StartRefreshScheduler(); core()->TrackRefreshDelayPref(local_state, policy_prefs::kUserPolicyRefreshRate); if (external_data_manager_) external_data_manager_->Connect(request_context); - - CreateComponentCloudPolicyService(component_policy_cache_path_, - request_context); } // static
diff --git a/components/policy/core/common/cloud/user_cloud_policy_store.cc b/components/policy/core/common/cloud/user_cloud_policy_store.cc index 815d48f..db8302d9 100644 --- a/components/policy/core/common/cloud/user_cloud_policy_store.cc +++ b/components/policy/core/common/cloud/user_cloud_policy_store.cc
@@ -112,7 +112,7 @@ } bool WriteStringToFile(const base::FilePath path, const std::string& data) { - if (!base::CreateDirectory(path.DirName())) { + if (!base::CreateDirectory(path.DirName())) { DLOG(WARNING) << "Failed to create directory " << path.DirName().value(); return false; }
diff --git a/components/policy/core/common/cloud/user_cloud_policy_store_unittest.cc b/components/policy/core/common/cloud/user_cloud_policy_store_unittest.cc index 7576a8a1..f2eb553 100644 --- a/components/policy/core/common/cloud/user_cloud_policy_store_unittest.cc +++ b/components/policy/core/common/cloud/user_cloud_policy_store_unittest.cc
@@ -35,7 +35,7 @@ } bool WriteStringToFile(const base::FilePath path, const std::string& data) { - if (!base::CreateDirectory(path.DirName())) { + if (!base::CreateDirectory(path.DirName())) { DLOG(WARNING) << "Failed to create directory " << path.DirName().value(); return false; } @@ -140,6 +140,7 @@ base::ScopedTempDir tmp_dir_; + private: DISALLOW_COPY_AND_ASSIGN(UserCloudPolicyStoreTest); };
diff --git a/components/policy/core/common/policy_loader_win.cc b/components/policy/core/common/policy_loader_win.cc index 69320db..2989a36 100644 --- a/components/policy/core/common/policy_loader_win.cc +++ b/components/policy/core/common/policy_loader_win.cc
@@ -218,7 +218,7 @@ return is_wow_64_process_ && wow_64_disable_wow_64_fs_redirection_ && wow_64_revert_wow_64_fs_redirection_; - } + } bool IsWow64() { BOOL result = 0;
diff --git a/components/policy/core/common/policy_loader_win.h b/components/policy/core/common/policy_loader_win.h index 72ba64d..9d99c1bb 100644 --- a/components/policy/core/common/policy_loader_win.h +++ b/components/policy/core/common/policy_loader_win.h
@@ -70,7 +70,7 @@ // result in |policy|. bool ReadPRegFile(const base::FilePath& preg_file, RegistryDict* policy, - PolicyLoadStatusSample *status); + PolicyLoadStatusSample* status); // Loads and parses GPO policy in |policy_object_list| for scope |scope|. If // successful, stores the result in |policy| and returns true. Returns false @@ -79,14 +79,14 @@ bool LoadGPOPolicy(PolicyScope scope, PGROUP_POLICY_OBJECT policy_object_list, RegistryDict* policy, - PolicyLoadStatusSample *status); + PolicyLoadStatusSample* status); // Queries Windows for applied group policy and writes the result to |policy|. // This is the preferred way to obtain GPO data, there are reports of abuse // of the registry GPO keys by 3rd-party software. bool ReadPolicyFromGPO(PolicyScope scope, RegistryDict* policy, - PolicyLoadStatusSample *status); + PolicyLoadStatusSample* status); // Parses Chrome policy from |gpo_dict| for the given |scope| and |level| and // merges it into |chrome_policy_map|.
diff --git a/components/policy/core/common/policy_namespace.h b/components/policy/core/common/policy_namespace.h index 86dc5866..e07ec0f1 100644 --- a/components/policy/core/common/policy_namespace.h +++ b/components/policy/core/common/policy_namespace.h
@@ -5,9 +5,12 @@ #ifndef COMPONENTS_POLICY_CORE_COMMON_POLICY_NAMESPACE_H_ #define COMPONENTS_POLICY_CORE_COMMON_POLICY_NAMESPACE_H_ +#include <stdint.h> + #include <string> #include <vector> +#include "base/containers/hash_tables.h" #include "components/policy/policy_export.h" namespace policy { @@ -49,4 +52,18 @@ } // namespace policy +// Define a custom std::hash for PolicyNamespace so that it can be used as +// a key in hash_maps, and in particular in ScopedPtrHashMaps (which uses the +// default std::hash). +namespace BASE_HASH_NAMESPACE { + +template <> +struct hash<policy::PolicyNamespace> { + std::size_t operator()(const policy::PolicyNamespace& ns) const { + return hash<std::string>()(ns.component_id) ^ (UINT64_C(1) << ns.domain); + } +}; + +} // namespace BASE_HASH_NAMESPACE + #endif // COMPONENTS_POLICY_CORE_COMMON_POLICY_NAMESPACE_H_
diff --git a/components/policy/core/common/policy_service_stub.cc b/components/policy/core/common/policy_service_stub.cc index 1f9682b..0459f8d 100644 --- a/components/policy/core/common/policy_service_stub.cc +++ b/components/policy/core/common/policy_service_stub.cc
@@ -21,7 +21,7 @@ const PolicyMap& PolicyServiceStub::GetPolicies( const PolicyNamespace& ns) const { return kEmpty_; -}; +} bool PolicyServiceStub::IsInitializationComplete(PolicyDomain domain) const { return true;
diff --git a/components/policy/core/common/proxy_policy_provider_unittest.cc b/components/policy/core/common/proxy_policy_provider_unittest.cc index 49d65db7..e84a819 100644 --- a/components/policy/core/common/proxy_policy_provider_unittest.cc +++ b/components/policy/core/common/proxy_policy_provider_unittest.cc
@@ -40,6 +40,7 @@ return copy.Pass(); } + private: DISALLOW_COPY_AND_ASSIGN(ProxyPolicyProviderTest); };
diff --git a/components/policy/core/common/registry_dict_win_unittest.cc b/components/policy/core/common/registry_dict_win_unittest.cc index 2458435f..4db7ead 100644 --- a/components/policy/core/common/registry_dict_win_unittest.cc +++ b/components/policy/core/common/registry_dict_win_unittest.cc
@@ -244,7 +244,8 @@ expected.Set("int-to-double", new base::FundamentalValue(42.0)); expected.Set("string-to-bool", new base::FundamentalValue(false)); expected.Set("string-to-double", new base::FundamentalValue(0.0)); - expected.Set("string-to-int", new base::FundamentalValue((int) 0)); + expected.Set("string-to-int", + new base::FundamentalValue(static_cast<int>(0))); expected_list.reset(new base::ListValue()); expected_list->Append(new base::StringValue("value")); expected_subdict.reset(new base::DictionaryValue());
diff --git a/components/policy/core/common/schema.cc b/components/policy/core/common/schema.cc index 18fa9a7..9224478 100644 --- a/components/policy/core/common/schema.cc +++ b/components/policy/core/common/schema.cc
@@ -104,7 +104,7 @@ SCHEMA_ALLOW_UNKNOWN, // SCHEMA_ALLOW_INVALID_TOPLEVEL_AND_ALLOW_UNKNOWN SCHEMA_ALLOW_INVALID, // SCHEMA_ALLOW_INVALID }; - return next_level_strategy[(int)strategy]; + return next_level_strategy[static_cast<int>(strategy)]; } void SchemaErrorFound(std::string* error_path,
diff --git a/components/policy/resources/OWNERS b/components/policy/resources/OWNERS index ba78872f..5d894b89 100644 --- a/components/policy/resources/OWNERS +++ b/components/policy/resources/OWNERS
@@ -8,4 +8,3 @@ per-file policy_templates.json=set noparent per-file policy_templates.json=atwilson@chromium.org per-file policy_templates.json=bartfab@chromium.org -per-file policy_templates.json=joaodasilva@chromium.org
diff --git a/components/policy/resources/PRESUBMIT.py b/components/policy/resources/PRESUBMIT.py index 1f16ca8..b59e8d3 100644 --- a/components/policy/resources/PRESUBMIT.py +++ b/components/policy/resources/PRESUBMIT.py
@@ -3,7 +3,7 @@ # found in the LICENSE file. # If this presubmit check fails or misbehaves, please complain to -# mnissler@chromium.org, pastarmovj@chromium.org or joaodasilva@chromium.org. +# mnissler@chromium.org, bartfab@chromium.org or atwilson@chromium.org. import itertools import sys
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json index a652de6..6209b77 100644 --- a/components/policy/resources/policy_templates.json +++ b/components/policy/resources/policy_templates.json
@@ -123,7 +123,7 @@ # persistent IDs for all fields (but not for groups!) are needed. These are # specified by the 'id' keys of each policy. NEVER CHANGE EXISTING IDs, # because doing so would break the deployed wire format! -# For your editing convenience: highest ID currently used: 281 +# For your editing convenience: highest ID currently used: 283 # # Placeholders: # The following placeholder strings are automatically substituted: @@ -793,16 +793,57 @@ 'dynamic_refresh': True, 'per_profile': True, }, + 'deprecated': True, 'example_value': False, 'id': 162, 'caption': '''Force SafeSearch''', - 'desc': '''Forces queries in Google Web Search to be done with SafeSearch set to active and prevents users from changing this setting. This setting also forces Safety Mode on YouTube. + 'desc': '''This policy is deprecated, please use ForceGoogleSafeSearch and ForceYouTubeSafetyMode instead. + + Forces queries in Google Web Search to be done with SafeSearch set to active and prevents users from changing this setting. This setting also forces Safety Mode on YouTube. If you enable this setting, SafeSearch in Google Search and YouTube is always active. If you disable this setting or do not set a value, SafeSearch in Google Search and YouTube is not enforced.''', }, { + 'name': 'ForceGoogleSafeSearch', + 'type': 'main', + 'schema': { 'type': 'boolean' }, + 'supported_on': ['chrome.*:41-', 'chrome_os:41-', 'android:41-'], + 'features': { + 'can_be_recommended': False, + 'dynamic_refresh': True, + 'per_profile': True, + }, + 'example_value': False, + 'id': 282, + 'caption': '''Force Google SafeSearch''', + 'desc': '''Forces queries in Google Web Search to be done with SafeSearch set to active and prevents users from changing this setting. + + If you enable this setting, SafeSearch in Google Search is always active. + + If you disable this setting or do not set a value, SafeSearch in Google Search is not enforced.''', + }, + { + 'name': 'ForceYouTubeSafetyMode', + 'type': 'main', + 'schema': { 'type': 'boolean' }, + 'supported_on': ['chrome.*:41-', 'chrome_os:41-', 'android:41-'], + 'features': { + 'can_be_recommended': False, + 'dynamic_refresh': True, + 'per_profile': True, + }, + 'example_value': False, + 'id': 283, + 'caption': '''Force YouTube Safety Mode''', + 'desc': '''Forces YouTube Safety Mode to active and prevents users from changing this setting. + + If you enable this setting, Safety Mode on YouTube is always active. + + If you disable this setting or do not set a value, Safety Mode on YouTube is not enforced.''', + }, + { 'name': 'SafeBrowsingEnabled', 'type': 'main', 'schema': { 'type': 'boolean' }, @@ -6894,7 +6935,7 @@ 'caption': '''Minimum SSL version enabled''', 'desc': '''Warning: SSLv3 support will be entirely removed from Chrome after version 43 (around July 2015) after which the setting "ssl3" will be ignored and the default of "tls1" used instead. - If this policy is not configured then <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> will use a default minimum version, which is SSLv3 in Chrome 39 but may be TLS 1.0 in Chrome 40. + If this policy is not configured then <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> uses a default minimum version which is SSLv3 in <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> 39 and TLS 1.0 in later versions. Otherwise it may be set to one of the following values: "sslv3", "tls1", "tls1.1" or "tls1.2". When set, <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> will not use SSL/TLS versions less than the specified version. An unrecognized value will be ignored. @@ -6951,7 +6992,7 @@ When an SSL/TLS handshake fails, <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> will retry the connection with a lesser version of SSL/TLS in order to work around bugs in HTTPS servers. This setting configures the version at which this fallback process will stop. If a server performs version negotiation correctly (i.e. without breaking the connection) then this setting doesn't apply. Regardless, the resulting connection must still comply with SSLVersionMin. - If this policy is not configured then <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> will use a default minimum version, which was SSLv3 in Chrome 38 but is TLS 1.0 in Chrome 39. + If this policy is not configured then <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> uses a default minimum version which is SSLv3 in <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> 38 and TLS 1.0 in later versions. Otherwise it may be set to one of the following values: "sslv3", "tls1", "tls1.1" or "tls1.2". A setting of "tls1" protects against attacks on SSLv3 but is already the default. A more likely situation is that compatibility with a buggy server must be maintained and thus this needs to be set to "sslv3". That potentially opens up all connections to SSLv3 attacks since a network attacker can induce fallbacks. Thus this is a stopgap measure and the server should be rapidly fixed.
diff --git a/components/signin/core/browser/about_signin_internals.cc b/components/signin/core/browser/about_signin_internals.cc index 98a52f7d..9ff37168 100644 --- a/components/signin/core/browser/about_signin_internals.cc +++ b/components/signin/core/browser/about_signin_internals.cc
@@ -223,6 +223,9 @@ } void AboutSigninInternals::NotifyObservers() { + if (!signin_observers_.might_have_observers()) + return; + // TODO(vadimt): Remove ScopedTracker below once crbug.com/422460 is fixed. tracked_objects::ScopedTracker tracking_profile( FROM_HERE_WITH_EXPLICIT_FUNCTION(
diff --git a/content/DEPS b/content/DEPS index d3543fc..04a5d60 100644 --- a/content/DEPS +++ b/content/DEPS
@@ -75,6 +75,7 @@ "+third_party/WebKit/public/platform", "+third_party/WebKit/public/web", + "+ui/accelerated_widget_mac", "+ui/accessibility", "+ui/android", # Aura is analogous to Win32 or a Gtk, so it is allowed.
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index f02a034..ccccb626 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -336,6 +336,7 @@ "geolocation/empty_wifi_data_provider.cc", "geolocation/empty_wifi_data_provider.h", ] + deps += [ "//ui/accelerated_widget_mac" ] libs += [ "bsm" ] }
diff --git a/content/browser/accessibility/accessibility_tree_formatter_utils_win.cc b/content/browser/accessibility/accessibility_tree_formatter_utils_win.cc index 02159bc..fdf9519 100644 --- a/content/browser/accessibility/accessibility_tree_formatter_utils_win.cc +++ b/content/browser/accessibility/accessibility_tree_formatter_utils_win.cc
@@ -200,6 +200,7 @@ IA2_STATE_MAP(IA2_STATE_CHECKABLE) IA2_STATE_MAP(IA2_STATE_DEFUNCT) IA2_STATE_MAP(IA2_STATE_EDITABLE) + IA2_STATE_MAP(IA2_STATE_HORIZONTAL) IA2_STATE_MAP(IA2_STATE_ICONIFIED) IA2_STATE_MAP(IA2_STATE_INVALID_ENTRY) IA2_STATE_MAP(IA2_STATE_MANAGES_DESCENDANTS) @@ -211,12 +212,11 @@ IA2_STATE_MAP(IA2_STATE_STALE) IA2_STATE_MAP(IA2_STATE_SUPPORTS_AUTOCOMPLETION) IA2_STATE_MAP(IA2_STATE_TRANSIENT) + IA2_STATE_MAP(IA2_STATE_VERTICAL) // Untested states include those that would be repeated on nearly every node, // or would vary based on window size. - // IA2_STATE_MAP(IA2_STATE_HORIZONTAL) // Untested. // IA2_STATE_MAP(IA2_STATE_OPAQUE) // Untested. - // IA2_STATE_MAP(IA2_STATE_VERTICAL) // Untested. } } // namespace.
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc index a700e9a..3cbfbbd 100644 --- a/content/browser/accessibility/browser_accessibility.cc +++ b/content/browser/accessibility/browser_accessibility.cc
@@ -51,7 +51,6 @@ // implementation details, but we want to expose them as leaves // to platform accessibility APIs. switch (GetRole()) { - case ui::AX_ROLE_EDITABLE_TEXT: case ui::AX_ROLE_SLIDER: case ui::AX_ROLE_STATIC_TEXT: case ui::AX_ROLE_TEXT_AREA:
diff --git a/content/browser/accessibility/browser_accessibility_android.cc b/content/browser/accessibility/browser_accessibility_android.cc index 53189cbf..ce8f46d 100644 --- a/content/browser/accessibility/browser_accessibility_android.cc +++ b/content/browser/accessibility/browser_accessibility_android.cc
@@ -169,8 +169,7 @@ } bool BrowserAccessibilityAndroid::IsEditableText() const { - return (GetRole() == ui::AX_ROLE_EDITABLE_TEXT || - GetRole() == ui::AX_ROLE_TEXT_AREA || + return (GetRole() == ui::AX_ROLE_TEXT_AREA || GetRole() == ui::AX_ROLE_TEXT_FIELD); } @@ -247,7 +246,6 @@ const char* class_name = NULL; switch(GetRole()) { - case ui::AX_ROLE_EDITABLE_TEXT: case ui::AX_ROLE_SPIN_BUTTON: case ui::AX_ROLE_TEXT_AREA: case ui::AX_ROLE_TEXT_FIELD: @@ -334,7 +332,6 @@ switch (GetRole()) { case ui::AX_ROLE_COMBO_BOX: - case ui::AX_ROLE_EDITABLE_TEXT: case ui::AX_ROLE_POP_UP_BUTTON: case ui::AX_ROLE_TEXT_AREA: case ui::AX_ROLE_TEXT_FIELD: @@ -371,7 +368,6 @@ base::string16 placeholder; switch (GetRole()) { case ui::AX_ROLE_DATE: - case ui::AX_ROLE_EDITABLE_TEXT: case ui::AX_ROLE_TEXT_AREA: case ui::AX_ROLE_TEXT_FIELD: case ui::AX_ROLE_TIME:
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm index 33a95c4..bb3e2b5 100644 --- a/content/browser/accessibility/browser_accessibility_cocoa.mm +++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -446,20 +446,12 @@ } - (NSString*)orientation { - // We present a spin button as a vertical slider, with a role description - // of "spin button". - if ([self internalRole] == ui::AX_ROLE_SPIN_BUTTON) - return NSAccessibilityVerticalOrientationValue; - - if ([self internalRole] == ui::AX_ROLE_LIST || - [self internalRole] == ui::AX_ROLE_LIST_BOX) { - return NSAccessibilityVerticalOrientationValue; - } - if (GetState(browserAccessibility_, ui::AX_STATE_VERTICAL)) return NSAccessibilityVerticalOrientationValue; - else + else if (GetState(browserAccessibility_, ui::AX_STATE_HORIZONTAL)) return NSAccessibilityHorizontalOrientationValue; + + return @""; } - (NSNumber*)numberOfCharacters { @@ -1277,7 +1269,6 @@ [ret addObjectsFromArray:[NSArray arrayWithObjects: NSAccessibilityMaxValueAttribute, NSAccessibilityMinValueAttribute, - NSAccessibilityOrientationAttribute, NSAccessibilityValueDescriptionAttribute, nil]]; } else if ([subrole isEqualToString:NSAccessibilityOutlineRowSubrole]) { @@ -1308,7 +1299,6 @@ } } else if ([role isEqualToString:NSAccessibilityListRole]) { [ret addObjectsFromArray:[NSArray arrayWithObjects: - NSAccessibilityOrientationAttribute, NSAccessibilitySelectedChildrenAttribute, NSAccessibilityVisibleChildrenAttribute, nil]]; @@ -1355,6 +1345,12 @@ nil]]; } + if (GetState(browserAccessibility_, ui::AX_STATE_VERTICAL) + || GetState(browserAccessibility_, ui::AX_STATE_HORIZONTAL)) { + [ret addObjectsFromArray:[NSArray arrayWithObjects: + NSAccessibilityOrientationAttribute, nil]]; + } + // Title UI Element. if (browserAccessibility_->HasIntAttribute(ui::AX_ATTR_TITLE_UI_ELEMENT) || (browserAccessibility_->HasIntListAttribute(ui::AX_ATTR_LABELLEDBY_IDS) &&
diff --git a/content/browser/accessibility/browser_accessibility_win.cc b/content/browser/accessibility/browser_accessibility_win.cc index 65459ad..40b0e56e 100644 --- a/content/browser/accessibility/browser_accessibility_win.cc +++ b/content/browser/accessibility/browser_accessibility_win.cc
@@ -3358,11 +3358,10 @@ ia_state_ |= STATE_SYSTEM_TRAVERSED; if (!HasState(ui::AX_STATE_ENABLED)) ia_state_ |= STATE_SYSTEM_UNAVAILABLE; - if (HasState(ui::AX_STATE_VERTICAL)) { + if (HasState(ui::AX_STATE_VERTICAL)) ia2_state_ |= IA2_STATE_VERTICAL; - } else { + if (HasState(ui::AX_STATE_HORIZONTAL)) ia2_state_ |= IA2_STATE_HORIZONTAL; - } if (HasState(ui::AX_STATE_VISITED)) ia_state_ |= STATE_SYSTEM_TRAVERSED; @@ -3509,11 +3508,6 @@ ia_role_ = ROLE_SYSTEM_CLIENT; ia2_role_ = IA2_ROLE_EMBEDDED_OBJECT; break; - case ui::AX_ROLE_EDITABLE_TEXT: - ia_role_ = ROLE_SYSTEM_TEXT; - ia2_state_ |= IA2_STATE_SINGLE_LINE; - ia2_state_ |= IA2_STATE_EDITABLE; - break; case ui::AX_ROLE_FIGCAPTION: role_name_ = html_tag; ia2_role_ = IA2_ROLE_CAPTION; @@ -3550,10 +3544,6 @@ } break; } - case ui::AX_ROLE_GROW_AREA: - ia_role_ = ROLE_SYSTEM_GRIP; - ia_state_ |= STATE_SYSTEM_READONLY; - break; case ui::AX_ROLE_HEADING: role_name_ = html_tag; ia2_role_ = IA2_ROLE_HEADING; @@ -3731,11 +3721,6 @@ case ui::AX_ROLE_SPIN_BUTTON_PART: ia_role_ = ROLE_SYSTEM_PUSHBUTTON; break; - case ui::AX_ROLE_SPLIT_GROUP: - ia_role_ = ROLE_SYSTEM_CLIENT; - ia2_role_ = IA2_ROLE_SPLIT_PANE; - ia_state_ |= STATE_SYSTEM_READONLY; - break; case ui::AX_ROLE_ANNOTATION: case ui::AX_ROLE_LIST_MARKER: case ui::AX_ROLE_STATIC_TEXT:
diff --git a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc index 57aea660..82150d6 100644 --- a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc +++ b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -399,6 +399,10 @@ RunTest(FILE_PATH_LITERAL("aria-dialog.html")); } +IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaDirectory) { + RunTest(FILE_PATH_LITERAL("aria-directory.html")); +} + IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaExpanded) { RunTest(FILE_PATH_LITERAL("aria-expanded.html")); } @@ -494,6 +498,11 @@ RunTest(FILE_PATH_LITERAL("aria-menuitemradio.html")); } +IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, + AccessibilityAriaMultiline) { + RunTest(FILE_PATH_LITERAL("aria-multiline.html")); +} + IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaNavigation) { RunTest(FILE_PATH_LITERAL("aria-navigation.html")); } @@ -566,6 +575,10 @@ RunTest(FILE_PATH_LITERAL("aria-sort.html")); } +IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaSlider) { + RunTest(FILE_PATH_LITERAL("aria-slider.html")); +} + IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaSpinButton) { RunTest(FILE_PATH_LITERAL("aria-spinbutton.html")); @@ -588,10 +601,18 @@ RunTest(FILE_PATH_LITERAL("aria-toolbar.html")); } +IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaTooltip) { + RunTest(FILE_PATH_LITERAL("aria-tooltip.html")); +} + IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaTree) { RunTest(FILE_PATH_LITERAL("aria-tree.html")); } +IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaTreeGrid) { + RunTest(FILE_PATH_LITERAL("aria-treegrid.html")); +} + IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaValueMin) { RunTest(FILE_PATH_LITERAL("aria-valuemin.html")); }
diff --git a/content/browser/android/content_startup_flags.cc b/content/browser/android/content_startup_flags.cc index d8e132c4..f4d92d59e 100644 --- a/content/browser/android/content_startup_flags.cc +++ b/content/browser/android/content_startup_flags.cc
@@ -61,7 +61,12 @@ // Run the GPU service as a thread in the browser instead of as a // standalone process. + // TODO(sievers): Remove this parsed_command_line->AppendSwitch(switches::kInProcessGPU); + + // There is no software fallback on Android, so don't limit GPU crashes. + parsed_command_line->AppendSwitch(switches::kDisableGpuProcessCrashLimit); + parsed_command_line->AppendSwitch(switches::kDisableGpuShaderDiskCache); parsed_command_line->AppendSwitch(switches::kEnableViewport);
diff --git a/content/browser/android/in_process/synchronous_compositor_external_begin_frame_source.cc b/content/browser/android/in_process/synchronous_compositor_external_begin_frame_source.cc index 245561f..0c272fd 100644 --- a/content/browser/android/in_process/synchronous_compositor_external_begin_frame_source.cc +++ b/content/browser/android/in_process/synchronous_compositor_external_begin_frame_source.cc
@@ -33,9 +33,8 @@ void SynchronousCompositorExternalBeginFrameSource::BeginFrame() { DCHECK(CalledOnValidThread()); CallOnBeginFrame(cc::BeginFrameArgs::Create( - gfx::FrameTime::Now(), base::TimeTicks(), - cc::BeginFrameArgs::DefaultInterval(), - cc::BeginFrameArgs::SYNCHRONOUS)); + BEGINFRAME_FROM_HERE, gfx::FrameTime::Now(), base::TimeTicks(), + cc::BeginFrameArgs::DefaultInterval(), cc::BeginFrameArgs::SYNCHRONOUS)); } void SynchronousCompositorExternalBeginFrameSource::SetCompositor(
diff --git a/content/browser/android/java/gin_java_bridge_dispatcher_host.cc b/content/browser/android/java/gin_java_bridge_dispatcher_host.cc index c0b20b97..c8fb2fd 100644 --- a/content/browser/android/java/gin_java_bridge_dispatcher_host.cc +++ b/content/browser/android/java/gin_java_bridge_dispatcher_host.cc
@@ -210,18 +210,10 @@ named_objects_.erase(iter); object->RemoveName(); - // Not erasing from the objects map, as we can still receive method - // invocation requests for this object, and they should work until the - // java object is gone. - if (!object->IsNamed()) { - JNIEnv* env = base::android::AttachCurrentThread(); - base::android::ScopedJavaLocalRef<jobject> retained_object_set = - retained_object_set_.get(env); - if (!retained_object_set.is_null()) { - JNI_Java_HashSet_remove( - env, retained_object_set, object->GetLocalRef(env)); - } - } + // As the object isn't going to be removed from the JavaScript side until the + // next page reload, calls to it must still work, thus we should continue to + // hold it. All the transient objects and removed named objects will be purged + // during the cleansing caused by DocumentAvailableInMainFrame event. web_contents()->SendToAllFrames( new GinJavaBridgeMsg_RemoveNamedObject(MSG_ROUTING_NONE, copied_name));
diff --git a/content/browser/browser_main_runner.cc b/content/browser/browser_main_runner.cc index 491f6c0..2975ef8 100644 --- a/content/browser/browser_main_runner.cc +++ b/content/browser/browser_main_runner.cc
@@ -20,17 +20,11 @@ #include "ui/base/ime/input_method_initializer.h" #if defined(OS_WIN) -#include <dwrite.h> -#include "base/win/scoped_comptr.h" #include "base/win/win_util.h" #include "base/win/windows_version.h" #include "net/cert/sha256_legacy_support_win.h" #include "sandbox/win/src/sidestep/preamble_patcher.h" -#include "skia/ext/fontmgr_default_win.h" -#include "third_party/skia/include/ports/SkFontMgr.h" -#include "third_party/skia/include/ports/SkTypeface_win.h" #include "ui/base/win/scoped_ole_initializer.h" -#include "ui/gfx/platform_font_win.h" #include "ui/gfx/switches.h" #include "ui/gfx/win/direct_write.h" #endif @@ -118,43 +112,6 @@ #endif // _WIN64 } -void MaybeEnableDirectWriteFontRendering() { - if (gfx::win::ShouldUseDirectWrite() && - !CommandLine::ForCurrentProcess()->HasSwitch( - switches::kDisableDirectWriteForUI) && - !CommandLine::ForCurrentProcess()->HasSwitch( - switches::kDisableHarfBuzzRenderText)) { - typedef decltype(DWriteCreateFactory)* DWriteCreateFactoryProc; - HMODULE dwrite_dll = LoadLibraryW(L"dwrite.dll"); - if (!dwrite_dll) - return; - - DWriteCreateFactoryProc dwrite_create_factory_proc = - reinterpret_cast<DWriteCreateFactoryProc>( - GetProcAddress(dwrite_dll, "DWriteCreateFactory")); - // Not finding the DWriteCreateFactory function indicates a corrupt dll. - CHECK(dwrite_create_factory_proc); - - base::win::ScopedComPtr<IDWriteFactory> factory; - - CHECK(SUCCEEDED( - dwrite_create_factory_proc( - DWRITE_FACTORY_TYPE_SHARED, - __uuidof(IDWriteFactory), - reinterpret_cast<IUnknown**>(factory.Receive())))); - // The skia call to create a new DirectWrite font manager instance can fail - // if we are unable to get the system font collection from the DirectWrite - // factory. The GetSystemFontCollection method in the IDWriteFactory - // interface fails with E_INVALIDARG on certain Windows 7 gold versions - // (6.1.7600.*). We should just use GDI in these cases. - SkFontMgr* direct_write_font_mgr = SkFontMgr_New_DirectWrite(factory.get()); - if (direct_write_font_mgr) { - SetDefaultSkiaFactory(direct_write_font_mgr); - gfx::PlatformFontWin::SetDirectWriteFactory(factory.get()); - } - } -} - } // namespace #endif // OS_WIN @@ -208,7 +165,7 @@ // on Windows 8 Metro mode. ole_initializer_.reset(new ui::ScopedOleInitializer); // Enable DirectWrite font rendering if needed. - MaybeEnableDirectWriteFontRendering(); + gfx::win::MaybeInitializeDirectWrite(); #endif // OS_WIN main_loop_.reset(new BrowserMainLoop(parameters));
diff --git a/content/browser/child_process_launcher.cc b/content/browser/child_process_launcher.cc index 3529a74..0870e6c2 100644 --- a/content/browser/child_process_launcher.cc +++ b/content/browser/child_process_launcher.cc
@@ -317,9 +317,7 @@ if (launch_elevated) { base::LaunchOptions options; options.start_hidden = true; - base::ProcessHandle handle = base::kNullProcessHandle; - if (base::LaunchElevatedProcess(*cmd_line, options, &handle)) - process = base::Process(handle); + process = base::LaunchElevatedProcess(*cmd_line, options); } else { process = StartSandboxedProcess(delegate, cmd_line); } @@ -431,7 +429,7 @@ } if (launched) - broker->AddPlaceholderForPid(handle); + broker->AddPlaceholderForPid(handle, child_process_id); // After updating the broker, release the lock and let the child's // messasge be processed on the broker's thread.
diff --git a/content/browser/compositor/browser_compositor_view_mac.h b/content/browser/compositor/browser_compositor_view_mac.h index 013388d..c4ef507 100644 --- a/content/browser/compositor/browser_compositor_view_mac.h +++ b/content/browser/compositor/browser_compositor_view_mac.h
@@ -5,7 +5,7 @@ #ifndef CONTENT_BROWSER_COMPOSITOR_BROWSER_COMPOSITOR_VIEW_MAC_H_ #define CONTENT_BROWSER_COMPOSITOR_BROWSER_COMPOSITOR_VIEW_MAC_H_ -#include "content/browser/compositor/browser_compositor_ca_layer_tree_mac.h" +#include "ui/accelerated_widget_mac/accelerated_widget_mac.h" #include "ui/compositor/compositor.h" namespace content { @@ -23,14 +23,14 @@ static void Recycle(scoped_ptr<BrowserCompositorMac> compositor); ui::Compositor* compositor() { return &compositor_; } - AcceleratedWidgetMac* accelerated_widget_mac() { + ui::AcceleratedWidgetMac* accelerated_widget_mac() { return &accelerated_widget_mac_; } private: BrowserCompositorMac(); - AcceleratedWidgetMac accelerated_widget_mac_; + ui::AcceleratedWidgetMac accelerated_widget_mac_; ui::Compositor compositor_; DISALLOW_COPY_AND_ASSIGN(BrowserCompositorMac);
diff --git a/content/browser/compositor/browser_compositor_view_mac.mm b/content/browser/compositor/browser_compositor_view_mac.mm index aa889d6..7b2c799 100644 --- a/content/browser/compositor/browser_compositor_view_mac.mm +++ b/content/browser/compositor/browser_compositor_view_mac.mm
@@ -6,9 +6,11 @@ #include "base/debug/trace_event.h" #include "base/lazy_instance.h" -#include "content/browser/compositor/browser_compositor_ca_layer_tree_mac.h" +#include "content/browser/gpu/gpu_data_manager_impl.h" #include "content/browser/renderer_host/render_widget_resize_helper.h" #include "content/public/browser/context_factory.h" +#include "gpu/config/gpu_driver_bug_workaround_type.h" +#include "ui/accelerated_widget_mac/accelerated_widget_mac.h" //////////////////////////////////////////////////////////////////////////////// // BrowserCompositorMac @@ -26,10 +28,16 @@ base::LazyInstance<scoped_ptr<BrowserCompositorMac>> g_recyclable_browser_compositor; +bool WidgetNeedsGLFinishWorkaround() { + return GpuDataManagerImpl::GetInstance()->IsDriverBugWorkaroundActive( + gpu::FORCE_GL_FINISH_AFTER_COMPOSITING); +} + } // namespace BrowserCompositorMac::BrowserCompositorMac() - : compositor_( + : accelerated_widget_mac_(WidgetNeedsGLFinishWorkaround()), + compositor_( accelerated_widget_mac_.accelerated_widget(), content::GetContextFactory(), RenderWidgetResizeHelper::Get()->task_runner()) {
diff --git a/content/browser/compositor/gpu_process_transport_factory.cc b/content/browser/compositor/gpu_process_transport_factory.cc index 1c737dda..9f56909 100644 --- a/content/browser/compositor/gpu_process_transport_factory.cc +++ b/content/browser/compositor/gpu_process_transport_factory.cc
@@ -238,6 +238,7 @@ manager, compositor->surface_id_allocator(), context_provider)); display_client->set_surface_output_surface(output_surface.get()); output_surface->set_display_client(display_client.get()); + display_client->display()->Resize(compositor->size()); data->display_client = display_client.Pass(); compositor->SetOutputSurface(output_surface.Pass()); return; @@ -375,6 +376,17 @@ new cc::SurfaceIdAllocator(next_surface_id_namespace_++)); } +void GpuProcessTransportFactory::ResizeDisplay(ui::Compositor* compositor, + const gfx::Size& size) { + PerCompositorDataMap::iterator it = per_compositor_data_.find(compositor); + if (it == per_compositor_data_.end()) + return; + PerCompositorData* data = it->second; + DCHECK(data); + if (data->display_client) + data->display_client->display()->Resize(size); +} + cc::SurfaceManager* GpuProcessTransportFactory::GetSurfaceManager() { return surface_manager_.get(); }
diff --git a/content/browser/compositor/gpu_process_transport_factory.h b/content/browser/compositor/gpu_process_transport_factory.h index 25cfbc0..2608ff18 100644 --- a/content/browser/compositor/gpu_process_transport_factory.h +++ b/content/browser/compositor/gpu_process_transport_factory.h
@@ -56,6 +56,8 @@ gpu::GpuMemoryBufferManager* GetGpuMemoryBufferManager() override; base::MessageLoopProxy* GetCompositorMessageLoop() override; scoped_ptr<cc::SurfaceIdAllocator> CreateSurfaceIdAllocator() override; + void ResizeDisplay(ui::Compositor* compositor, + const gfx::Size& size) override; // ImageTransportFactory implementation. ui::ContextFactory* GetContextFactory() override;
diff --git a/content/browser/compositor/overlay_candidate_validator_ozone.cc b/content/browser/compositor/overlay_candidate_validator_ozone.cc index a92dc101..90db8d8 100644 --- a/content/browser/compositor/overlay_candidate_validator_ozone.cc +++ b/content/browser/compositor/overlay_candidate_validator_ozone.cc
@@ -19,6 +19,7 @@ case cc::LUMINANCE_8: case cc::RGB_565: case cc::ETC1: + case cc::RED_8: break; } NOTREACHED();
diff --git a/content/browser/compositor/software_output_device_mac.mm b/content/browser/compositor/software_output_device_mac.mm index e08372e..129c9d8b 100644 --- a/content/browser/compositor/software_output_device_mac.mm +++ b/content/browser/compositor/software_output_device_mac.mm
@@ -6,7 +6,7 @@ #include "content/browser/compositor/software_output_device_mac.h" -#include "content/browser/compositor/browser_compositor_ca_layer_tree_mac.h" +#include "ui/accelerated_widget_mac/accelerated_widget_mac.h" #include "ui/compositor/compositor.h" namespace content { @@ -20,8 +20,8 @@ void SoftwareOutputDeviceMac::EndPaint(cc::SoftwareFrameData* frame_data) { SoftwareOutputDevice::EndPaint(frame_data); - AcceleratedWidgetMacGotSoftwareFrame( - compositor_->widget(), frame_data, scale_factor_, canvas_.get()); + ui::AcceleratedWidgetMacGotSoftwareFrame( + compositor_->widget(), scale_factor_, canvas_.get()); } } // namespace content
diff --git a/content/browser/compositor/surface_display_output_surface.cc b/content/browser/compositor/surface_display_output_surface.cc index e15aeb5a..19ab9ad 100644 --- a/content/browser/compositor/surface_display_output_surface.cc +++ b/content/browser/compositor/surface_display_output_surface.cc
@@ -51,8 +51,8 @@ factory_.Create(surface_id_); display_size_ = frame_size; } - display_client_->display()->Resize( - surface_id_, frame_size, frame->metadata.device_scale_factor); + display_client_->display()->SetSurfaceId(surface_id_, + frame->metadata.device_scale_factor); scoped_ptr<cc::CompositorFrame> frame_copy(new cc::CompositorFrame()); frame->AssignTo(frame_copy.get());
diff --git a/content/browser/devtools/devtools_http_handler_impl.cc b/content/browser/devtools/devtools_http_handler_impl.cc index c5d4076..f3aa4a3 100644 --- a/content/browser/devtools/devtools_http_handler_impl.cc +++ b/content/browser/devtools/devtools_http_handler_impl.cc
@@ -101,8 +101,7 @@ private: // DevToolsHttpHandler implementation. - GURL GetFrontendURL() override; - + GURL GetFrontendURL(const std::string& path) override; static void OnTargetListReceivedWeak( base::WeakPtr<DevToolsHttpHandlerImpl> handler, @@ -525,10 +524,11 @@ STLDeleteValues(&connection_to_client_); } -GURL DevToolsHttpHandlerImpl::GetFrontendURL() { +GURL DevToolsHttpHandlerImpl::GetFrontendURL(const std::string& path) { if (!server_ip_address_) return GURL(); - return GURL(std::string("http://") + server_ip_address_->ToString() + frontend_url_); + return GURL(std::string("http://") + server_ip_address_->ToString() + + (path.empty() ? frontend_url_ : path)); } static std::string PathWithoutParams(const std::string& path) {
diff --git a/content/browser/devtools/protocol/page_handler.cc b/content/browser/devtools/protocol/page_handler.cc index e00b97e..c3d04b2 100644 --- a/content/browser/devtools/protocol/page_handler.cc +++ b/content/browser/devtools/protocol/page_handler.cc
@@ -115,9 +115,10 @@ screencast_max_width_(-1), screencast_max_height_(-1), capture_retry_count_(0), - has_last_compositor_frame_metadata_(false), + has_compositor_frame_metadata_(false), screencast_frame_sent_(0), screencast_frame_acked_(0), + processing_screencast_frame_(false), color_picker_(new ColorPicker(base::Bind( &PageHandler::OnColorPicked, base::Unretained(this)))), host_(nullptr), @@ -146,8 +147,10 @@ void PageHandler::OnSwapCompositorFrame( const cc::CompositorFrameMetadata& frame_metadata) { - last_compositor_frame_metadata_ = frame_metadata; - has_last_compositor_frame_metadata_ = true; + last_compositor_frame_metadata_ = has_compositor_frame_metadata_ ? + next_compositor_frame_metadata_ : frame_metadata; + next_compositor_frame_metadata_ = frame_metadata; + has_compositor_frame_metadata_ = true; if (screencast_enabled_) InnerSwapCompositorFrame(); @@ -377,7 +380,7 @@ bool visible = !host_->is_hidden(); NotifyScreencastVisibility(visible); if (visible) { - if (has_last_compositor_frame_metadata_) + if (has_compositor_frame_metadata_) InnerSwapCompositorFrame(); else host_->Send(new ViewMsg_ForceRedraw(host_->GetRoutingID(), 0)); @@ -470,7 +473,7 @@ void PageHandler::InnerSwapCompositorFrame() { if (screencast_frame_sent_ - screencast_frame_acked_ > - kMaxScreencastFramesInFlight) { + kMaxScreencastFramesInFlight || processing_screencast_frame_) { return; } @@ -508,6 +511,7 @@ gfx::ScaleSize(viewport_size_dip, scale))); if (snapshot_size_dip.width() > 0 && snapshot_size_dip.height() > 0) { + processing_screencast_frame_ = true; gfx::Rect viewport_bounds_dip(gfx::ToRoundedSize(viewport_size_dip)); view->CopyFromCompositingSurface( viewport_bounds_dip, @@ -524,6 +528,7 @@ const SkBitmap& bitmap, ReadbackResponse response) { if (response != READBACK_SUCCESS) { + processing_screencast_frame_ = false; if (capture_retry_count_) { --capture_retry_count_; base::MessageLoop::current()->PostDelayedTask( @@ -546,6 +551,8 @@ void PageHandler::ScreencastFrameEncoded( const cc::CompositorFrameMetadata& metadata, const std::string& data) { + processing_screencast_frame_ = false; + // Consider metadata empty in case it has no device scale factor. if (metadata.device_scale_factor == 0 || !host_ || data.empty()) return;
diff --git a/content/browser/devtools/protocol/page_handler.h b/content/browser/devtools/protocol/page_handler.h index b95618a..c0a3a6ac 100644 --- a/content/browser/devtools/protocol/page_handler.h +++ b/content/browser/devtools/protocol/page_handler.h
@@ -117,10 +117,12 @@ int screencast_max_width_; int screencast_max_height_; int capture_retry_count_; - bool has_last_compositor_frame_metadata_; + bool has_compositor_frame_metadata_; + cc::CompositorFrameMetadata next_compositor_frame_metadata_; cc::CompositorFrameMetadata last_compositor_frame_metadata_; int screencast_frame_sent_; int screencast_frame_acked_; + bool processing_screencast_frame_; scoped_ptr<ColorPicker> color_picker_;
diff --git a/content/browser/frame_host/navigator_impl_unittest.cc b/content/browser/frame_host/navigator_impl_unittest.cc index 96afc97..2258b25 100644 --- a/content/browser/frame_host/navigator_impl_unittest.cc +++ b/content/browser/frame_host/navigator_impl_unittest.cc
@@ -33,14 +33,8 @@ : public RenderViewHostImplTestHarness { public: void SetUp() override { - RenderViewHostImplTestHarness::SetUp(); - BrowserSideNavigationSetUp(); EnableBrowserSideNavigation(); - } - - void TearDown() override { - BrowserSideNavigationTearDown(); - RenderViewHostImplTestHarness::TearDown(); + RenderViewHostImplTestHarness::SetUp(); } TestNavigationURLLoader* GetLoaderForNavigationRequest(
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc index c95c67b0..bd618c4 100644 --- a/content/browser/frame_host/render_frame_host_impl.cc +++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -1214,6 +1214,15 @@ } } + // We may be returning to an existing NavigationEntry that had been granted + // file access. If this is a different process, we will need to grant the + // access again. The files listed in the page state are validated when they + // are received from the renderer to prevent abuse. + if (params.commit_params.page_state.IsValid()) { + render_view_host_->GrantFileAccessFromPageState( + params.commit_params.page_state); + } + // Only send the message if we aren't suspended at the start of a cross-site // request. if (navigations_suspended_) {
diff --git a/content/browser/frame_host/render_frame_host_manager_browsertest.cc b/content/browser/frame_host/render_frame_host_manager_browsertest.cc index 54a0d49..a1942026 100644 --- a/content/browser/frame_host/render_frame_host_manager_browsertest.cc +++ b/content/browser/frame_host/render_frame_host_manager_browsertest.cc
@@ -7,6 +7,7 @@ #include "base/command_line.h" #include "base/json/json_reader.h" #include "base/memory/ref_counted.h" +#include "base/path_service.h" #include "base/strings/utf_string_conversions.h" #include "base/values.h" #include "content/browser/child_process_security_policy_impl.h" @@ -22,6 +23,9 @@ #include "content/public/browser/web_contents_observer.h" #include "content/public/common/bindings_policy.h" #include "content/public/common/content_switches.h" +#include "content/public/common/file_chooser_file_info.h" +#include "content/public/common/file_chooser_params.h" +#include "content/public/common/page_state.h" #include "content/public/common/url_constants.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/content_browser_test.h" @@ -1511,4 +1515,85 @@ shell()->web_contents()->GetRenderProcessHost()->GetID())); } +class FileChooserDelegate : public WebContentsDelegate { + public: + FileChooserDelegate(const base::FilePath& file) + : file_(file), file_chosen_(false) {} + + void RunFileChooser(WebContents* web_contents, + const FileChooserParams& params) override { + // Send the selected file to the renderer process. + FileChooserFileInfo file_info; + file_info.file_path = file_; + std::vector<FileChooserFileInfo> files; + files.push_back(file_info); + web_contents->GetRenderViewHost()->FilesSelectedInChooser( + files, FileChooserParams::Open); + + file_chosen_ = true; + } + + bool file_chosen() { return file_chosen_; } + + private: + base::FilePath file_; + bool file_chosen_; +}; + +// Test for http://crbug.com/262948. +IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest, + RestoreFileAccessForHistoryNavigation) { + StartServer(); + base::FilePath file_path; + EXPECT_TRUE(PathService::Get(base::DIR_TEMP, &file_path)); + file_path = file_path.AppendASCII("bar"); + + // Navigate to url and get it to reference a file in its PageState. + GURL url1(test_server()->GetURL("files/file_input.html")); + NavigateToURL(shell(), url1); + int process_id = shell()->web_contents()->GetRenderProcessHost()->GetID(); + scoped_ptr<FileChooserDelegate> delegate(new FileChooserDelegate(file_path)); + shell()->web_contents()->SetDelegate(delegate.get()); + EXPECT_TRUE(ExecuteScript(shell()->web_contents(), + "document.getElementById('fileinput').click();")); + EXPECT_TRUE(delegate->file_chosen()); + EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile( + process_id, file_path)); + + // Navigate to a different process without access to the file, and wait for + // the old process to exit. + RenderProcessHostWatcher exit_observer( + shell()->web_contents()->GetRenderProcessHost(), + RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION); + NavigateToURL(shell(), GetCrossSiteURL("files/title1.html")); + exit_observer.Wait(); + EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile( + shell()->web_contents()->GetRenderProcessHost()->GetID(), file_path)); + + // Ensure that the file ended up in the PageState of the previous entry. + NavigationEntry* prev_entry = + shell()->web_contents()->GetController().GetEntryAtIndex(0); + EXPECT_EQ(url1, prev_entry->GetURL()); + const std::vector<base::FilePath>& file_paths = + prev_entry->GetPageState().GetReferencedFiles(); + ASSERT_EQ(1U, file_paths.size()); + EXPECT_EQ(file_path, file_paths.at(0)); + + // Go back, ending up in a different RenderProcessHost than before. + TestNavigationObserver back_nav_load_observer(shell()->web_contents()); + shell()->web_contents()->GetController().GoBack(); + back_nav_load_observer.Wait(); + EXPECT_NE(process_id, + shell()->web_contents()->GetRenderProcessHost()->GetID()); + + // Ensure that the file access still exists in the new process ID. + EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile( + shell()->web_contents()->GetRenderProcessHost()->GetID(), file_path)); + + // Navigate to a same site page to trigger a PageState update and ensure the + // renderer is not killed. + EXPECT_TRUE( + NavigateToURL(shell(), test_server()->GetURL("files/title2.html"))); +} + } // namespace content
diff --git a/content/browser/frame_host/render_frame_host_manager_unittest.cc b/content/browser/frame_host/render_frame_host_manager_unittest.cc index 11c3c8a..69eb043 100644 --- a/content/browser/frame_host/render_frame_host_manager_unittest.cc +++ b/content/browser/frame_host/render_frame_host_manager_unittest.cc
@@ -1405,7 +1405,6 @@ // Fake a process crash. RenderProcessHost::RendererClosedDetails details( - rvh1->GetProcess()->GetHandle(), base::TERMINATION_STATUS_PROCESS_CRASHED, 0); NotificationService::current()->Notify(
diff --git a/content/browser/gpu/gpu_process_host_ui_shim.cc b/content/browser/gpu/gpu_process_host_ui_shim.cc index c92a72db..2293e74 100644 --- a/content/browser/gpu/gpu_process_host_ui_shim.cc +++ b/content/browser/gpu/gpu_process_host_ui_shim.cc
@@ -25,7 +25,7 @@ #include "content/public/browser/browser_thread.h" #if defined(OS_MACOSX) -#include "content/browser/compositor/browser_compositor_ca_layer_tree_mac.h" +#include "ui/accelerated_widget_mac/accelerated_widget_mac.h" #endif #if defined(USE_OZONE) @@ -279,7 +279,7 @@ DCHECK(IsDelegatedRendererEnabled()); gfx::AcceleratedWidget native_widget = content::GpuSurfaceTracker::Get()->AcquireNativeWidget(params.surface_id); - AcceleratedWidgetMacGotAcceleratedFrame( + ui::AcceleratedWidgetMacGotAcceleratedFrame( native_widget, params.surface_handle, params.latency_info,
diff --git a/content/browser/loader/resource_loader.cc b/content/browser/loader/resource_loader.cc index 36c6328..ac843af8 100644 --- a/content/browser/loader/resource_loader.cc +++ b/content/browser/loader/resource_loader.cc
@@ -643,6 +643,10 @@ } void ResourceLoader::StartReading(bool is_continuation) { + // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed. + tracked_objects::ScopedTracker tracking_profile( + FROM_HERE_WITH_EXPLICIT_FUNCTION("423948 ResourceLoader::StartReading")); + int bytes_read = 0; ReadMore(&bytes_read); @@ -680,6 +684,10 @@ } void ResourceLoader::ReadMore(int* bytes_read) { + // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed. + tracked_objects::ScopedTracker tracking_profile1( + FROM_HERE_WITH_EXPLICIT_FUNCTION("423948 ResourceLoader::ReadMore1")); + DCHECK(!is_deferred()); // Make sure we track the buffer in at least one place. This ensures it gets @@ -689,8 +697,8 @@ int buf_size; { // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed. - tracked_objects::ScopedTracker tracking_profile( - FROM_HERE_WITH_EXPLICIT_FUNCTION("423948 ResourceLoader::ReadMore")); + tracked_objects::ScopedTracker tracking_profile2( + FROM_HERE_WITH_EXPLICIT_FUNCTION("423948 ResourceLoader::ReadMore2")); if (!handler_->OnWillRead(&buf, &buf_size, -1)) { Cancel();
diff --git a/content/browser/mach_broker_mac.h b/content/browser/mach_broker_mac.h index 9088ca70..4aa34dc3 100644 --- a/content/browser/mach_broker_mac.h +++ b/content/browser/mach_broker_mac.h
@@ -5,11 +5,11 @@ #ifndef CONTENT_BROWSER_MACH_BROKER_MAC_H_ #define CONTENT_BROWSER_MACH_BROKER_MAC_H_ +#include <mach/mach.h> + #include <map> #include <string> -#include <mach/mach.h> - #include "base/memory/singleton.h" #include "base/process/process_handle.h" #include "base/process/process_metrics.h" @@ -61,7 +61,7 @@ // Callers are expected to later update the port with FinalizePid(). Callers // MUST acquire the lock given by GetLock() before calling this method (and // release the lock afterwards). - void AddPlaceholderForPid(base::ProcessHandle pid); + void AddPlaceholderForPid(base::ProcessHandle pid, int child_process_id); // Implement |ProcessMetrics::PortProvider|. mach_port_t TaskForPid(base::ProcessHandle process) const override; @@ -90,8 +90,8 @@ // this method (and release the lock afterwards). void FinalizePid(base::ProcessHandle pid, mach_port_t task_port); - // Removes all mappings belonging to |pid| from the broker. - void InvalidatePid(base::ProcessHandle pid); + // Removes all mappings belonging to |child_process_id| from the broker. + void InvalidateChildProcessId(int child_process_id); // Returns the Mach port name to use when sending or receiving messages. // Does the Right Thing in the browser and in child processes. @@ -110,7 +110,12 @@ typedef std::map<base::ProcessHandle, mach_port_t> MachMap; MachMap mach_map_; - // Mutex that guards |mach_map_|. + // Stores the Child process unique id (RenderProcessHost ID) for every + // process. + typedef std::map<int, base::ProcessHandle> ChildProcessIdMap; + ChildProcessIdMap child_process_id_map_; + + // Mutex that guards |mach_map_| and |child_process_id_map_|. mutable base::Lock lock_; DISALLOW_COPY_AND_ASSIGN(MachBroker);
diff --git a/content/browser/mach_broker_mac.mm b/content/browser/mach_broker_mac.mm index f2e5f985..0e0eec8 100644 --- a/content/browser/mach_broker_mac.mm +++ b/content/browser/mach_broker_mac.mm
@@ -195,11 +195,13 @@ } } -void MachBroker::AddPlaceholderForPid(base::ProcessHandle pid) { +void MachBroker::AddPlaceholderForPid(base::ProcessHandle pid, + int child_process_id) { lock_.AssertAcquired(); DCHECK_EQ(0u, mach_map_.count(pid)); mach_map_[pid] = MACH_PORT_NULL; + child_process_id_map_[child_process_id] = pid; } mach_port_t MachBroker::TaskForPid(base::ProcessHandle pid) const { @@ -212,33 +214,27 @@ void MachBroker::BrowserChildProcessHostDisconnected( const ChildProcessData& data) { - InvalidatePid(data.handle); + InvalidateChildProcessId(data.id); } void MachBroker::BrowserChildProcessCrashed(const ChildProcessData& data) { - InvalidatePid(data.handle); + InvalidateChildProcessId(data.id); } void MachBroker::Observe(int type, const NotificationSource& source, const NotificationDetails& details) { - // TODO(rohitrao): These notifications do not always carry the proper PIDs, - // especially when the renderer is already gone or has crashed. Find a better - // way to listen for child process deaths. http://crbug.com/55734 - base::ProcessHandle handle = 0; switch (type) { - case NOTIFICATION_RENDERER_PROCESS_CLOSED: - handle = Details<RenderProcessHost::RendererClosedDetails>( - details)->handle; - break; case NOTIFICATION_RENDERER_PROCESS_TERMINATED: - handle = Source<RenderProcessHost>(source)->GetHandle(); + case NOTIFICATION_RENDERER_PROCESS_CLOSED: { + RenderProcessHost* host = Source<RenderProcessHost>(source).ptr(); + InvalidateChildProcessId(host->GetID()); break; + } default: NOTREACHED() << "Unexpected notification"; break; } - InvalidatePid(handle); } MachBroker::MachBroker() : listener_thread_started_(false) { @@ -262,16 +258,21 @@ it->second = task_port; } -void MachBroker::InvalidatePid(base::ProcessHandle pid) { +void MachBroker::InvalidateChildProcessId(int child_process_id) { base::AutoLock lock(lock_); - MachBroker::MachMap::iterator it = mach_map_.find(pid); - if (it == mach_map_.end()) + MachBroker::ChildProcessIdMap::iterator it = + child_process_id_map_.find(child_process_id); + if (it == child_process_id_map_.end()) return; - kern_return_t kr = mach_port_deallocate(mach_task_self(), - it->second); - MACH_LOG_IF(WARNING, kr != KERN_SUCCESS, kr) << "mach_port_deallocate"; - mach_map_.erase(it); + MachMap::iterator mach_it = mach_map_.find(it->second); + if (mach_it != mach_map_.end()) { + kern_return_t kr = mach_port_deallocate(mach_task_self(), + mach_it->second); + MACH_LOG_IF(WARNING, kr != KERN_SUCCESS, kr) << "mach_port_deallocate"; + mach_map_.erase(mach_it); + } + child_process_id_map_.erase(it); } // static
diff --git a/content/browser/mach_broker_mac_unittest.cc b/content/browser/mach_broker_mac_unittest.cc index a7eca4fd..9ba50c3 100644 --- a/content/browser/mach_broker_mac_unittest.cc +++ b/content/browser/mach_broker_mac_unittest.cc
@@ -12,13 +12,17 @@ class MachBrokerTest : public testing::Test { public: // Helper function to acquire/release locks and call |PlaceholderForPid()|. - void AddPlaceholderForPid(base::ProcessHandle pid) { + void AddPlaceholderForPid(base::ProcessHandle pid, int child_process_id) { base::AutoLock lock(broker_.GetLock()); - broker_.AddPlaceholderForPid(pid); + broker_.AddPlaceholderForPid(pid, child_process_id); } - void InvalidatePid(base::ProcessHandle pid) { - broker_.InvalidatePid(pid); + void InvalidateChildProcessId(int child_process_id) { + broker_.InvalidateChildProcessId(child_process_id); + } + + int GetChildProcessCount(int child_process_id) { + return broker_.child_process_id_map_.count(child_process_id); } // Helper function to acquire/release locks and call |FinalizePid()|. @@ -39,7 +43,7 @@ TEST_F(MachBrokerTest, AddPlaceholderAndFinalize) { // Add a placeholder for PID 1. - AddPlaceholderForPid(1); + AddPlaceholderForPid(1, 1); EXPECT_EQ(0u, broker_.TaskForPid(1)); // Finalize PID 1. @@ -50,15 +54,26 @@ EXPECT_EQ(0u, broker_.TaskForPid(2)); } -TEST_F(MachBrokerTest, Invalidate) { - AddPlaceholderForPid(1); +TEST_F(MachBrokerTest, InvalidateChildProcessId) { + // Add a placeholder for PID 1 and child process id 50. + AddPlaceholderForPid(1, 50); FinalizePid(1, 100u); EXPECT_EQ(100u, broker_.TaskForPid(1)); - InvalidatePid(1u); + InvalidateChildProcessId(50); EXPECT_EQ(0u, broker_.TaskForPid(1)); } +TEST_F(MachBrokerTest, ValidateChildProcessIdMap) { + // Add a placeholder for PID 1 and child process id 50. + AddPlaceholderForPid(1, 50); + FinalizePid(1, 100u); + + EXPECT_EQ(1, GetChildProcessCount(50)); + InvalidateChildProcessId(50); + EXPECT_EQ(0, GetChildProcessCount(50)); +} + TEST_F(MachBrokerTest, FinalizeUnknownPid) { // Finalizing an entry for an unknown pid should not add it to the map. FinalizePid(1u, 100u);
diff --git a/content/browser/media/capture/web_contents_audio_input_stream.cc b/content/browser/media/capture/web_contents_audio_input_stream.cc index 605124d..629d106 100644 --- a/content/browser/media/capture/web_contents_audio_input_stream.cc +++ b/content/browser/media/capture/web_contents_audio_input_stream.cc
@@ -382,8 +382,8 @@ return impl_->mixer_stream()->GetVolume(); } -void WebContentsAudioInputStream::SetAutomaticGainControl(bool enabled) { - impl_->mixer_stream()->SetAutomaticGainControl(enabled); +bool WebContentsAudioInputStream::SetAutomaticGainControl(bool enabled) { + return impl_->mixer_stream()->SetAutomaticGainControl(enabled); } bool WebContentsAudioInputStream::GetAutomaticGainControl() {
diff --git a/content/browser/media/capture/web_contents_audio_input_stream.h b/content/browser/media/capture/web_contents_audio_input_stream.h index d66d2700..ff8074d4 100644 --- a/content/browser/media/capture/web_contents_audio_input_stream.h +++ b/content/browser/media/capture/web_contents_audio_input_stream.h
@@ -44,7 +44,7 @@ double GetMaxVolume() override; void SetVolume(double volume) override; double GetVolume() override; - void SetAutomaticGainControl(bool enabled) override; + bool SetAutomaticGainControl(bool enabled) override; bool GetAutomaticGainControl() override; bool IsMuted() override;
diff --git a/content/browser/media/capture/web_contents_audio_input_stream_unittest.cc b/content/browser/media/capture/web_contents_audio_input_stream_unittest.cc index 9772c945..c107808 100644 --- a/content/browser/media/capture/web_contents_audio_input_stream_unittest.cc +++ b/content/browser/media/capture/web_contents_audio_input_stream_unittest.cc
@@ -134,7 +134,7 @@ MOCK_METHOD0(GetMaxVolume, double()); MOCK_METHOD1(SetVolume, void(double)); MOCK_METHOD0(GetVolume, double()); - MOCK_METHOD1(SetAutomaticGainControl, void(bool)); + MOCK_METHOD1(SetAutomaticGainControl, bool(bool)); MOCK_METHOD0(GetAutomaticGainControl, bool()); MOCK_METHOD2(AddOutputStream, void(VirtualAudioOutputStream*, const AudioParameters&));
diff --git a/content/browser/media/cdm/browser_cdm_manager.cc b/content/browser/media/cdm/browser_cdm_manager.cc index 92720d3d..b8e9224 100644 --- a/content/browser/media/cdm/browser_cdm_manager.cc +++ b/content/browser/media/cdm/browser_cdm_manager.cc
@@ -71,21 +71,17 @@ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI); } - // This may overwrite an existing entry of |render_process_id| if the - // previous process crashed and didn't cleanup its child frames. For example, - // see FrameTreeBrowserTest.FrameTreeAfterCrash test. + DCHECK(!g_browser_cdm_manager_map.Get().count(render_process_id_)) + << render_process_id_; g_browser_cdm_manager_map.Get()[render_process_id] = this; } BrowserCdmManager::~BrowserCdmManager() { DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK(g_browser_cdm_manager_map.Get().count(render_process_id_)); + DCHECK_EQ(this, g_browser_cdm_manager_map.Get()[render_process_id_]); - // If an entry of |render_process_id| was overwritten, we shouldn't remove - // the entry. For example, see FrameTreeBrowserTest.FrameTreeAfterCrash test, - // and http://crbug.com/430251. - if (g_browser_cdm_manager_map.Get()[render_process_id_] == this) - g_browser_cdm_manager_map.Get().erase(render_process_id_); + g_browser_cdm_manager_map.Get().erase(render_process_id_); } // Makes sure BrowserCdmManager is always deleted on the Browser UI thread.
diff --git a/content/browser/message_port_provider.cc b/content/browser/message_port_provider.cc index d00fdf1..12be0653 100644 --- a/content/browser/message_port_provider.cc +++ b/content/browser/message_port_provider.cc
@@ -63,6 +63,8 @@ MessagePortService* msp = MessagePortService::GetInstance(); msp->Create(mf->GetNextRoutingID(), mf, port1); msp->Create(mf->GetNextRoutingID(), mf, port2); + msp->Entangle(*port1, *port2); + msp->Entangle(*port2, *port1); } } // namespace content
diff --git a/content/browser/push_messaging/OWNERS b/content/browser/push_messaging/OWNERS index fd872d5f0..9fe6d9b 100644 --- a/content/browser/push_messaging/OWNERS +++ b/content/browser/push_messaging/OWNERS
@@ -1,3 +1,2 @@ mvanouwerkerk@chromium.org peter@chromium.org -
diff --git a/content/browser/push_messaging/push_messaging_message_filter.cc b/content/browser/push_messaging/push_messaging_message_filter.cc index fbece4a4..e3edeaf4 100644 --- a/content/browser/push_messaging/push_messaging_message_filter.cc +++ b/content/browser/push_messaging/push_messaging_message_filter.cc
@@ -7,6 +7,7 @@ #include <string> #include "base/bind.h" +#include "base/logging.h" #include "base/metrics/histogram.h" #include "base/strings/string_number_conversions.h" #include "content/browser/renderer_host/render_process_host_impl.h" @@ -44,19 +45,25 @@ const IPC::Message& message) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(PushMessagingMessageFilter, message) - IPC_MESSAGE_HANDLER(PushMessagingHostMsg_Register, OnRegister) + IPC_MESSAGE_HANDLER(PushMessagingHostMsg_RegisterFromDocument, + OnRegisterFromDocument) + IPC_MESSAGE_HANDLER(PushMessagingHostMsg_RegisterFromWorker, + OnRegisterFromWorker) IPC_MESSAGE_HANDLER(PushMessagingHostMsg_PermissionStatus, OnPermissionStatusRequest) + IPC_MESSAGE_HANDLER(PushMessagingHostMsg_GetPermissionStatus, + OnGetPermissionStatus) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; } -void PushMessagingMessageFilter::OnRegister(int render_frame_id, - int callbacks_id, - const std::string& sender_id, - bool user_gesture, - int service_worker_provider_id) { +void PushMessagingMessageFilter::OnRegisterFromDocument( + int render_frame_id, + int request_id, + const std::string& sender_id, + bool user_gesture, + int service_worker_provider_id) { DCHECK_CURRENTLY_ON(BrowserThread::IO); // TODO(mvanouwerkerk): Validate arguments? ServiceWorkerProviderHost* service_worker_host = @@ -65,26 +72,47 @@ if (!service_worker_host || !service_worker_host->active_version()) { PushRegistrationStatus status = PUSH_REGISTRATION_STATUS_NO_SERVICE_WORKER; - Send(new PushMessagingMsg_RegisterError( - render_frame_id, - callbacks_id, - status)); + Send(new PushMessagingMsg_RegisterFromDocumentError(render_frame_id, + request_id, status)); RecordRegistrationStatus(status); return; } + + // TODO(mvanouwerkerk): Persist sender id in Service Worker storage. + // https://crbug.com/437298 + BrowserThread::PostTask( - BrowserThread::UI, - FROM_HERE, - base::Bind(&PushMessagingMessageFilter::DoRegister, - weak_factory_.GetWeakPtr(), - render_frame_id, - callbacks_id, - sender_id, - user_gesture, + BrowserThread::UI, FROM_HERE, + base::Bind(&PushMessagingMessageFilter::RegisterFromDocumentOnUI, + weak_factory_.GetWeakPtr(), render_frame_id, request_id, + sender_id, user_gesture, service_worker_host->active_version()->scope().GetOrigin(), service_worker_host->active_version()->registration_id())); } +void PushMessagingMessageFilter::OnRegisterFromWorker( + int request_id, + int64 service_worker_registration_id) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + ServiceWorkerRegistration* service_worker_registration = + service_worker_context_->context()->GetLiveRegistration( + service_worker_registration_id); + DCHECK(service_worker_registration); + if (!service_worker_registration) + return; + + // TODO(mvanouwerkerk): Get sender id from Service Worker storage. + // https://crbug.com/437298 + std::string sender_id = ""; + + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&PushMessagingMessageFilter::RegisterFromWorkerOnUI, + weak_factory_.GetWeakPtr(), request_id, sender_id, + service_worker_registration->pattern().GetOrigin(), + service_worker_registration_id)); +} + void PushMessagingMessageFilter::OnPermissionStatusRequest( int render_frame_id, int service_worker_provider_id, @@ -109,34 +137,65 @@ } } -void PushMessagingMessageFilter::DoRegister( +void PushMessagingMessageFilter::OnGetPermissionStatus( + int request_id, + int64 service_worker_registration_id) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + ServiceWorkerRegistration* service_worker_registration = + service_worker_context_->context()->GetLiveRegistration( + service_worker_registration_id); + DCHECK(service_worker_registration); + if (!service_worker_registration) + return; + + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&PushMessagingMessageFilter::GetPermissionStatusOnUI, + weak_factory_.GetWeakPtr(), + service_worker_registration->pattern().GetOrigin(), + request_id)); +} + +void PushMessagingMessageFilter::RegisterFromDocumentOnUI( int render_frame_id, - int callbacks_id, + int request_id, const std::string& sender_id, bool user_gesture, - const GURL& origin, + const GURL& requesting_origin, int64 service_worker_registration_id) { DCHECK_CURRENTLY_ON(BrowserThread::UI); if (!service()) { PushRegistrationStatus status = PUSH_REGISTRATION_STATUS_SERVICE_NOT_AVAILABLE; - Send(new PushMessagingMsg_RegisterError( - render_frame_id, - callbacks_id, - status)); + Send(new PushMessagingMsg_RegisterFromDocumentError(render_frame_id, + request_id, status)); RecordRegistrationStatus(status); return; } - service()->Register(origin, - service_worker_registration_id, - sender_id, - render_process_id_, - render_frame_id, - user_gesture, - base::Bind(&PushMessagingMessageFilter::DidRegister, - weak_factory_.GetWeakPtr(), - render_frame_id, - callbacks_id)); + service()->RegisterFromDocument( + requesting_origin, service_worker_registration_id, sender_id, + render_process_id_, render_frame_id, user_gesture, + base::Bind(&PushMessagingMessageFilter::DidRegisterFromDocument, + weak_factory_.GetWeakPtr(), render_frame_id, request_id)); +} + +void PushMessagingMessageFilter::RegisterFromWorkerOnUI( + int request_id, + const std::string& sender_id, + const GURL& requesting_origin, + int64 service_worker_registration_id) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + if (!service()) { + PushRegistrationStatus status = + PUSH_REGISTRATION_STATUS_SERVICE_NOT_AVAILABLE; + Send(new PushMessagingMsg_RegisterFromWorkerError(request_id, status)); + RecordRegistrationStatus(status); + return; + } + service()->RegisterFromWorker( + requesting_origin, service_worker_registration_id, sender_id, + base::Bind(&PushMessagingMessageFilter::DidRegisterFromWorker, + weak_factory_.GetWeakPtr(), request_id)); } void PushMessagingMessageFilter::DoPermissionStatusRequest( @@ -152,19 +211,45 @@ render_frame_id, callback_id, permission_value)); } -void PushMessagingMessageFilter::DidRegister( +void PushMessagingMessageFilter::GetPermissionStatusOnUI( + const GURL& requesting_origin, + int request_id) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + GURL embedding_origin = requesting_origin; + blink::WebPushPermissionStatus permission_status = + service()->GetPermissionStatus(requesting_origin, embedding_origin); + Send(new PushMessagingMsg_GetPermissionStatusSuccess(request_id, + permission_status)); +} + +void PushMessagingMessageFilter::DidRegisterFromDocument( int render_frame_id, - int callbacks_id, - const GURL& push_endpoint, + int request_id, const std::string& push_registration_id, PushRegistrationStatus status) { DCHECK_CURRENTLY_ON(BrowserThread::UI); if (status == PUSH_REGISTRATION_STATUS_SUCCESS) { - Send(new PushMessagingMsg_RegisterSuccess( - render_frame_id, callbacks_id, push_endpoint, push_registration_id)); + GURL push_endpoint(service()->PushEndpoint()); + Send(new PushMessagingMsg_RegisterFromDocumentSuccess( + render_frame_id, request_id, push_endpoint, push_registration_id)); } else { - Send(new PushMessagingMsg_RegisterError( - render_frame_id, callbacks_id, status)); + Send(new PushMessagingMsg_RegisterFromDocumentError(render_frame_id, + request_id, status)); + } + RecordRegistrationStatus(status); +} + +void PushMessagingMessageFilter::DidRegisterFromWorker( + int request_id, + const std::string& push_registration_id, + PushRegistrationStatus status) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + if (status == PUSH_REGISTRATION_STATUS_SUCCESS) { + GURL push_endpoint(service()->PushEndpoint()); + Send(new PushMessagingMsg_RegisterFromWorkerSuccess( + request_id, push_endpoint, push_registration_id)); + } else { + Send(new PushMessagingMsg_RegisterFromWorkerError(request_id, status)); } RecordRegistrationStatus(status); }
diff --git a/content/browser/push_messaging/push_messaging_message_filter.h b/content/browser/push_messaging/push_messaging_message_filter.h index 07b9a64..f981270 100644 --- a/content/browser/push_messaging/push_messaging_message_filter.h +++ b/content/browser/push_messaging/push_messaging_message_filter.h
@@ -32,32 +32,52 @@ // BrowserMessageFilter implementation. bool OnMessageReceived(const IPC::Message& message) override; - void OnRegister(int render_frame_id, - int callbacks_id, - const std::string& sender_id, - bool user_gesture, - int service_worker_provider_id); + void OnRegisterFromDocument(int render_frame_id, + int request_id, + const std::string& sender_id, + bool user_gesture, + int service_worker_provider_id); + void OnRegisterFromWorker(int request_id, + int64 service_worker_registration_id); + + // TODO(mvanouwerkerk): Delete once the Push API flows through platform. + // https://crbug.com/389194 void OnPermissionStatusRequest(int render_frame_id, int service_worker_provider_id, int permission_callback_id); - void DoRegister(int render_frame_id, - int callbacks_id, - const std::string& sender_id, - bool user_gesture, - const GURL& origin, - int64 service_worker_registration_id); + void OnGetPermissionStatus(int request_id, + int64 service_worker_registration_id); + void RegisterFromDocumentOnUI(int render_frame_id, + int request_id, + const std::string& sender_id, + bool user_gesture, + const GURL& requesting_origin, + int64 service_worker_registration_id); + + void RegisterFromWorkerOnUI(int request_id, + const std::string& sender_id, + const GURL& requesting_origin, + int64 service_worker_registration_id); + + // TODO(mvanouwerkerk): Delete once the Push API flows through platform. + // https://crbug.com/389194 void DoPermissionStatusRequest(const GURL& requesting_origin, int render_frame_id, int callback_id); - void DidRegister(int render_frame_id, - int callbacks_id, - const GURL& push_endpoint, - const std::string& push_registration_id, - PushRegistrationStatus status); + void GetPermissionStatusOnUI(const GURL& requesting_origin, int request_id); + + void DidRegisterFromDocument(int render_frame_id, + int request_id, + const std::string& push_registration_id, + PushRegistrationStatus status); + + void DidRegisterFromWorker(int request_id, + const std::string& push_registration_id, + PushRegistrationStatus status); PushMessagingService* service();
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc index 02fedcd..c1795f8 100644 --- a/content/browser/renderer_host/compositor_impl_android.cc +++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -81,11 +81,6 @@ } virtual void SwapBuffers(cc::CompositorFrame* frame) override { - for (size_t i = 0; i < frame->metadata.latency_info.size(); i++) { - frame->metadata.latency_info[i].AddLatencyNumber( - ui::INPUT_EVENT_BROWSER_SWAP_BUFFER_COMPONENT, 0, 0); - } - GetCommandBufferProxy()->SetLatencyInfo(frame->metadata.latency_info); DCHECK(frame->gl_frame_data->sub_buffer_rect == gfx::Rect(frame->gl_frame_data->size));
diff --git a/content/browser/renderer_host/input/input_router_impl_unittest.cc b/content/browser/renderer_host/input/input_router_impl_unittest.cc index 8cd679f..08562d3 100644 --- a/content/browser/renderer_host/input/input_router_impl_unittest.cc +++ b/content/browser/renderer_host/input/input_router_impl_unittest.cc
@@ -1628,7 +1628,7 @@ EXPECT_EQ(25, wheel_event->windowY); EXPECT_EQ(PinchScaleToWheelDelta(1.5), wheel_event->deltaY); EXPECT_EQ(0, wheel_event->deltaX); - EXPECT_EQ(1, wheel_event->hasPreciseScrollingDeltas); + EXPECT_TRUE(wheel_event->hasPreciseScrollingDeltas); EXPECT_EQ(1, wheel_event->wheelTicksY); EXPECT_EQ(0, wheel_event->wheelTicksX); EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); @@ -1651,7 +1651,7 @@ ASSERT_EQ(WebInputEvent::MouseWheel, input_event->type); wheel_event = static_cast<const WebMouseWheelEvent*>(input_event); EXPECT_FLOAT_EQ(PinchScaleToWheelDelta(0.3f), wheel_event->deltaY); - EXPECT_EQ(1, wheel_event->hasPreciseScrollingDeltas); + EXPECT_TRUE(wheel_event->hasPreciseScrollingDeltas); EXPECT_EQ(-1, wheel_event->wheelTicksY); EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
diff --git a/content/browser/renderer_host/input/touch_emulator_unittest.cc b/content/browser/renderer_host/input/touch_emulator_unittest.cc index 80eb51a..3c6aa96 100644 --- a/content/browser/renderer_host/input/touch_emulator_unittest.cc +++ b/content/browser/renderer_host/input/touch_emulator_unittest.cc
@@ -75,8 +75,8 @@ EXPECT_EQ(1U, event.touchesLength); EXPECT_EQ(last_mouse_x_, event.touches[0].position.x); EXPECT_EQ(last_mouse_y_, event.touches[0].position.y); - int expectedCancelable = event.type != WebInputEvent::TouchCancel; - EXPECT_EQ(expectedCancelable, event.cancelable); + bool expected_cancelable = event.type != WebInputEvent::TouchCancel; + EXPECT_EQ(expected_cancelable, !!event.cancelable); if (ack_touches_synchronously_) { emulator()->HandleTouchEventAck( event, INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
diff --git a/content/browser/renderer_host/p2p/socket_host_udp.cc b/content/browser/renderer_host/p2p/socket_host_udp.cc index 2988317..c545ac78 100644 --- a/content/browser/renderer_host/p2p/socket_host_udp.cc +++ b/content/browser/renderer_host/p2p/socket_host_udp.cc
@@ -77,7 +77,8 @@ net::NetLog::Source())), send_pending_(false), last_dscp_(net::DSCP_CS0), - throttler_(throttler) { + throttler_(throttler), + send_buffer_size_(0) { } P2PSocketHostUdp::~P2PSocketHostUdp() { @@ -98,6 +99,8 @@ if (!SetOption(P2P_SOCKET_OPT_SNDBUF, send_buffer_size)) { LOG(WARNING) << "Failed to set socket send buffer size to " << send_buffer_size; + } else { + send_buffer_size_ = send_buffer_size; } } } @@ -358,6 +361,11 @@ case P2P_SOCKET_OPT_RCVBUF: return socket_->SetReceiveBufferSize(value) == net::OK; case P2P_SOCKET_OPT_SNDBUF: + // Ignore any following call to set the send buffer size if we're under + // experiment. + if (send_buffer_size_ > 0) { + return true; + } return socket_->SetSendBufferSize(value) == net::OK; case P2P_SOCKET_OPT_DSCP: return (net::OK == socket_->SetDiffServCodePoint(
diff --git a/content/browser/renderer_host/p2p/socket_host_udp.h b/content/browser/renderer_host/p2p/socket_host_udp.h index f0b04a6..1839663 100644 --- a/content/browser/renderer_host/p2p/socket_host_udp.h +++ b/content/browser/renderer_host/p2p/socket_host_udp.h
@@ -86,6 +86,9 @@ ConnectedPeerSet connected_peers_; P2PMessageThrottler* throttler_; + // Keep track of the send socket buffer size under experiment. + size_t send_buffer_size_; + DISALLOW_COPY_AND_ASSIGN(P2PSocketHostUdp); };
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index 0c75bb8a..e683a1d 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1174,6 +1174,7 @@ switches::kEnableRendererMojoChannel, switches::kEnableSeccompFilterSandbox, switches::kEnableSkiaBenchmarking, + switches::kEnableSlimmingPaint, switches::kEnableSmoothScrolling, switches::kEnableStatsTable, switches::kEnableStrictSiteIsolation, @@ -1538,8 +1539,14 @@ // away first, since deleting the channel proxy will post a // OnChannelClosed() to IPC::ChannelProxy::Context on the IO thread. channel_.reset(); + + // The following members should be cleared in ProcessDied() as well! gpu_message_filter_ = NULL; message_port_message_filter_ = NULL; +#if defined(ENABLE_BROWSER_CDMS) + browser_cdm_manager_ = NULL; +#endif + RemoveUserData(kSessionStorageHolderKey); // Remove ourself from the list of renderer processes so that we can't be @@ -1940,7 +1947,7 @@ &exit_code) : base::TERMINATION_STATUS_NORMAL_TERMINATION; - RendererClosedDetails details(GetHandle(), status, exit_code); + RendererClosedDetails details(status, exit_code); mojo_application_host_->WillDestroySoon(); child_process_launcher_.reset(); @@ -1958,6 +1965,9 @@ gpu_message_filter_ = NULL; message_port_message_filter_ = NULL; +#if defined(ENABLE_BROWSER_CDMS) + browser_cdm_manager_ = NULL; +#endif RemoveUserData(kSessionStorageHolderKey); IDMap<IPC::Listener>::iterator iter(&listeners_);
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc index 5c47bac..bc26b3ac 100644 --- a/content/browser/renderer_host/render_view_host_impl.cc +++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -504,22 +504,11 @@ prefs.v8_cache_options = V8_CACHE_OPTIONS_DEFAULT; } - std::string streaming_experiment_group = - base::FieldTrialList::FindFullName("V8ScriptStreaming"); - prefs.v8_script_streaming_enabled = - command_line.HasSwitch(switches::kEnableV8ScriptStreaming); - if (streaming_experiment_group == "Enabled") { - prefs.v8_script_streaming_enabled = true; - prefs.v8_script_streaming_mode = V8_SCRIPT_STREAMING_MODE_ALL; - } else if (streaming_experiment_group == "OnlyAsyncAndDefer") { - prefs.v8_script_streaming_enabled = true; - prefs.v8_script_streaming_mode = - V8_SCRIPT_STREAMING_MODE_ONLY_ASYNC_AND_DEFER; - } else if (streaming_experiment_group == "AllPlusBlockParserBlocking") { - prefs.v8_script_streaming_enabled = true; - prefs.v8_script_streaming_mode = - V8_SCRIPT_STREAMING_MODE_ALL_PLUS_BLOCK_PARSER_BLOCKING; - } + // TODO(marja): Clean up preferences + command line flag after streaming has + // launched in stable. + prefs.v8_script_streaming_enabled = true; + prefs.v8_script_streaming_mode = + V8_SCRIPT_STREAMING_MODE_ONLY_ASYNC_AND_DEFER; GetContentClient()->browser()->OverrideWebkitPrefs(this, url, &prefs); return prefs; @@ -1466,14 +1455,24 @@ ChildProcessSecurityPolicyImpl::GetInstance(); const std::vector<base::FilePath>& file_paths = state.GetReferencedFiles(); - for (std::vector<base::FilePath>::const_iterator file = file_paths.begin(); - file != file_paths.end(); ++file) { - if (!policy->CanReadFile(GetProcess()->GetID(), *file)) + for (const auto& file : file_paths) { + if (!policy->CanReadFile(GetProcess()->GetID(), file)) return false; } return true; } +void RenderViewHostImpl::GrantFileAccessFromPageState(const PageState& state) { + ChildProcessSecurityPolicyImpl* policy = + ChildProcessSecurityPolicyImpl::GetInstance(); + + const std::vector<base::FilePath>& file_paths = state.GetReferencedFiles(); + for (const auto& file : file_paths) { + if (!policy->CanReadFile(GetProcess()->GetID(), file)) + policy->GrantReadFile(GetProcess()->GetID(), file); + } +} + void RenderViewHostImpl::AttachToFrameTree() { FrameTree* frame_tree = delegate_->GetFrameTree();
diff --git a/content/browser/renderer_host/render_view_host_impl.h b/content/browser/renderer_host/render_view_host_impl.h index c6fdf05..bb2013a 100644 --- a/content/browser/renderer_host/render_view_host_impl.h +++ b/content/browser/renderer_host/render_view_host_impl.h
@@ -388,8 +388,16 @@ // to fire. static const int64 kUnloadTimeoutMS; + // Returns whether the current RenderProcessHost has read access to the files + // reported in |state|. bool CanAccessFilesOfPageState(const PageState& state) const; + // Grants the current RenderProcessHost read access to any file listed in + // |validated_state|. It is important that the PageState has been validated + // upon receipt from the renderer process to prevent it from forging access to + // files without the user's consent. + void GrantFileAccessFromPageState(const PageState& validated_state); + // The number of RenderFrameHosts which have a reference to this RVH. int frames_ref_count_;
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc index 344032a..38a85f7b 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -89,10 +89,6 @@ bool g_check_for_pending_resize_ack = true; -const size_t kBrowserCompositeLatencyHistorySize = 60; -const double kBrowserCompositeLatencyEstimationPercentile = 90.0; -const double kBrowserCompositeLatencyEstimationSlack = 1.1; - typedef std::pair<int32, int32> RenderWidgetHostID; typedef base::hash_map<RenderWidgetHostID, RenderWidgetHostImpl*> RoutingIDWidgetMap; @@ -187,7 +183,6 @@ has_touch_handler_(false), last_input_number_(static_cast<int64>(GetProcess()->GetID()) << 32), next_browser_snapshot_id_(1), - browser_composite_latency_history_(kBrowserCompositeLatencyHistorySize), weak_factory_(this) { CHECK(delegate_); if (routing_id_ == MSG_ROUTING_NONE) { @@ -1527,11 +1522,6 @@ input_router_->OnViewUpdated( GetInputRouterViewFlagsFromCompositorFrameMetadata(frame->metadata)); - for (size_t i = 0; i < frame->metadata.latency_info.size(); ++i) { - frame->metadata.latency_info[i].AddLatencyNumber( - ui::INPUT_EVENT_BROWSER_COMPOSITE_COMPONENT, 0, 0); - } - if (view_) { view_->OnSwapCompositorFrame(output_surface_id, frame.Pass()); view_->DidReceiveRendererFrame(); @@ -2237,21 +2227,6 @@ 100); } } - - ui::LatencyInfo::LatencyComponent gpu_swap_component; - if (!latency_info.FindLatency( - ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, &gpu_swap_component)) { - return; - } - - ui::LatencyInfo::LatencyComponent composite_component; - if (latency_info.FindLatency(ui::INPUT_EVENT_BROWSER_COMPOSITE_COMPONENT, - 0, - &composite_component)) { - base::TimeDelta delta = - gpu_swap_component.event_time - composite_component.event_time; - browser_composite_latency_history_.InsertSample(delta); - } } void RenderWidgetHostImpl::DidReceiveRendererFrame() { @@ -2425,17 +2400,6 @@ delegate_->GetOrCreateRootBrowserAccessibilityManager() : NULL; } -base::TimeDelta RenderWidgetHostImpl::GetEstimatedBrowserCompositeTime() { - // TODO(orglofch) remove lower bound on estimate once we're sure it won't - // cause regressions - return std::max( - browser_composite_latency_history_.Percentile( - kBrowserCompositeLatencyEstimationPercentile) * - kBrowserCompositeLatencyEstimationSlack, - base::TimeDelta::FromMicroseconds( - (1.0f * base::Time::kMicrosecondsPerSecond) / (3.0f * 60))); -} - #if defined(OS_WIN) gfx::NativeViewAccessible RenderWidgetHostImpl::GetParentNativeViewAccessible() {
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h index 6ea591a..49d7568 100644 --- a/content/browser/renderer_host/render_widget_host_impl.h +++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -23,7 +23,6 @@ #include "base/time/time.h" #include "base/timer/timer.h" #include "build/build_config.h" -#include "cc/base/rolling_time_delta_history.h" #include "cc/resources/shared_bitmap.h" #include "content/browser/renderer_host/event_with_latency_info.h" #include "content/browser/renderer_host/input/input_ack_handler.h" @@ -481,8 +480,6 @@ // or create it if it doesn't already exist. BrowserAccessibilityManager* GetOrCreateRootBrowserAccessibilityManager(); - base::TimeDelta GetEstimatedBrowserCompositeTime(); - #if defined(OS_WIN) gfx::NativeViewAccessible GetParentNativeViewAccessible(); #endif @@ -850,8 +847,6 @@ base::Callback<void(const unsigned char*, size_t)> > PendingSnapshotMap; PendingSnapshotMap pending_browser_snapshots_; - cc::RollingTimeDeltaHistory browser_composite_latency_history_; - base::WeakPtrFactory<RenderWidgetHostImpl> weak_factory_; DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostImpl);
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc index 95a77be..b8ddefc 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.cc +++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -349,9 +349,7 @@ gesture_provider_(CreateGestureProviderConfig(), this), stylus_text_selector_(this), accelerated_surface_route_id_(0), - using_synchronous_compositor_(SynchronousCompositorImpl::FromID( - widget_host->GetProcess()->GetID(), - widget_host->GetRoutingID()) != NULL), + using_browser_compositor_(CompositorImpl::IsInitialized()), frame_evictor_(new DelegatedFrameEvictor(this)), locks_on_frame_count_(0), observing_root_window_(false), @@ -738,7 +736,7 @@ } void RenderWidgetHostViewAndroid::OnSetNeedsBeginFrames(bool enabled) { - DCHECK(!using_synchronous_compositor_); + DCHECK(using_browser_compositor_); TRACE_EVENT1("cc", "RenderWidgetHostViewAndroid::OnSetNeedsBeginFrames", "enabled", enabled); if (enabled) @@ -909,7 +907,7 @@ return; } base::TimeTicks start_time = base::TimeTicks::Now(); - if (!using_synchronous_compositor_ && !IsSurfaceAvailableForCopy()) { + if (using_browser_compositor_ && !IsSurfaceAvailableForCopy()) { callback.Run(SkBitmap(), READBACK_NOT_SUPPORTED); return; } @@ -921,7 +919,7 @@ gfx::Rect src_subrect_in_pixel = gfx::ConvertRectToPixel(device_scale_factor, src_subrect); - if (using_synchronous_compositor_) { + if (!using_browser_compositor_) { SynchronousCopyContents(src_subrect_in_pixel, dst_size_in_pixel, callback, color_type); UMA_HISTOGRAM_TIMES("Compositing.CopyFromSurfaceTimeSynchronous", @@ -1207,12 +1205,12 @@ bool RenderWidgetHostViewAndroid::SupportsAnimation() const { // The synchronous (WebView) compositor does not have a proper browser // compositor with which to drive animations. - return !using_synchronous_compositor_; + return using_browser_compositor_; } void RenderWidgetHostViewAndroid::SetNeedsAnimate() { DCHECK(content_view_core_); - DCHECK(!using_synchronous_compositor_); + DCHECK(using_browser_compositor_); content_view_core_->GetWindowAndroid()->SetNeedsAnimate(); } @@ -1248,7 +1246,7 @@ scoped_ptr<TouchHandleDrawable> RenderWidgetHostViewAndroid::CreateDrawable() { DCHECK(content_view_core_); - if (using_synchronous_compositor_) + if (!using_browser_compositor_) return content_view_core_->CreatePopupTouchHandleDrawable(); return scoped_ptr<TouchHandleDrawable>(new CompositedTouchHandleDrawable( @@ -1358,7 +1356,7 @@ void RenderWidgetHostViewAndroid::RequestVSyncUpdate(uint32 requests) { // The synchronous compositor does not requre BeginFrame messages. - if (using_synchronous_compositor_) + if (!using_browser_compositor_) requests &= FLUSH_INPUT; bool should_request_vsync = !outstanding_vsync_requests_ && requests; @@ -1403,13 +1401,17 @@ "frame_time_us", frame_time.ToInternalValue()); base::TimeTicks display_time = frame_time + vsync_period; - base::TimeTicks deadline = - display_time - host_->GetEstimatedBrowserCompositeTime(); + // TODO(brianderson): Use adaptive draw-time estimation. + base::TimeDelta estimated_browser_composite_time = + base::TimeDelta::FromMicroseconds( + (1.0f * base::Time::kMicrosecondsPerSecond) / (3.0f * 60)); + + base::TimeTicks deadline = display_time - estimated_browser_composite_time; host_->Send(new ViewMsg_BeginFrame( host_->GetRoutingID(), - cc::BeginFrameArgs::Create(frame_time, deadline, vsync_period, - cc::BeginFrameArgs::NORMAL))); + cc::BeginFrameArgs::Create(BEGINFRAME_FROM_HERE, frame_time, deadline, + vsync_period, cc::BeginFrameArgs::NORMAL))); } bool RenderWidgetHostViewAndroid::Animate(base::TimeTicks frame_time) { @@ -1452,7 +1454,7 @@ gfx::GLSurfaceHandle RenderWidgetHostViewAndroid::GetCompositingSurface() { gfx::GLSurfaceHandle handle = gfx::GLSurfaceHandle(gfx::kNullPluginWindow, gfx::NULL_TRANSPORT); - if (CompositorImpl::IsInitialized()) { + if (using_browser_compositor_) { handle.parent_client_id = BrowserGpuChannelHostFactory::instance()->GetGpuChannelId(); } @@ -1711,7 +1713,7 @@ void RenderWidgetHostViewAndroid::OnDetachCompositor() { DCHECK(content_view_core_); - DCHECK(!using_synchronous_compositor_); + DCHECK(using_browser_compositor_); RunAckCallbacks(); overscroll_controller_.reset(); }
diff --git a/content/browser/renderer_host/render_widget_host_view_android.h b/content/browser/renderer_host/render_widget_host_view_android.h index 886352f..a3ddc0f 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.h +++ b/content/browser/renderer_host/render_widget_host_view_android.h
@@ -388,7 +388,7 @@ // Size to use if we have no backing ContentViewCore gfx::Size default_size_; - const bool using_synchronous_compositor_; + const bool using_browser_compositor_; scoped_ptr<DelegatedFrameEvictor> frame_evictor_;
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.h b/content/browser/renderer_host/render_widget_host_view_mac.h index ff663dc..5efc7dbe 100644 --- a/content/browser/renderer_host/render_widget_host_view_mac.h +++ b/content/browser/renderer_host/render_widget_host_view_mac.h
@@ -17,10 +17,8 @@ #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "base/time/time.h" -#include "content/browser/compositor/browser_compositor_ca_layer_tree_mac.h" #include "content/browser/compositor/browser_compositor_view_mac.h" #include "content/browser/compositor/delegated_frame_host.h" -#include "content/browser/compositor/io_surface_layer_mac.h" #include "content/browser/renderer_host/display_link_mac.h" #include "content/browser/renderer_host/render_widget_host_view_base.h" #include "content/common/content_export.h" @@ -29,6 +27,8 @@ #import "content/public/browser/render_widget_host_view_mac_base.h" #include "ipc/ipc_sender.h" #include "third_party/WebKit/public/web/WebCompositionUnderline.h" +#include "ui/accelerated_widget_mac/accelerated_widget_mac.h" +#include "ui/accelerated_widget_mac/io_surface_layer.h" #include "ui/base/cocoa/base_view.h" #include "ui/base/cocoa/remote_layer_api.h" #include "ui/gfx/display_observer.h" @@ -204,7 +204,7 @@ class CONTENT_EXPORT RenderWidgetHostViewMac : public RenderWidgetHostViewBase, public DelegatedFrameHostClient, - public AcceleratedWidgetMacNSView, + public ui::AcceleratedWidgetMacNSView, public IPC::Sender, public gfx::DisplayObserver { public:
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm index 100d8b1..7f53735 100644 --- a/content/browser/renderer_host/render_widget_host_view_mac.mm +++ b/content/browser/renderer_host/render_widget_host_view_mac.mm
@@ -30,22 +30,19 @@ #include "content/browser/accessibility/browser_accessibility_manager_mac.h" #import "content/browser/cocoa/system_hotkey_helper_mac.h" #import "content/browser/cocoa/system_hotkey_map.h" -#include "content/browser/compositor/io_surface_layer_mac.h" #include "content/browser/compositor/resize_lock.h" -#include "content/browser/compositor/software_layer_mac.h" #include "content/browser/frame_host/frame_tree.h" #include "content/browser/frame_host/frame_tree_node.h" #include "content/browser/frame_host/render_frame_host_impl.h" #include "content/browser/gpu/compositor_util.h" -#include "content/browser/renderer_host/render_widget_helper.h" #include "content/browser/renderer_host/render_view_host_impl.h" +#include "content/browser/renderer_host/render_widget_helper.h" #import "content/browser/renderer_host/render_widget_host_view_mac_dictionary_helper.h" #import "content/browser/renderer_host/render_widget_host_view_mac_editcommand_helper.h" #import "content/browser/renderer_host/text_input_client_mac.h" #include "content/common/accessibility_messages.h" #include "content/common/edit_command.h" #include "content/common/gpu/gpu_messages.h" -#include "content/common/gpu/surface_handle_types_mac.h" #include "content/common/input_messages.h" #include "content/common/view_messages.h" #include "content/common/webplugin_geometry.h" @@ -63,13 +60,15 @@ #include "third_party/WebKit/public/web/WebInputEvent.h" #include "third_party/WebKit/public/web/mac/WebInputEventFactory.h" #import "third_party/mozilla/ComplexTextInputPanel.h" +#include "ui/accelerated_widget_mac/io_surface_layer.h" +#include "ui/accelerated_widget_mac/surface_handle_types.h" #include "ui/base/cocoa/animation_utils.h" #import "ui/base/cocoa/fullscreen_window_manager.h" #import "ui/base/cocoa/underlay_opengl_hosting_window.h" -#include "ui/events/keycodes/keyboard_codes.h" #include "ui/base/layout.h" #include "ui/compositor/compositor.h" #include "ui/compositor/layer.h" +#include "ui/events/keycodes/keyboard_codes.h" #include "ui/gfx/display.h" #include "ui/gfx/frame_time.h" #include "ui/gfx/geometry/dip_util.h"
diff --git a/content/browser/service_worker/service_worker_database.cc b/content/browser/service_worker/service_worker_database.cc index 61b8659..70bf33da 100644 --- a/content/browser/service_worker/service_worker_database.cc +++ b/content/browser/service_worker/service_worker_database.cc
@@ -4,8 +4,6 @@ #include "content/browser/service_worker/service_worker_database.h" -#include <string> - #include "base/files/file_util.h" #include "base/location.h" #include "base/logging.h" @@ -53,6 +51,11 @@ // (ex. "REG:http://example.com\x00123456") // value: <ServiceWorkerRegistrationData serialized as a string> // +// key: "REG_USER_DATA:" + <int64 'registration_id'> + '\x00' +// + <std::string user_data_name> +// (ex. "REG_USER_DATA:123456\x00foo_bar") +// value: <std::string user_data> +// // key: "RES:" + <int64 'version_id'> + '\x00' + <int64 'resource_id'> // (ex. "RES:123456\x00654321") // value: <ServiceWorkerResourceRecord serialized as a string> @@ -71,6 +74,7 @@ const char kUniqueOriginKey[] = "INITDATA_UNIQUE_ORIGIN:"; const char kRegKeyPrefix[] = "REG:"; +const char kRegUserDataKeyPrefix[] = "REG_USER_DATA:"; const char kResKeyPrefix[] = "RES:"; const char kKeySeparator = '\x00'; @@ -120,6 +124,18 @@ "%s%s", key_prefix, base::Int64ToString(resource_id).c_str()); } +std::string CreateUserDataKeyPrefix(int64 registration_id) { + return base::StringPrintf("%s%s%c", + kRegUserDataKeyPrefix, + base::Int64ToString(registration_id).c_str(), + kKeySeparator); +} + +std::string CreateUserDataKey(int64 registration_id, + const std::string& user_data_name) { + return CreateUserDataKeyPrefix(registration_id).append(user_data_name); +} + void PutRegistrationDataToBatch( const ServiceWorkerDatabase::RegistrationData& input, leveldb::WriteBatch* batch) { @@ -647,7 +663,7 @@ // Delete a registration specified by |registration_id|. batch.Delete(CreateRegistrationKey(registration_id, origin)); - // Delete resource records associated with the registration. + // Delete resource records and user data associated with the registration. for (const auto& registration : registrations) { if (registration.registration_id == registration_id) { *deleted_version = registration; @@ -655,6 +671,10 @@ registration.version_id, newly_purgeable_resources, &batch); if (status != STATUS_OK) return status; + + status = DeleteUserDataForRegistration(registration_id, &batch); + if (status != STATUS_OK) + return status; break; } } @@ -662,6 +682,69 @@ return WriteBatch(&batch); } +ServiceWorkerDatabase::Status ServiceWorkerDatabase::ReadUserData( + int64 registration_id, + const std::string& user_data_name, + std::string* user_data) { + DCHECK(sequence_checker_.CalledOnValidSequencedThread()); + DCHECK_NE(kInvalidServiceWorkerRegistrationId, registration_id); + DCHECK(!user_data_name.empty()); + DCHECK(user_data); + + Status status = LazyOpen(false); + if (IsNewOrNonexistentDatabase(status) || status != STATUS_OK) + return status; + + const std::string key = CreateUserDataKey(registration_id, user_data_name); + status = LevelDBStatusToStatus( + db_->Get(leveldb::ReadOptions(), key, user_data)); + HandleReadResult(FROM_HERE, + status == STATUS_ERROR_NOT_FOUND ? STATUS_OK : status); + return status; +} + +ServiceWorkerDatabase::Status ServiceWorkerDatabase::WriteUserData( + int64 registration_id, + const GURL& origin, + const std::string& user_data_name, + const std::string& user_data) { + DCHECK(sequence_checker_.CalledOnValidSequencedThread()); + DCHECK_NE(kInvalidServiceWorkerRegistrationId, registration_id); + DCHECK(!user_data_name.empty()); + + Status status = LazyOpen(false); + if (IsNewOrNonexistentDatabase(status) || status != STATUS_OK) + return status; + + // There should be the registration specified by |registration_id|. + RegistrationData registration; + status = ReadRegistrationData(registration_id, origin, ®istration); + if (status != STATUS_OK) + return status; + + leveldb::WriteBatch batch; + batch.Put(CreateUserDataKey(registration_id, user_data_name), user_data); + return WriteBatch(&batch); +} + +ServiceWorkerDatabase::Status ServiceWorkerDatabase::DeleteUserData( + int64 registration_id, + const std::string& user_data_name) { + DCHECK(sequence_checker_.CalledOnValidSequencedThread()); + DCHECK_NE(kInvalidServiceWorkerRegistrationId, registration_id); + DCHECK(!user_data_name.empty()); + + Status status = LazyOpen(false); + if (IsNewOrNonexistentDatabase(status)) + return STATUS_OK; + if (status != STATUS_OK) + return status; + + leveldb::WriteBatch batch; + batch.Delete(CreateUserDataKey(registration_id, user_data_name)); + return WriteBatch(&batch); +} + ServiceWorkerDatabase::Status ServiceWorkerDatabase::GetUncommittedResourceIds(std::set<int64>* ids) { return ReadResourceIds(kUncommittedResIdKeyPrefix, ids); @@ -729,13 +812,18 @@ if (status != STATUS_OK) return status; - // Delete registrations and resource records. + // Delete registrations, resource records and user data. for (const RegistrationData& data : registrations) { batch.Delete(CreateRegistrationKey(data.registration_id, origin)); + status = DeleteResourceRecords( data.version_id, newly_purgeable_resources, &batch); if (status != STATUS_OK) return status; + + status = DeleteUserDataForRegistration(data.registration_id, &batch); + if (status != STATUS_OK) + return status; } } @@ -1044,6 +1132,30 @@ return STATUS_OK; } +ServiceWorkerDatabase::Status +ServiceWorkerDatabase::DeleteUserDataForRegistration( + int64 registration_id, + leveldb::WriteBatch* batch) { + DCHECK(batch); + Status status = STATUS_OK; + const std::string prefix = CreateUserDataKeyPrefix(registration_id); + + scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions())); + for (itr->Seek(prefix); itr->Valid(); itr->Next()) { + status = LevelDBStatusToStatus(itr->status()); + if (status != STATUS_OK) { + HandleReadResult(FROM_HERE, status); + return status; + } + + const std::string key = itr->key().ToString(); + if (!RemovePrefix(key, prefix, nullptr)) + break; + batch->Delete(key); + } + return status; +} + ServiceWorkerDatabase::Status ServiceWorkerDatabase::ReadDatabaseVersion( int64* db_version) { std::string value;
diff --git a/content/browser/service_worker/service_worker_database.h b/content/browser/service_worker/service_worker_database.h index 96283c9..b57647a 100644 --- a/content/browser/service_worker/service_worker_database.h +++ b/content/browser/service_worker/service_worker_database.h
@@ -7,6 +7,7 @@ #include <map> #include <set> +#include <string> #include <vector> #include "base/files/file_path.h" @@ -158,6 +159,25 @@ RegistrationData* deleted_version, std::vector<int64>* newly_purgeable_resources); + // Reads user data for |registration_id| and |user_data_name| from the + // database. + Status ReadUserData(int64 registration_id, + const std::string& user_data_name, + std::string* user_data); + + // Writes |user_data| into the database. Returns NOT_FOUND if the registration + // specified by |registration_id| does not exist in the database. + Status WriteUserData(int64 registration_id, + const GURL& origin, + const std::string& user_data_name, + const std::string& user_data); + + // Deletes user data for |registration_id| and |user_data_name| from the + // database. Returns OK if it's successfully deleted or not found in the + // database. + Status DeleteUserData(int64 registration_id, + const std::string& user_data_name); + // As new resources are put into the diskcache, they go into an uncommitted // list. When a registration is saved that refers to those ids, they're // removed from that list. When a resource no longer has any registrations or @@ -273,6 +293,12 @@ const std::set<int64>& ids, leveldb::WriteBatch* batch); + // Deletes all user data for |registration_id| from the database. Returns OK + // if they are successfully deleted or not found in the database. + Status DeleteUserDataForRegistration( + int64 registration_id, + leveldb::WriteBatch* batch); + // Reads the current schema version from the database. If the database hasn't // been written anything yet, sets |db_version| to 0 and returns OK. Status ReadDatabaseVersion(int64* db_version);
diff --git a/content/browser/service_worker/service_worker_database_unittest.cc b/content/browser/service_worker/service_worker_database_unittest.cc index 0e052f5..9816ce3 100644 --- a/content/browser/service_worker/service_worker_database_unittest.cc +++ b/content/browser/service_worker/service_worker_database_unittest.cc
@@ -741,6 +741,225 @@ VerifyResourceRecords(resources2, resources_out); } +TEST(ServiceWorkerDatabaseTest, UserData_Basic) { + scoped_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory()); + const GURL kOrigin("http://example.com"); + + // Should be failed because the database does not exist. + std::string user_data_out; + EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, + database->WriteUserData(100, kOrigin, "key1", "data")); + EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, + database->ReadUserData(100, "key1", &user_data_out)); + EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, + database->DeleteUserData(100, "key1")); + + // Add a registration. + RegistrationData data; + data.registration_id = 100; + data.scope = URL(kOrigin, "/foo"); + data.script = URL(kOrigin, "/script.js"); + data.version_id = 200; + + std::vector<Resource> resources; + ServiceWorkerDatabase::RegistrationData deleted_version; + std::vector<int64> newly_purgeable_resources; + ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, + database->WriteRegistration( + data, resources, &deleted_version, &newly_purgeable_resources)); + + // Write user data associated with the stored registration. + EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, + database->WriteUserData( + data.registration_id, kOrigin, "key1", "data")); + EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, + database->ReadUserData( + data.registration_id, "key1", &user_data_out)); + EXPECT_EQ("data", user_data_out); + + // Writing user data not associated with the stored registration should be + // failed. + EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, + database->WriteUserData(300, kOrigin, "key1", "data")); + + // Write empty user data for a different key. + EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, + database->WriteUserData( + data.registration_id, kOrigin, "key2", std::string())); + EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, + database->ReadUserData( + data.registration_id, "key2", &user_data_out)); + EXPECT_EQ(std::string(), user_data_out); + EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, + database->ReadUserData( + data.registration_id, "key1", &user_data_out)); + EXPECT_EQ("data", user_data_out); + + // Overwrite the existing user data. + EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, + database->WriteUserData( + data.registration_id, kOrigin, "key1", "overwrite")); + EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, + database->ReadUserData( + data.registration_id, "key1", &user_data_out)); + EXPECT_EQ("overwrite", user_data_out); + + // Delete the user data. + EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, + database->DeleteUserData(data.registration_id, "key1")); + EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, + database->ReadUserData( + data.registration_id, "key1", &user_data_out)); + EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, + database->ReadUserData( + data.registration_id, "key2", &user_data_out)); + EXPECT_EQ(std::string(), user_data_out); +} + +TEST(ServiceWorkerDatabaseTest, UserData_DataIsolation) { + scoped_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory()); + const GURL kOrigin("http://example.com"); + + // Add registration 1. + RegistrationData data1; + data1.registration_id = 100; + data1.scope = URL(kOrigin, "/foo"); + data1.script = URL(kOrigin, "/script1.js"); + data1.version_id = 200; + + // Add registration 2. + RegistrationData data2; + data2.registration_id = 101; + data2.scope = URL(kOrigin, "/bar"); + data2.script = URL(kOrigin, "/script2.js"); + data2.version_id = 201; + + std::vector<Resource> resources; + ServiceWorkerDatabase::RegistrationData deleted_version; + std::vector<int64> newly_purgeable_resources; + ASSERT_EQ( + ServiceWorkerDatabase::STATUS_OK, + database->WriteRegistration( + data1, resources, &deleted_version, &newly_purgeable_resources)); + ASSERT_EQ( + ServiceWorkerDatabase::STATUS_OK, + database->WriteRegistration( + data2, resources, &deleted_version, &newly_purgeable_resources)); + + // Write user data associated with the registration1. + std::string user_data_out; + ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, + database->WriteUserData( + data1.registration_id, kOrigin, "key", "data1")); + EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, + database->ReadUserData( + data1.registration_id, "key", &user_data_out)); + EXPECT_EQ("data1", user_data_out); + EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, + database->ReadUserData( + data2.registration_id, "key", &user_data_out)); + + // Write user data associated with the registration2. This shouldn't overwrite + // the data associated with registration1. + ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, + database->WriteUserData( + data2.registration_id, kOrigin, "key", "data2")); + EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, + database->ReadUserData( + data1.registration_id, "key", &user_data_out)); + EXPECT_EQ("data1", user_data_out); + EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, + database->ReadUserData( + data2.registration_id, "key", &user_data_out)); + EXPECT_EQ("data2", user_data_out); + + // Delete the data associated with the registration2. This shouldn't delete + // the data associated with registration1. + ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, + database->DeleteUserData(data2.registration_id, "key")); + EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, + database->ReadUserData( + data1.registration_id, "key", &user_data_out)); + EXPECT_EQ("data1", user_data_out); + EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, + database->ReadUserData( + data2.registration_id, "key", &user_data_out)); +} + +TEST(ServiceWorkerDatabaseTest, UserData_DeleteRegistration) { + scoped_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory()); + const GURL kOrigin("http://example.com"); + + // Add registration 1. + RegistrationData data1; + data1.registration_id = 100; + data1.scope = URL(kOrigin, "/foo"); + data1.script = URL(kOrigin, "/script1.js"); + data1.version_id = 200; + + // Add registration 2. + RegistrationData data2; + data2.registration_id = 101; + data2.scope = URL(kOrigin, "/bar"); + data2.script = URL(kOrigin, "/script2.js"); + data2.version_id = 201; + + std::vector<Resource> resources; + ServiceWorkerDatabase::RegistrationData deleted_version; + std::vector<int64> newly_purgeable_resources; + ASSERT_EQ( + ServiceWorkerDatabase::STATUS_OK, + database->WriteRegistration( + data1, resources, &deleted_version, &newly_purgeable_resources)); + ASSERT_EQ( + ServiceWorkerDatabase::STATUS_OK, + database->WriteRegistration( + data2, resources, &deleted_version, &newly_purgeable_resources)); + + // Write user data associated with the registration1. + std::string user_data_out; + ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, + database->WriteUserData( + data1.registration_id, kOrigin, "key1", "data1")); + ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, + database->WriteUserData( + data1.registration_id, kOrigin, "key2", "data2")); + ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, + database->ReadUserData( + data1.registration_id, "key1", &user_data_out)); + ASSERT_EQ("data1", user_data_out); + ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, + database->ReadUserData( + data1.registration_id, "key2", &user_data_out)); + ASSERT_EQ("data2", user_data_out); + + // Write user data associated with the registration2. + ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, + database->WriteUserData( + data2.registration_id, kOrigin, "key3", "data3")); + ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, + database->ReadUserData( + data2.registration_id, "key3", &user_data_out)); + ASSERT_EQ("data3", user_data_out); + + // Delete all data associated with the registration1. This shouldn't delete + // the data associated with registration2. + ASSERT_EQ(ServiceWorkerDatabase::STATUS_OK, + database->DeleteRegistration( + data1.registration_id, kOrigin, + &deleted_version, &newly_purgeable_resources)); + EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, + database->ReadUserData( + data1.registration_id, "key1", &user_data_out)); + EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, + database->ReadUserData( + data1.registration_id, "key2", &user_data_out)); + EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, + database->ReadUserData( + data2.registration_id, "key3", &user_data_out)); + EXPECT_EQ("data3", user_data_out); +} + TEST(ServiceWorkerDatabaseTest, UpdateVersionToActive) { scoped_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory()); GURL origin("http://example.com"); @@ -958,7 +1177,7 @@ GURL origin1("http://example.com"); GURL origin2("http://example.org"); - // |origin1| has two registrations. + // |origin1| has two registrations (registration1 and registration2). RegistrationData data1; data1.registration_id = 10; data1.scope = URL(origin1, "/foo"); @@ -973,6 +1192,14 @@ ServiceWorkerDatabase::STATUS_OK, database->WriteRegistration( data1, resources1, &deleted_version, &newly_purgeable_resources)); + ASSERT_EQ( + ServiceWorkerDatabase::STATUS_OK, + database->WriteUserData( + data1.registration_id, origin1, "key1", "data1")); + ASSERT_EQ( + ServiceWorkerDatabase::STATUS_OK, + database->WriteUserData( + data1.registration_id, origin1, "key2", "data2")); RegistrationData data2; data2.registration_id = 11; @@ -988,8 +1215,16 @@ ServiceWorkerDatabase::STATUS_OK, database->WriteRegistration( data2, resources2, &deleted_version, &newly_purgeable_resources)); + ASSERT_EQ( + ServiceWorkerDatabase::STATUS_OK, + database->WriteUserData( + data2.registration_id, origin1, "key3", "data3")); + ASSERT_EQ( + ServiceWorkerDatabase::STATUS_OK, + database->WriteUserData( + data2.registration_id, origin1, "key4", "data4")); - // |origin2| has one registration. + // |origin2| has one registration (registration3). RegistrationData data3; data3.registration_id = 12; data3.scope = URL(origin2, "/hoge"); @@ -1004,6 +1239,14 @@ ServiceWorkerDatabase::STATUS_OK, database->WriteRegistration( data3, resources3, &deleted_version, &newly_purgeable_resources)); + ASSERT_EQ( + ServiceWorkerDatabase::STATUS_OK, + database->WriteUserData( + data3.registration_id, origin2, "key5", "data5")); + ASSERT_EQ( + ServiceWorkerDatabase::STATUS_OK, + database->WriteUserData( + data3.registration_id, origin2, "key6", "data6")); std::set<GURL> origins_to_delete; origins_to_delete.insert(origin1); @@ -1041,6 +1284,31 @@ EXPECT_TRUE(ContainsKey(purgeable_ids_out, 2)); EXPECT_TRUE(ContainsKey(purgeable_ids_out, 3)); EXPECT_TRUE(ContainsKey(purgeable_ids_out, 4)); + + // The user data associated with |origin1| should be removed. + std::string user_data_out; + EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, + database->ReadUserData( + data1.registration_id, "key1", &user_data_out)); + EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, + database->ReadUserData( + data1.registration_id, "key2", &user_data_out)); + EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, + database->ReadUserData( + data2.registration_id, "key3", &user_data_out)); + EXPECT_EQ(ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND, + database->ReadUserData( + data2.registration_id, "key4", &user_data_out)); + + // The user data associated with |origin2| should not be removed. + EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, + database->ReadUserData( + data3.registration_id, "key5", &user_data_out)); + EXPECT_EQ("data5", user_data_out); + EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK, + database->ReadUserData( + data3.registration_id, "key6", &user_data_out)); + EXPECT_EQ("data6", user_data_out); } TEST(ServiceWorkerDatabaseTest, DestroyDatabase) {
diff --git a/content/browser/service_worker/service_worker_registration.cc b/content/browser/service_worker/service_worker_registration.cc index 0445f08..c4d8d6a 100644 --- a/content/browser/service_worker/service_worker_registration.cc +++ b/content/browser/service_worker/service_worker_registration.cc
@@ -197,6 +197,29 @@ most_recent_version)); } +void ServiceWorkerRegistration::GetUserData( + const std::string& key, + const GetUserDataCallback& callback) { + DCHECK(context_); + context_->storage()->GetUserData(registration_id_, key, callback); +} + +void ServiceWorkerRegistration::StoreUserData( + const std::string& key, + const std::string& data, + const StatusCallback& callback) { + DCHECK(context_); + context_->storage()->StoreUserData( + registration_id_, pattern().GetOrigin(), key, data, callback); +} + +void ServiceWorkerRegistration::ClearUserData( + const std::string& key, + const StatusCallback& callback) { + DCHECK(context_); + context_->storage()->ClearUserData(registration_id_, key, callback); +} + void ServiceWorkerRegistration::OnNoControllees(ServiceWorkerVersion* version) { DCHECK_EQ(active_version(), version); if (is_uninstalling_)
diff --git a/content/browser/service_worker/service_worker_registration.h b/content/browser/service_worker/service_worker_registration.h index b386eec..3aee44b 100644 --- a/content/browser/service_worker/service_worker_registration.h +++ b/content/browser/service_worker/service_worker_registration.h
@@ -5,6 +5,8 @@ #ifndef CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_REGISTRATION_H_ #define CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_REGISTRATION_H_ +#include <string> + #include "base/basictypes.h" #include "base/gtest_prod_util.h" #include "base/logging.h" @@ -28,6 +30,9 @@ public ServiceWorkerVersion::Listener { public: typedef base::Callback<void(ServiceWorkerStatusCode status)> StatusCallback; + typedef base::Callback<void( + const std::string& data, + ServiceWorkerStatusCode status)> GetUserDataCallback; class Listener { public: @@ -115,6 +120,17 @@ base::Time last_update_check() const { return last_update_check_; } void set_last_update_check(base::Time last) { last_update_check_ = last; } + // Provide a storage mechanism to read/write arbitrary data associated with + // this registration in the storage. Stored data is deleted when this + // registration is deleted from the storage. + void GetUserData(const std::string& key, + const GetUserDataCallback& callback); + void StoreUserData(const std::string& key, + const std::string& data, + const StatusCallback& callback); + void ClearUserData(const std::string& key, + const StatusCallback& callback); + private: friend class base::RefCounted<ServiceWorkerRegistration>;
diff --git a/content/browser/service_worker/service_worker_storage.cc b/content/browser/service_worker/service_worker_storage.cc index 0a06823..038afbe 100644 --- a/content/browser/service_worker/service_worker_storage.cc +++ b/content/browser/service_worker/service_worker_storage.cc
@@ -4,8 +4,6 @@ #include "content/browser/service_worker/service_worker_storage.h" -#include <string> - #include "base/bind_helpers.h" #include "base/debug/trace_event.h" #include "base/files/file_util.h" @@ -615,6 +613,88 @@ comparer->Start(); // It deletes itself when done. } +void ServiceWorkerStorage::StoreUserData( + int64 registration_id, + const GURL& origin, + const std::string& key, + const std::string& data, + const StatusCallback& callback) { + DCHECK(state_ == INITIALIZED || state_ == DISABLED) << state_; + if (IsDisabled() || !context_) { + RunSoon(FROM_HERE, base::Bind(callback, SERVICE_WORKER_ERROR_FAILED)); + return; + } + + if (registration_id == kInvalidServiceWorkerRegistrationId || key.empty()) { + RunSoon(FROM_HERE, base::Bind(callback, SERVICE_WORKER_ERROR_FAILED)); + return; + } + + PostTaskAndReplyWithResult( + database_task_manager_->GetTaskRunner(), + FROM_HERE, + base::Bind(&ServiceWorkerDatabase::WriteUserData, + base::Unretained(database_.get()), + registration_id, origin, key, data), + base::Bind(&ServiceWorkerStorage::DidStoreUserData, + weak_factory_.GetWeakPtr(), + callback)); +} + +void ServiceWorkerStorage::GetUserData( + int64 registration_id, + const std::string& key, + const GetUserDataCallback& callback) { + DCHECK(state_ == INITIALIZED || state_ == DISABLED) << state_; + if (IsDisabled() || !context_) { + RunSoon(FROM_HERE, + base::Bind(callback, std::string(), SERVICE_WORKER_ERROR_FAILED)); + return; + } + + if (registration_id == kInvalidServiceWorkerRegistrationId || key.empty()) { + RunSoon(FROM_HERE, + base::Bind(callback, std::string(), SERVICE_WORKER_ERROR_FAILED)); + return; + } + + database_task_manager_->GetTaskRunner()->PostTask( + FROM_HERE, + base::Bind(&ServiceWorkerStorage::GetUserDataInDB, + database_.get(), + base::MessageLoopProxy::current(), + registration_id, + key, + base::Bind(&ServiceWorkerStorage::DidGetUserData, + weak_factory_.GetWeakPtr(), callback))); +} + +void ServiceWorkerStorage::ClearUserData( + int64 registration_id, + const std::string& key, + const StatusCallback& callback) { + DCHECK(state_ == INITIALIZED || state_ == DISABLED) << state_; + if (IsDisabled() || !context_) { + RunSoon(FROM_HERE, base::Bind(callback, SERVICE_WORKER_ERROR_FAILED)); + return; + } + + if (registration_id == kInvalidServiceWorkerRegistrationId || key.empty()) { + RunSoon(FROM_HERE, base::Bind(callback, SERVICE_WORKER_ERROR_FAILED)); + return; + } + + PostTaskAndReplyWithResult( + database_task_manager_->GetTaskRunner(), + FROM_HERE, + base::Bind(&ServiceWorkerDatabase::DeleteUserData, + base::Unretained(database_.get()), + registration_id, key), + base::Bind(&ServiceWorkerStorage::DidDeleteUserData, + weak_factory_.GetWeakPtr(), + callback)); +} + void ServiceWorkerStorage::DeleteAndStartOver(const StatusCallback& callback) { Disable(); @@ -1039,6 +1119,38 @@ StartPurgingResources(newly_purgeable_resources); } +void ServiceWorkerStorage::DidStoreUserData( + const StatusCallback& callback, + ServiceWorkerDatabase::Status status) { + // |status| can be NOT_FOUND when the associated registration did not exist in + // the database. In the case, we don't have to schedule the corruption + // recovery. + if (status != ServiceWorkerDatabase::STATUS_OK && + status != ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND) { + ScheduleDeleteAndStartOver(); + } + callback.Run(DatabaseStatusToStatusCode(status)); +} + +void ServiceWorkerStorage::DidGetUserData( + const GetUserDataCallback& callback, + const std::string& data, + ServiceWorkerDatabase::Status status) { + if (status != ServiceWorkerDatabase::STATUS_OK && + status != ServiceWorkerDatabase::STATUS_ERROR_NOT_FOUND) { + ScheduleDeleteAndStartOver(); + } + callback.Run(data, DatabaseStatusToStatusCode(status)); +} + +void ServiceWorkerStorage::DidDeleteUserData( + const StatusCallback& callback, + ServiceWorkerDatabase::Status status) { + if (status != ServiceWorkerDatabase::STATUS_OK) + ScheduleDeleteAndStartOver(); + callback.Run(DatabaseStatusToStatusCode(status)); +} + scoped_refptr<ServiceWorkerRegistration> ServiceWorkerStorage::GetOrCreateRegistration( const ServiceWorkerDatabase::RegistrationData& data, @@ -1452,6 +1564,19 @@ FROM_HERE, base::Bind(callback, data, resources, status)); } +void ServiceWorkerStorage::GetUserDataInDB( + ServiceWorkerDatabase* database, + scoped_refptr<base::SequencedTaskRunner> original_task_runner, + int64 registration_id, + const std::string& key, + const GetUserDataInDBCallback& callback) { + std::string data; + ServiceWorkerDatabase::Status status = + database->ReadUserData(registration_id, key, &data); + original_task_runner->PostTask( + FROM_HERE, base::Bind(callback, data, status)); +} + void ServiceWorkerStorage::DeleteAllDataForOriginsFromDB( ServiceWorkerDatabase* database, const std::set<GURL>& origins) {
diff --git a/content/browser/service_worker/service_worker_storage.h b/content/browser/service_worker/service_worker_storage.h index 0eda8bf5..83ec670 100644 --- a/content/browser/service_worker/service_worker_storage.h +++ b/content/browser/service_worker/service_worker_storage.h
@@ -8,6 +8,7 @@ #include <deque> #include <map> #include <set> +#include <string> #include <vector> #include "base/bind.h" @@ -57,6 +58,9 @@ typedef base::Callback< void(ServiceWorkerStatusCode status, bool are_equal)> CompareCallback; + typedef base::Callback< + void(const std::string& data, ServiceWorkerStatusCode status)> + GetUserDataCallback; ~ServiceWorkerStorage() override; @@ -136,6 +140,21 @@ void CompareScriptResources(int64 lhs_id, int64 rhs_id, const CompareCallback& callback); + // Provide a storage mechanism to read/write arbitrary data associated with + // a registration. Each registration has its own key namespace. Stored data + // is deleted when the associated registraton is deleted. + void GetUserData(int64 registration_id, + const std::string& key, + const GetUserDataCallback& callback); + void StoreUserData(int64 registration_id, + const GURL& origin, + const std::string& key, + const std::string& data, + const StatusCallback& callback); + void ClearUserData(int64 registration_id, + const std::string& key, + const StatusCallback& callback); + // Deletes the storage and starts over. void DeleteAndStartOver(const StatusCallback& callback); @@ -163,6 +182,7 @@ void PurgeResources(const ResourceList& resources); private: + friend class ServiceWorkerStorageTest; friend class ServiceWorkerResourceStorageTest; friend class ServiceWorkerControlleeRequestHandlerTest; friend class ServiceWorkerContextRequestHandlerTest; @@ -221,6 +241,9 @@ const ServiceWorkerDatabase::RegistrationData& data, const ResourceList& resources, ServiceWorkerDatabase::Status status)> FindInDBCallback; + typedef base::Callback<void( + const std::string& data, + ServiceWorkerDatabase::Status)> GetUserDataInDBCallback; typedef base::Callback<void(const std::vector<int64>& resource_ids, ServiceWorkerDatabase::Status status)> GetResourcesCallback; @@ -279,6 +302,16 @@ const ServiceWorkerDatabase::RegistrationData& deleted_version, const std::vector<int64>& newly_purgeable_resources, ServiceWorkerDatabase::Status status); + void DidStoreUserData( + const StatusCallback& callback, + ServiceWorkerDatabase::Status status); + void DidGetUserData( + const GetUserDataCallback& callback, + const std::string& data, + ServiceWorkerDatabase::Status status); + void DidDeleteUserData( + const StatusCallback& callback, + ServiceWorkerDatabase::Status status); void ReturnFoundRegistration( const FindRegistrationCallback& callback, const ServiceWorkerDatabase::RegistrationData& data, @@ -350,6 +383,12 @@ int64 registration_id, const GURL& origin, const FindInDBCallback& callback); + static void GetUserDataInDB( + ServiceWorkerDatabase* database, + scoped_refptr<base::SequencedTaskRunner> original_task_runner, + int64 registration_id, + const std::string& key, + const GetUserDataInDBCallback& callback); static void DeleteAllDataForOriginsFromDB( ServiceWorkerDatabase* database, const std::set<GURL>& origins);
diff --git a/content/browser/service_worker/service_worker_storage_unittest.cc b/content/browser/service_worker/service_worker_storage_unittest.cc index e98b83d..088de2d 100644 --- a/content/browser/service_worker/service_worker_storage_unittest.cc +++ b/content/browser/service_worker/service_worker_storage_unittest.cc
@@ -79,6 +79,17 @@ return base::Bind(&GetAllCallback, was_called, all); } +void GetUserDataCallback( + bool* was_called, + std::string* data_out, + ServiceWorkerStatusCode* status_out, + const std::string& data, + ServiceWorkerStatusCode status) { + *was_called = true; + *data_out = data; + *status_out = status; +} + void OnCompareComplete( ServiceWorkerStatusCode* status_out, bool* are_equal_out, ServiceWorkerStatusCode status, bool are_equal) { @@ -225,6 +236,11 @@ } protected: + void LazyInitialize() { + storage()->LazyInitialize(base::Bind(&base::DoNothing)); + base::RunLoop().RunUntilIdle(); + } + ServiceWorkerStatusCode StoreRegistration( scoped_refptr<ServiceWorkerRegistration> registration, scoped_refptr<ServiceWorkerVersion> version) { @@ -262,6 +278,50 @@ EXPECT_TRUE(was_called); } + ServiceWorkerStatusCode GetUserData( + int64 registration_id, + const std::string& key, + std::string* data) { + bool was_called = false; + ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED; + storage()->GetUserData( + registration_id, key, + base::Bind(&GetUserDataCallback, &was_called, data, &result)); + EXPECT_FALSE(was_called); // always async + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(was_called); + return result; + } + + ServiceWorkerStatusCode StoreUserData( + int64 registration_id, + const GURL& origin, + const std::string& key, + const std::string& data) { + bool was_called = false; + ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED; + storage()->StoreUserData( + registration_id, origin, key, data, + MakeStatusCallback(&was_called, &result)); + EXPECT_FALSE(was_called); // always async + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(was_called); + return result; + } + + ServiceWorkerStatusCode ClearUserData( + int64 registration_id, + const std::string& key) { + bool was_called = false; + ServiceWorkerStatusCode result = SERVICE_WORKER_ERROR_FAILED; + storage()->ClearUserData( + registration_id, key, MakeStatusCallback(&was_called, &result)); + EXPECT_FALSE(was_called); // always async + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(was_called); + return result; + } + ServiceWorkerStatusCode UpdateToActiveState( scoped_refptr<ServiceWorkerRegistration> registration) { bool was_called = false; @@ -568,6 +628,69 @@ EXPECT_TRUE(all_registrations.empty()); } +TEST_F(ServiceWorkerStorageTest, StoreUserData) { + const GURL kScope("http://www.test.not/scope/"); + const GURL kScript("http://www.test.not/script.js"); + const int64 kRegistrationId = 0; + const int64 kVersionId = 0; + + LazyInitialize(); + + // Store a registration. + scoped_refptr<ServiceWorkerRegistration> live_registration = + new ServiceWorkerRegistration( + kScope, kRegistrationId, context_ptr_); + scoped_refptr<ServiceWorkerVersion> live_version = + new ServiceWorkerVersion( + live_registration.get(), kScript, kVersionId, context_ptr_); + live_version->SetStatus(ServiceWorkerVersion::INSTALLED); + live_registration->SetWaitingVersion(live_version.get()); + EXPECT_EQ(SERVICE_WORKER_OK, + StoreRegistration(live_registration, live_version)); + + // Store user data associated with the registration. + std::string data_out; + EXPECT_EQ(SERVICE_WORKER_OK, + StoreUserData(kRegistrationId, kScope.GetOrigin(), "key", "data")); + EXPECT_EQ(SERVICE_WORKER_OK, GetUserData(kRegistrationId, "key", &data_out)); + EXPECT_EQ("data", data_out); + EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND, + GetUserData(kRegistrationId, "unknown_key", &data_out)); + EXPECT_EQ(SERVICE_WORKER_OK, ClearUserData(kRegistrationId, "key")); + EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND, + GetUserData(kRegistrationId, "key", &data_out)); + + // User data should be deleted when the associated registration is deleted. + ASSERT_EQ(SERVICE_WORKER_OK, + StoreUserData(kRegistrationId, kScope.GetOrigin(), "key", "data")); + ASSERT_EQ(SERVICE_WORKER_OK, + GetUserData(kRegistrationId, "key", &data_out)); + ASSERT_EQ("data", data_out); + + EXPECT_EQ(SERVICE_WORKER_OK, + DeleteRegistration(kRegistrationId, kScope.GetOrigin())); + EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND, + GetUserData(kRegistrationId, "key", &data_out)); + + // Data access with an invalid registration id should be failed. + EXPECT_EQ(SERVICE_WORKER_ERROR_FAILED, + StoreUserData(kInvalidServiceWorkerRegistrationId, + kScope.GetOrigin(), "key", "data")); + EXPECT_EQ(SERVICE_WORKER_ERROR_FAILED, + GetUserData(kInvalidServiceWorkerRegistrationId, "key", &data_out)); + EXPECT_EQ(SERVICE_WORKER_ERROR_FAILED, + ClearUserData(kInvalidServiceWorkerRegistrationId, "key")); + + // Data access with an empty key should be failed. + EXPECT_EQ(SERVICE_WORKER_ERROR_FAILED, + StoreUserData( + kRegistrationId, kScope.GetOrigin(), std::string(), "data")); + EXPECT_EQ(SERVICE_WORKER_ERROR_FAILED, + GetUserData(kRegistrationId, std::string(), &data_out)); + EXPECT_EQ(SERVICE_WORKER_ERROR_FAILED, + ClearUserData(kRegistrationId, std::string())); +} + class ServiceWorkerResourceStorageTest : public ServiceWorkerStorageTest { public: void SetUp() override {
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index 84db9fe..4a738e6 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc
@@ -3611,14 +3611,12 @@ void WebContentsImpl::UpdateState(RenderViewHost* rvh, int32 page_id, const PageState& page_state) { - // Ensure that this state update comes from either the active RVH or one of - // the swapped out RVHs. We don't expect to hear from any other RVHs. + // Ensure that this state update comes from a RenderViewHost that belongs to + // this WebContents. // TODO(nasko): This should go through RenderFrameHost. // TODO(creis): We can't update state for cross-process subframes until we // have FrameNavigationEntries. Once we do, this should be a DCHECK. - if (rvh != GetRenderViewHost() && - !GetRenderManager()->IsRVHOnSwappedOutList( - static_cast<RenderViewHostImpl*>(rvh))) + if (rvh->GetDelegate()->GetAsWebContents() != this) return; // We must be prepared to handle state updates for any page, these occur
diff --git a/content/browser/webui/shared_resources_data_source.cc b/content/browser/webui/shared_resources_data_source.cc index 5254bd1..2ecb989 100644 --- a/content/browser/webui/shared_resources_data_source.cc +++ b/content/browser/webui/shared_resources_data_source.cc
@@ -81,23 +81,20 @@ DCHECK_NE(-1, idr) << " path: " << path; scoped_refptr<base::RefCountedMemory> bytes; - ContentClient* content_client = GetContentClient(); - - // TODO(dbeam): there's some comments in content/DEPS about disallowing - // grd-related code. Does using this IDR_* go against that spirit? if (idr == IDR_WEBUI_CSS_TEXT_DEFAULTS) { std::vector<std::string> placeholders; placeholders.push_back(webui::GetTextDirection()); // $1 placeholders.push_back(webui::GetFontFamily()); // $2 placeholders.push_back(webui::GetFontSize()); // $3 + ContentClient* content_client = GetContentClient(); const std::string& chrome_shared = content_client->GetDataResource(idr, ui::SCALE_FACTOR_NONE).as_string(); std::string replaced = ReplaceStringPlaceholders(chrome_shared, placeholders, nullptr); bytes = base::RefCountedString::TakeString(&replaced); } else { - bytes = content_client->GetDataResourceBytes(idr); + bytes = GetContentClient()->GetDataResourceBytes(idr); } callback.Run(bytes.get());
diff --git a/content/child/blink_platform_impl.cc b/content/child/blink_platform_impl.cc index 022f2972..aeab042 100644 --- a/content/child/blink_platform_impl.cc +++ b/content/child/blink_platform_impl.cc
@@ -36,6 +36,8 @@ #include "content/child/geofencing/web_geofencing_provider_impl.h" #include "content/child/notifications/notification_dispatcher.h" #include "content/child/notifications/notification_manager.h" +#include "content/child/push_messaging/push_dispatcher.h" +#include "content/child/push_messaging/push_provider.h" #include "content/child/thread_safe_sender.h" #include "content/child/web_discardable_memory_impl.h" #include "content/child/web_gesture_curve_impl.h" @@ -448,6 +450,7 @@ thread_safe_sender_ = ChildThread::current()->thread_safe_sender(); notification_dispatcher_ = ChildThread::current()->notification_dispatcher(); + push_dispatcher_ = ChildThread::current()->push_dispatcher(); } if (main_thread_task_runner_.get()) { @@ -1064,6 +1067,14 @@ notification_dispatcher_.get()); } +blink::WebPushProvider* BlinkPlatformImpl::pushProvider() { + if (!thread_safe_sender_.get() || !push_dispatcher_.get()) + return nullptr; + + return PushProvider::ThreadSpecificInstance(thread_safe_sender_.get(), + push_dispatcher_.get()); +} + WebThemeEngine* BlinkPlatformImpl::themeEngine() { return &native_theme_engine_; }
diff --git a/content/child/blink_platform_impl.h b/content/child/blink_platform_impl.h index a0153deb..441f137 100644 --- a/content/child/blink_platform_impl.h +++ b/content/child/blink_platform_impl.h
@@ -34,6 +34,7 @@ namespace content { class FlingCurveConfiguration; class NotificationDispatcher; +class PushDispatcher; class ThreadSafeSender; class WebBluetoothImpl; class WebCryptoImpl; @@ -156,6 +157,7 @@ virtual blink::WebGeofencingProvider* geofencingProvider(); virtual blink::WebBluetooth* bluetooth(); virtual blink::WebNotificationManager* notificationManager(); + virtual blink::WebPushProvider* pushProvider(); void SuspendSharedTimer(); void ResumeSharedTimer(); @@ -190,6 +192,7 @@ scoped_refptr<ThreadSafeSender> thread_safe_sender_; scoped_refptr<NotificationDispatcher> notification_dispatcher_; + scoped_refptr<PushDispatcher> push_dispatcher_; }; } // namespace content
diff --git a/content/child/child_shared_bitmap_manager.cc b/content/child/child_shared_bitmap_manager.cc index 3affb9d..a62fd414 100644 --- a/content/child/child_shared_bitmap_manager.cc +++ b/content/child/child_shared_bitmap_manager.cc
@@ -67,10 +67,13 @@ sender_->Send(new ChildProcessHostMsg_SyncAllocateSharedBitmap( memory_size, id, &handle)); memory = make_scoped_ptr(new base::SharedMemory(handle, false)); - CHECK(memory->Map(memory_size)); + if (!memory->Map(memory_size)) + CHECK(false); #else - memory.reset(ChildThread::AllocateSharedMemory(memory_size, sender_.get())); + memory = ChildThread::AllocateSharedMemory(memory_size, sender_.get()); CHECK(memory); + if (!memory->Map(memory_size)) + CHECK(false); base::SharedMemoryHandle handle_to_send = memory->handle(); sender_->Send(new ChildProcessHostMsg_AllocatedSharedBitmap( memory_size, handle_to_send, id));
diff --git a/content/child/child_thread.cc b/content/child/child_thread.cc index 5061b4c..0380df2b 100644 --- a/content/child/child_thread.cc +++ b/content/child/child_thread.cc
@@ -39,6 +39,7 @@ #include "content/child/mojo/mojo_application.h" #include "content/child/notifications/notification_dispatcher.h" #include "content/child/power_monitor_broadcast_source.h" +#include "content/child/push_messaging/push_dispatcher.h" #include "content/child/quota_dispatcher.h" #include "content/child/quota_message_filter.h" #include "content/child/resource_dispatcher.h" @@ -296,11 +297,14 @@ new BluetoothMessageFilter(thread_safe_sender_.get()); notification_dispatcher_ = new NotificationDispatcher(thread_safe_sender_.get()); + push_dispatcher_ = new PushDispatcher(thread_safe_sender_.get()); + channel_->AddFilter(histogram_message_filter_.get()); channel_->AddFilter(sync_message_filter_.get()); channel_->AddFilter(resource_message_filter_.get()); channel_->AddFilter(quota_message_filter_->GetFilter()); channel_->AddFilter(notification_dispatcher_->GetFilter()); + channel_->AddFilter(push_dispatcher_->GetFilter()); channel_->AddFilter(service_worker_message_filter_->GetFilter()); channel_->AddFilter(geofencing_message_filter_->GetFilter()); channel_->AddFilter(bluetooth_message_filter_->GetFilter()); @@ -426,18 +430,20 @@ return &router_; } -base::SharedMemory* ChildThread::AllocateSharedMemory(size_t buf_size) { +scoped_ptr<base::SharedMemory> ChildThread::AllocateSharedMemory( + size_t buf_size) { + DCHECK(base::MessageLoop::current() == message_loop()); return AllocateSharedMemory(buf_size, this); } // static -base::SharedMemory* ChildThread::AllocateSharedMemory( +scoped_ptr<base::SharedMemory> ChildThread::AllocateSharedMemory( size_t buf_size, IPC::Sender* sender) { scoped_ptr<base::SharedMemory> shared_buf; #if defined(OS_WIN) shared_buf.reset(new base::SharedMemory); - if (!shared_buf->CreateAndMapAnonymous(buf_size)) { + if (!shared_buf->CreateAnonymous(buf_size)) { NOTREACHED(); return NULL; } @@ -449,10 +455,6 @@ buf_size, &shared_mem_handle))) { if (base::SharedMemory::IsHandleValid(shared_mem_handle)) { shared_buf.reset(new base::SharedMemory(shared_mem_handle, false)); - if (!shared_buf->Map(buf_size)) { - NOTREACHED() << "Map failed"; - return NULL; - } } else { NOTREACHED() << "Browser failed to allocate shared memory"; return NULL; @@ -462,7 +464,7 @@ return NULL; } #endif - return shared_buf.release(); + return shared_buf; } bool ChildThread::OnMessageReceived(const IPC::Message& msg) {
diff --git a/content/child/child_thread.h b/content/child/child_thread.h index ca9989d..8c42b04a 100644 --- a/content/child/child_thread.h +++ b/content/child/child_thread.h
@@ -45,6 +45,7 @@ class FileSystemDispatcher; class GeofencingMessageFilter; class NotificationDispatcher; +class PushDispatcher; class ServiceWorkerMessageFilter; class QuotaDispatcher; class QuotaMessageFilter; @@ -85,16 +86,17 @@ MessageRouter* GetRouter(); - // Allocates a block of shared memory of the given size and - // maps in into the address space. Returns NULL of failure. + // Allocates a block of shared memory of the given size. Returns NULL on + // failure. // Note: On posix, this requires a sync IPC to the browser process, // but on windows the child process directly allocates the block. - base::SharedMemory* AllocateSharedMemory(size_t buf_size); + scoped_ptr<base::SharedMemory> AllocateSharedMemory(size_t buf_size); // A static variant that can be called on background threads provided // the |sender| passed in is safe to use on background threads. - static base::SharedMemory* AllocateSharedMemory(size_t buf_size, - IPC::Sender* sender); + static scoped_ptr<base::SharedMemory> AllocateSharedMemory( + size_t buf_size, + IPC::Sender* sender); ChildSharedBitmapManager* shared_bitmap_manager() const { return shared_bitmap_manager_.get(); @@ -129,6 +131,10 @@ return notification_dispatcher_.get(); } + PushDispatcher* push_dispatcher() const { + return push_dispatcher_.get(); + } + IPC::SyncMessageFilter* sync_message_filter() const { return sync_message_filter_.get(); } @@ -251,6 +257,8 @@ scoped_refptr<NotificationDispatcher> notification_dispatcher_; + scoped_refptr<PushDispatcher> push_dispatcher_; + scoped_ptr<ChildSharedBitmapManager> shared_bitmap_manager_; scoped_ptr<ChildGpuMemoryBufferManager> gpu_memory_buffer_manager_;
diff --git a/content/child/push_messaging/OWNERS b/content/child/push_messaging/OWNERS new file mode 100644 index 0000000..9fe6d9b --- /dev/null +++ b/content/child/push_messaging/OWNERS
@@ -0,0 +1,2 @@ +mvanouwerkerk@chromium.org +peter@chromium.org
diff --git a/content/child/push_messaging/push_dispatcher.cc b/content/child/push_messaging/push_dispatcher.cc new file mode 100644 index 0000000..09ee1ccf --- /dev/null +++ b/content/child/push_messaging/push_dispatcher.cc
@@ -0,0 +1,78 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/child/push_messaging/push_dispatcher.h" + +#include "base/message_loop/message_loop_proxy.h" +#include "base/pickle.h" +#include "content/child/push_messaging/push_provider.h" +#include "content/child/thread_safe_sender.h" +#include "content/child/worker_thread_task_runner.h" +#include "content/common/push_messaging_messages.h" + +namespace content { + +PushDispatcher::PushDispatcher(ThreadSafeSender* thread_safe_sender) + : main_thread_loop_proxy_(base::MessageLoopProxy::current()), + thread_safe_sender_(thread_safe_sender), + next_request_id_(0) { +} + +PushDispatcher::~PushDispatcher() { +} + +int PushDispatcher::GenerateRequestId(int thread_id) { + base::AutoLock lock(request_id_map_lock_); + request_id_map_[next_request_id_] = thread_id; + return next_request_id_++; +} + +base::TaskRunner* PushDispatcher::OverrideTaskRunnerForMessage( + const IPC::Message& msg) { + if (!ShouldHandleMessage(msg)) + return nullptr; + + int request_id = -1; + int thread_id = 0; + + const bool success = PickleIterator(msg).ReadInt(&request_id); + DCHECK(success); + + { + base::AutoLock lock(request_id_map_lock_); + auto it = request_id_map_.find(request_id); + if (it != request_id_map_.end()) { + thread_id = it->second; + request_id_map_.erase(it); + } + } + + if (!thread_id) + return main_thread_loop_proxy_.get(); + + return new WorkerThreadTaskRunner(thread_id); +} + +bool PushDispatcher::OnMessageReceived(const IPC::Message& msg) { + if (!ShouldHandleMessage(msg)) + return false; + + bool handled = PushProvider::ThreadSpecificInstance( + thread_safe_sender_.get(), this)->OnMessageReceived(msg); + DCHECK(handled); + return handled; +} + +bool PushDispatcher::ShouldHandleMessage(const IPC::Message& msg) { + // Note that not all Push API IPC messages flow through this class. A subset + // of the API functionality requires a direct association with a document and + // a frame, and for those cases the IPC messages are handled by a + // RenderFrameObserver. + return msg.type() == PushMessagingMsg_RegisterFromWorkerSuccess::ID || + msg.type() == PushMessagingMsg_RegisterFromWorkerError::ID || + msg.type() == PushMessagingMsg_GetPermissionStatusSuccess::ID || + msg.type() == PushMessagingMsg_GetPermissionStatusError::ID; +} + +} // namespace content
diff --git a/content/child/push_messaging/push_dispatcher.h b/content/child/push_messaging/push_dispatcher.h new file mode 100644 index 0000000..db598fb --- /dev/null +++ b/content/child/push_messaging/push_dispatcher.h
@@ -0,0 +1,56 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_CHILD_PUSH_MESSAGING_PUSH_DISPATCHER_H_ +#define CONTENT_CHILD_PUSH_MESSAGING_PUSH_DISPATCHER_H_ + +#include <map> + +#include "base/memory/ref_counted.h" +#include "base/synchronization/lock.h" +#include "content/child/child_message_filter.h" +#include "content/public/common/push_messaging_status.h" + +namespace base { +class MessageLoopProxy; +} + +namespace content { + +class ThreadSafeSender; + +class PushDispatcher : public ChildMessageFilter { + public: + explicit PushDispatcher(ThreadSafeSender* thread_safe_sender); + + // Generates a process-unique new request id. Stores it in a map as key to + // |thread_id| and returns it. This method can be called on any thread. + // Note that the registration requests from document contexts do not go via + // this class and their request ids may overlap with the ones generated here. + int GenerateRequestId(int thread_id); + + protected: + ~PushDispatcher() override; + + private: + bool ShouldHandleMessage(const IPC::Message& msg); + + // ChildMessageFilter implementation. + base::TaskRunner* OverrideTaskRunnerForMessage( + const IPC::Message& msg) override; + bool OnMessageReceived(const IPC::Message& msg) override; + + scoped_refptr<base::MessageLoopProxy> main_thread_loop_proxy_; + scoped_refptr<ThreadSafeSender> thread_safe_sender_; + + base::Lock request_id_map_lock_; + std::map<int, int> request_id_map_; // Maps request id to thread id. + int next_request_id_; + + DISALLOW_COPY_AND_ASSIGN(PushDispatcher); +}; + +} // namespace content + +#endif // CONTENT_CHILD_PUSH_MESSAGING_PUSH_DISPATCHER_H_
diff --git a/content/child/push_messaging/push_provider.cc b/content/child/push_messaging/push_provider.cc new file mode 100644 index 0000000..6829d38 --- /dev/null +++ b/content/child/push_messaging/push_provider.cc
@@ -0,0 +1,174 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/child/push_messaging/push_provider.h" + +#include "base/lazy_instance.h" +#include "base/memory/scoped_ptr.h" +#include "base/stl_util.h" +#include "base/threading/thread_local.h" +#include "content/child/push_messaging/push_dispatcher.h" +#include "content/child/service_worker/web_service_worker_registration_impl.h" +#include "content/child/thread_safe_sender.h" +#include "content/child/worker_task_runner.h" +#include "content/common/push_messaging_messages.h" +#include "third_party/WebKit/public/platform/WebPushError.h" +#include "third_party/WebKit/public/platform/WebPushRegistration.h" +#include "third_party/WebKit/public/platform/WebString.h" + +namespace content { +namespace { + +int CurrentWorkerId() { + return WorkerTaskRunner::Instance()->CurrentWorkerId(); +} + +// Returns the id of the given |service_worker_registration|, which +// is only available on the implementation of the interface. +int64 GetServiceWorkerRegistrationId( + blink::WebServiceWorkerRegistration* service_worker_registration) { + return static_cast<WebServiceWorkerRegistrationImpl*>( + service_worker_registration)->registration_id(); +} + +} // namespace + +static base::LazyInstance<base::ThreadLocalPointer<PushProvider>>::Leaky + g_push_provider_tls = LAZY_INSTANCE_INITIALIZER; + +PushProvider::PushProvider(ThreadSafeSender* thread_safe_sender, + PushDispatcher* push_dispatcher) + : thread_safe_sender_(thread_safe_sender), + push_dispatcher_(push_dispatcher) { + g_push_provider_tls.Pointer()->Set(this); +} + +PushProvider::~PushProvider() { + STLDeleteContainerPairSecondPointers(registration_callbacks_.begin(), + registration_callbacks_.end()); + registration_callbacks_.clear(); + STLDeleteContainerPairSecondPointers(permission_status_callbacks_.begin(), + permission_status_callbacks_.end()); + permission_status_callbacks_.clear(); + g_push_provider_tls.Pointer()->Set(nullptr); +} + +PushProvider* PushProvider::ThreadSpecificInstance( + ThreadSafeSender* thread_safe_sender, + PushDispatcher* push_dispatcher) { + if (g_push_provider_tls.Pointer()->Get()) + return g_push_provider_tls.Pointer()->Get(); + + PushProvider* provider = + new PushProvider(thread_safe_sender, push_dispatcher); + if (CurrentWorkerId()) + WorkerTaskRunner::Instance()->AddStopObserver(provider); + return provider; +} + +void PushProvider::OnWorkerRunLoopStopped() { + delete this; +} + +void PushProvider::registerPushMessaging( + blink::WebServiceWorkerRegistration* service_worker_registration, + blink::WebPushRegistrationCallbacks* callbacks) { + DCHECK(service_worker_registration); + DCHECK(callbacks); + int request_id = push_dispatcher_->GenerateRequestId(CurrentWorkerId()); + registration_callbacks_[request_id] = callbacks; + int64 service_worker_registration_id = + GetServiceWorkerRegistrationId(service_worker_registration); + thread_safe_sender_->Send(new PushMessagingHostMsg_RegisterFromWorker( + request_id, service_worker_registration_id)); +} + +void PushProvider::getPermissionStatus( + blink::WebServiceWorkerRegistration* service_worker_registration, + blink::WebPushPermissionStatusCallbacks* callbacks) { + DCHECK(service_worker_registration); + DCHECK(callbacks); + int request_id = push_dispatcher_->GenerateRequestId(CurrentWorkerId()); + permission_status_callbacks_[request_id] = callbacks; + int64 service_worker_registration_id = + GetServiceWorkerRegistrationId(service_worker_registration); + thread_safe_sender_->Send(new PushMessagingHostMsg_GetPermissionStatus( + request_id, service_worker_registration_id)); +} + +bool PushProvider::OnMessageReceived(const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PushProvider, message) + IPC_MESSAGE_HANDLER(PushMessagingMsg_RegisterFromWorkerSuccess, + OnRegisterFromWorkerSuccess); + IPC_MESSAGE_HANDLER(PushMessagingMsg_RegisterFromWorkerError, + OnRegisterFromWorkerError); + IPC_MESSAGE_HANDLER(PushMessagingMsg_GetPermissionStatusSuccess, + OnGetPermissionStatusSuccess); + IPC_MESSAGE_HANDLER(PushMessagingMsg_GetPermissionStatusError, + OnGetPermissionStatusError); + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + + return handled; +} + +void PushProvider::OnRegisterFromWorkerSuccess( + int request_id, + const GURL& endpoint, + const std::string& registration_id) { + const auto& it = registration_callbacks_.find(request_id); + if (it == registration_callbacks_.end()) + return; + + scoped_ptr<blink::WebPushRegistrationCallbacks> callbacks(it->second); + registration_callbacks_.erase(it); + + scoped_ptr<blink::WebPushRegistration> registration( + new blink::WebPushRegistration( + blink::WebString::fromUTF8(endpoint.spec()), + blink::WebString::fromUTF8(registration_id))); + callbacks->onSuccess(registration.release()); +} + +void PushProvider::OnRegisterFromWorkerError(int request_id, + PushRegistrationStatus status) { + const auto& it = registration_callbacks_.find(request_id); + if (it == registration_callbacks_.end()) + return; + + scoped_ptr<blink::WebPushRegistrationCallbacks> callbacks(it->second); + registration_callbacks_.erase(it); + + scoped_ptr<blink::WebPushError> error(new blink::WebPushError( + blink::WebPushError::ErrorTypeAbort, + blink::WebString::fromUTF8(PushRegistrationStatusToString(status)))); + callbacks->onError(error.release()); +} + +void PushProvider::OnGetPermissionStatusSuccess( + int request_id, + blink::WebPushPermissionStatus status) { + const auto& it = permission_status_callbacks_.find(request_id); + if (it == permission_status_callbacks_.end()) + return; + + scoped_ptr<blink::WebPushPermissionStatusCallbacks> callbacks(it->second); + permission_status_callbacks_.erase(it); + + callbacks->onSuccess(&status); +} + +void PushProvider::OnGetPermissionStatusError(int request_id) { + const auto& it = permission_status_callbacks_.find(request_id); + if (it == permission_status_callbacks_.end()) + return; + + scoped_ptr<blink::WebPushPermissionStatusCallbacks> callbacks(it->second); + permission_status_callbacks_.erase(it); + + callbacks->onError(); +} + +} // namespace content
diff --git a/content/child/push_messaging/push_provider.h b/content/child/push_messaging/push_provider.h new file mode 100644 index 0000000..313a304a --- /dev/null +++ b/content/child/push_messaging/push_provider.h
@@ -0,0 +1,74 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_CHILD_PUSH_MESSAGING_PUSH_MANAGER_H_ +#define CONTENT_CHILD_PUSH_MESSAGING_PUSH_MANAGER_H_ + +#include <string> + +#include "base/memory/ref_counted.h" +#include "content/child/push_messaging/push_dispatcher.h" +#include "content/child/worker_task_runner.h" +#include "third_party/WebKit/public/platform/WebPushProvider.h" + +class GURL; + +namespace content { + +class ThreadSafeSender; + +class PushProvider : public blink::WebPushProvider, + public WorkerTaskRunner::Observer { + public: + ~PushProvider() override; + + // The |thread_safe_sender| and |push_dispatcher| are used if calling this + // leads to construction. + static PushProvider* ThreadSpecificInstance( + ThreadSafeSender* thread_safe_sender, + PushDispatcher* push_dispatcher); + + // WorkerTaskRunner::Observer implementation. + void OnWorkerRunLoopStopped() override; + + // blink::WebPushProvider implementation. + void registerPushMessaging(blink::WebServiceWorkerRegistration*, + blink::WebPushRegistrationCallbacks*) override; + void getPermissionStatus(blink::WebServiceWorkerRegistration*, + blink::WebPushPermissionStatusCallbacks*) override; + + // Called by the PushDispatcher. + bool OnMessageReceived(const IPC::Message& message); + + private: + PushProvider(ThreadSafeSender* thread_safe_sender, + PushDispatcher* push_dispatcher); + + // IPC message handlers. + void OnRegisterFromWorkerSuccess(int request_id, + const GURL& endpoint, + const std::string& registration_id); + void OnRegisterFromWorkerError(int request_id, PushRegistrationStatus status); + void OnGetPermissionStatusSuccess(int request_id, + blink::WebPushPermissionStatus status); + void OnGetPermissionStatusError(int request_id); + + scoped_refptr<ThreadSafeSender> thread_safe_sender_; + scoped_refptr<PushDispatcher> push_dispatcher_; + + // Stores the registration callbacks with their request ids. This class owns + // the callbacks. + std::map<int, blink::WebPushRegistrationCallbacks*> registration_callbacks_; + + // Stores the permission status callbacks with their request ids. This class + // owns the callbacks. + std::map<int, blink::WebPushPermissionStatusCallbacks*> + permission_status_callbacks_; + + DISALLOW_COPY_AND_ASSIGN(PushProvider); +}; + +} // namespace content + +#endif // CONTENT_CHILD_PUSH_MESSAGING_PUSH_MANAGER_H_
diff --git a/content/child/webblobregistry_impl.cc b/content/child/webblobregistry_impl.cc index 9503ec5..0140ce56 100644 --- a/content/child/webblobregistry_impl.cc +++ b/content/child/webblobregistry_impl.cc
@@ -134,6 +134,8 @@ ChildThread::AllocateSharedMemory(shared_memory_size, sender_.get())); CHECK(shared_memory.get()); + if (!shared_memory->Map(shared_memory_size)) + CHECK(false); size_t data_size = data.size(); const char* data_ptr = data.data(); @@ -180,6 +182,8 @@ ChildThread::AllocateSharedMemory(shared_memory_size, sender_.get())); CHECK(shared_memory.get()); + if (!shared_memory->Map(shared_memory_size)) + CHECK(false); size_t remaining_bytes = length; const char* current_ptr = data;
diff --git a/content/child/webcrypto/status.cc b/content/child/webcrypto/status.cc index 5eddb0d..d66a766 100644 --- a/content/child/webcrypto/status.cc +++ b/content/child/webcrypto/status.cc
@@ -210,7 +210,7 @@ Status Status::ErrorInvalidAesGcmTagLength() { return Status( - blink::WebCryptoErrorTypeData, + blink::WebCryptoErrorTypeOperation, "The tag length is invalid: Must be 32, 64, 96, 104, 112, 120, or 128 " "bits"); } @@ -260,7 +260,7 @@ Status Status::ErrorGenerateHmacKeyLengthZero() { return Status(blink::WebCryptoErrorTypeOperation, - "HMAC key length must be not be zero"); + "HMAC key length must not be zero"); } Status Status::ErrorCreateKeyBadUsages() {
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn index af4c97a..b66ed753 100644 --- a/content/common/BUILD.gn +++ b/content/common/BUILD.gn
@@ -152,6 +152,7 @@ "//content/app/resources", "//content:resources", "//third_party/WebKit/public:resources", + "//ui/accelerated_widget_mac", ] libs += [ "QuartzCore.framework" ] }
diff --git a/content/common/gpu/client/gl_helper_unittest.cc b/content/common/gpu/client/gl_helper_unittest.cc index 47e2edf..ba7d4fc 100644 --- a/content/common/gpu/client/gl_helper_unittest.cc +++ b/content/common/gpu/client/gl_helper_unittest.cc
@@ -21,6 +21,8 @@ #include "base/run_loop.h" #include "base/strings/stringprintf.h" #include "base/synchronization/waitable_event.h" +#include "base/test/launcher/unit_test_launcher.h" +#include "base/test/test_suite.h" #include "base/time/time.h" #include "content/common/gpu/client/gl_helper.h" #include "content/common/gpu/client/gl_helper_readback_support.h" @@ -1950,6 +1952,16 @@ CheckOptimizationsTest(); } +} // namespace content + +namespace { + +int RunHelper(base::TestSuite* test_suite) { + content::UnitTestTestSuite runner(test_suite); + base::MessageLoopForIO message_loop; + return runner.Run(); +} + } // namespace // These tests needs to run against a proper GL environment, so we @@ -1961,7 +1973,8 @@ base::mac::ScopedNSAutoreleasePool pool; #endif - content::UnitTestTestSuite runner(suite); - base::MessageLoop message_loop; - return runner.Run(); + return base::LaunchUnitTestsSerially( + argc, + argv, + base::Bind(&RunHelper, base::Unretained(suite))); }
diff --git a/content/common/gpu/gpu_memory_buffer_factory_io_surface.cc b/content/common/gpu/gpu_memory_buffer_factory_io_surface.cc index f13231d..e6954bf 100644 --- a/content/common/gpu/gpu_memory_buffer_factory_io_surface.cc +++ b/content/common/gpu/gpu_memory_buffer_factory_io_surface.cc
@@ -110,9 +110,13 @@ if (!io_surface) return gfx::GpuMemoryBufferHandle(); - IOSurfaceMapKey key(id, client_id); - DCHECK(io_surfaces_.find(key) == io_surfaces_.end()); - io_surfaces_[key] = io_surface; + { + base::AutoLock lock(io_surfaces_lock_); + + IOSurfaceMapKey key(id, client_id); + DCHECK(io_surfaces_.find(key) == io_surfaces_.end()); + io_surfaces_[key] = io_surface; + } gfx::GpuMemoryBufferHandle handle; handle.type = gfx::IO_SURFACE_BUFFER; @@ -124,6 +128,8 @@ void GpuMemoryBufferFactoryIOSurface::DestroyGpuMemoryBuffer( gfx::GpuMemoryBufferId id, int client_id) { + base::AutoLock lock(io_surfaces_lock_); + IOSurfaceMapKey key(id, client_id); IOSurfaceMap::iterator it = io_surfaces_.find(key); if (it != io_surfaces_.end()) @@ -141,6 +147,8 @@ gfx::GpuMemoryBuffer::Format format, unsigned internalformat, int client_id) { + base::AutoLock lock(io_surfaces_lock_); + DCHECK_EQ(handle.type, gfx::IO_SURFACE_BUFFER); IOSurfaceMapKey key(handle.id, client_id); IOSurfaceMap::iterator it = io_surfaces_.find(key);
diff --git a/content/common/gpu/gpu_memory_buffer_factory_io_surface.h b/content/common/gpu/gpu_memory_buffer_factory_io_surface.h index e2c64ee..e636bbd 100644 --- a/content/common/gpu/gpu_memory_buffer_factory_io_surface.h +++ b/content/common/gpu/gpu_memory_buffer_factory_io_surface.h
@@ -10,6 +10,7 @@ #include "base/containers/hash_tables.h" #include "base/mac/scoped_cftyperef.h" #include "base/memory/ref_counted.h" +#include "base/synchronization/lock.h" #include "content/common/gpu/gpu_memory_buffer_factory.h" #include "gpu/command_buffer/service/image_factory.h" #include "ui/gfx/geometry/size.h" @@ -57,6 +58,7 @@ typedef base::hash_map<IOSurfaceMapKey, base::ScopedCFTypeRef<IOSurfaceRef>> IOSurfaceMap; IOSurfaceMap io_surfaces_; + base::Lock io_surfaces_lock_; DISALLOW_COPY_AND_ASSIGN(GpuMemoryBufferFactoryIOSurface); };
diff --git a/content/common/gpu/gpu_memory_buffer_factory_surface_texture.cc b/content/common/gpu/gpu_memory_buffer_factory_surface_texture.cc index 779cfa2f..2410e61 100644 --- a/content/common/gpu/gpu_memory_buffer_factory_surface_texture.cc +++ b/content/common/gpu/gpu_memory_buffer_factory_surface_texture.cc
@@ -63,9 +63,13 @@ SurfaceTextureManager::GetInstance()->RegisterSurfaceTexture( id, client_id, surface_texture.get()); - SurfaceTextureMapKey key(id, client_id); - DCHECK(surface_textures_.find(key) == surface_textures_.end()); - surface_textures_[key] = surface_texture; + { + base::AutoLock lock(surface_textures_lock_); + + SurfaceTextureMapKey key(id, client_id); + DCHECK(surface_textures_.find(key) == surface_textures_.end()); + surface_textures_[key] = surface_texture; + } gfx::GpuMemoryBufferHandle handle; handle.type = gfx::SURFACE_TEXTURE_BUFFER; @@ -76,10 +80,14 @@ void GpuMemoryBufferFactorySurfaceTexture::DestroyGpuMemoryBuffer( gfx::GpuMemoryBufferId id, int client_id) { - SurfaceTextureMapKey key(id, client_id); - SurfaceTextureMap::iterator it = surface_textures_.find(key); - if (it != surface_textures_.end()) - surface_textures_.erase(it); + { + base::AutoLock lock(surface_textures_lock_); + + SurfaceTextureMapKey key(id, client_id); + SurfaceTextureMap::iterator it = surface_textures_.find(key); + if (it != surface_textures_.end()) + surface_textures_.erase(it); + } SurfaceTextureManager::GetInstance()->UnregisterSurfaceTexture(id, client_id); } @@ -95,7 +103,10 @@ gfx::GpuMemoryBuffer::Format format, unsigned internalformat, int client_id) { + base::AutoLock lock(surface_textures_lock_); + DCHECK_EQ(handle.type, gfx::SURFACE_TEXTURE_BUFFER); + SurfaceTextureMapKey key(handle.id, client_id); SurfaceTextureMap::iterator it = surface_textures_.find(key); if (it == surface_textures_.end())
diff --git a/content/common/gpu/gpu_memory_buffer_factory_surface_texture.h b/content/common/gpu/gpu_memory_buffer_factory_surface_texture.h index 80a5efc..57dfc94 100644 --- a/content/common/gpu/gpu_memory_buffer_factory_surface_texture.h +++ b/content/common/gpu/gpu_memory_buffer_factory_surface_texture.h
@@ -7,6 +7,7 @@ #include "base/containers/hash_tables.h" #include "base/memory/ref_counted.h" +#include "base/synchronization/lock.h" #include "content/common/gpu/gpu_memory_buffer_factory.h" #include "gpu/command_buffer/service/image_factory.h" #include "ui/gfx/geometry/size.h" @@ -55,6 +56,7 @@ typedef base::hash_map<SurfaceTextureMapKey, scoped_refptr<gfx::SurfaceTexture>> SurfaceTextureMap; SurfaceTextureMap surface_textures_; + base::Lock surface_textures_lock_; }; } // namespace content
diff --git a/content/common/gpu/image_transport_surface.cc b/content/common/gpu/image_transport_surface.cc index 922a498..02a6af01 100644 --- a/content/common/gpu/image_transport_surface.cc +++ b/content/common/gpu/image_transport_surface.cc
@@ -235,10 +235,6 @@ // GetVsyncValues before SwapBuffers to work around Mali driver bug: // crbug.com/223558. SendVSyncUpdateIfAvailable(); - for (size_t i = 0; i < latency_info_.size(); ++i) { - latency_info_[i].AddLatencyNumber( - ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, 0); - } bool result = gfx::GLSurfaceAdapter::SwapBuffers(); for (size_t i = 0; i < latency_info_.size(); i++) { latency_info_[i].AddLatencyNumber(
diff --git a/content/common/gpu/image_transport_surface_calayer_mac.mm b/content/common/gpu/image_transport_surface_calayer_mac.mm index 0147b3c..bd89912e 100644 --- a/content/common/gpu/image_transport_surface_calayer_mac.mm +++ b/content/common/gpu/image_transport_surface_calayer_mac.mm
@@ -8,7 +8,7 @@ #include "base/command_line.h" #include "base/mac/sdk_forward_declarations.h" -#include "content/common/gpu/surface_handle_types_mac.h" +#include "ui/accelerated_widget_mac/surface_handle_types.h" #include "ui/base/cocoa/animation_utils.h" #include "ui/gfx/geometry/size_conversions.h" #include "ui/gl/gl_gl_api_implementation.h" @@ -363,7 +363,7 @@ pending_draw_weak_factory_.InvalidateWeakPtrs(); has_pending_draw_ = false; transport_surface_->SendSwapBuffers( - SurfaceHandleFromCAContextID([context_ contextId]), + ui::SurfaceHandleFromCAContextID([context_ contextId]), fbo_pixel_size_, fbo_scale_factor_); }
diff --git a/content/common/gpu/image_transport_surface_iosurface_mac.cc b/content/common/gpu/image_transport_surface_iosurface_mac.cc index 121a3a2f..ec6b47f 100644 --- a/content/common/gpu/image_transport_surface_iosurface_mac.cc +++ b/content/common/gpu/image_transport_surface_iosurface_mac.cc
@@ -5,7 +5,7 @@ #include "content/common/gpu/image_transport_surface_iosurface_mac.h" #include "content/common/gpu/gpu_messages.h" -#include "content/common/gpu/surface_handle_types_mac.h" +#include "ui/accelerated_widget_mac/surface_handle_types.h" namespace content { namespace { @@ -115,7 +115,7 @@ pending_swapped_surfaces_.push_back(io_surface_); transport_surface_->SendSwapBuffers( - SurfaceHandleFromIOSurfaceID(io_surface_id_), size, scale_factor); + ui::SurfaceHandleFromIOSurfaceID(io_surface_id_), size, scale_factor); } void IOSurfaceStorageProvider::WillWriteToBackbuffer() {
diff --git a/content/common/gpu/media/generic_v4l2_video_device.cc b/content/common/gpu/media/exynos_v4l2_video_device.cc similarity index 85% rename from content/common/gpu/media/generic_v4l2_video_device.cc rename to content/common/gpu/media/exynos_v4l2_video_device.cc index b0cbe58..214a4311 100644 --- a/content/common/gpu/media/generic_v4l2_video_device.cc +++ b/content/common/gpu/media/exynos_v4l2_video_device.cc
@@ -14,23 +14,23 @@ #include "base/debug/trace_event.h" #include "base/files/scoped_file.h" #include "base/posix/eintr_wrapper.h" -#include "content/common/gpu/media/generic_v4l2_video_device.h" +#include "content/common/gpu/media/exynos_v4l2_video_device.h" #include "ui/gl/gl_bindings.h" namespace content { namespace { -const char kDecoderDevice[] = "/dev/video-dec"; -const char kEncoderDevice[] = "/dev/video-enc"; +const char kDecoderDevice[] = "/dev/mfc-dec"; +const char kEncoderDevice[] = "/dev/mfc-enc"; const char kImageProcessorDevice[] = "/dev/gsc1"; } -GenericV4L2Device::GenericV4L2Device(Type type) +ExynosV4L2Device::ExynosV4L2Device(Type type) : type_(type), device_fd_(-1), device_poll_interrupt_fd_(-1) {} -GenericV4L2Device::~GenericV4L2Device() { +ExynosV4L2Device::~ExynosV4L2Device() { if (device_poll_interrupt_fd_ != -1) { close(device_poll_interrupt_fd_); device_poll_interrupt_fd_ = -1; @@ -41,11 +41,11 @@ } } -int GenericV4L2Device::Ioctl(int request, void* arg) { +int ExynosV4L2Device::Ioctl(int request, void* arg) { return HANDLE_EINTR(ioctl(device_fd_, request, arg)); } -bool GenericV4L2Device::Poll(bool poll_device, bool* event_pending) { +bool ExynosV4L2Device::Poll(bool poll_device, bool* event_pending) { struct pollfd pollfds[2]; nfds_t nfds; int pollfd = -1; @@ -70,7 +70,7 @@ return true; } -void* GenericV4L2Device::Mmap(void* addr, +void* ExynosV4L2Device::Mmap(void* addr, unsigned int len, int prot, int flags, @@ -78,11 +78,11 @@ return mmap(addr, len, prot, flags, device_fd_, offset); } -void GenericV4L2Device::Munmap(void* addr, unsigned int len) { +void ExynosV4L2Device::Munmap(void* addr, unsigned int len) { munmap(addr, len); } -bool GenericV4L2Device::SetDevicePollInterrupt() { +bool ExynosV4L2Device::SetDevicePollInterrupt() { DVLOG(3) << "SetDevicePollInterrupt()"; const uint64 buf = 1; @@ -93,7 +93,7 @@ return true; } -bool GenericV4L2Device::ClearDevicePollInterrupt() { +bool ExynosV4L2Device::ClearDevicePollInterrupt() { DVLOG(3) << "ClearDevicePollInterrupt()"; uint64 buf; @@ -109,7 +109,7 @@ return true; } -bool GenericV4L2Device::Initialize() { +bool ExynosV4L2Device::Initialize() { const char* device_path = NULL; switch (type_) { case kDecoder: @@ -137,7 +137,7 @@ return true; } -EGLImageKHR GenericV4L2Device::CreateEGLImage(EGLDisplay egl_display, +EGLImageKHR ExynosV4L2Device::CreateEGLImage(EGLDisplay egl_display, EGLContext /* egl_context */, GLuint texture_id, gfx::Size frame_buffer_size, @@ -187,21 +187,21 @@ return egl_image; } -EGLBoolean GenericV4L2Device::DestroyEGLImage(EGLDisplay egl_display, +EGLBoolean ExynosV4L2Device::DestroyEGLImage(EGLDisplay egl_display, EGLImageKHR egl_image) { return eglDestroyImageKHR(egl_display, egl_image); } -GLenum GenericV4L2Device::GetTextureTarget() { return GL_TEXTURE_EXTERNAL_OES; } +GLenum ExynosV4L2Device::GetTextureTarget() { return GL_TEXTURE_EXTERNAL_OES; } -uint32 GenericV4L2Device::PreferredInputFormat() { +uint32 ExynosV4L2Device::PreferredInputFormat() { // TODO(posciak): We should support "dontcare" returns here once we // implement proper handling (fallback, negotiation) for this in users. CHECK_EQ(type_, kEncoder); return V4L2_PIX_FMT_NV12M; } -uint32 GenericV4L2Device::PreferredOutputFormat() { +uint32 ExynosV4L2Device::PreferredOutputFormat() { // TODO(posciak): We should support "dontcare" returns here once we // implement proper handling (fallback, negotiation) for this in users. CHECK_EQ(type_, kDecoder);
diff --git a/content/common/gpu/media/generic_v4l2_video_device.h b/content/common/gpu/media/exynos_v4l2_video_device.h similarity index 79% rename from content/common/gpu/media/generic_v4l2_video_device.h rename to content/common/gpu/media/exynos_v4l2_video_device.h index d748bcd1..d1498a6 100644 --- a/content/common/gpu/media/generic_v4l2_video_device.h +++ b/content/common/gpu/media/exynos_v4l2_video_device.h
@@ -2,20 +2,20 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// This file contains the implementation of GenericV4L2Device used on -// Generic platform. +// This file contains the implementation of ExynosV4L2Device used on +// Exynos platform. -#ifndef CONTENT_COMMON_GPU_MEDIA_GENERIC_V4L2_VIDEO_DEVICE_H_ -#define CONTENT_COMMON_GPU_MEDIA_GENERIC_V4L2_VIDEO_DEVICE_H_ +#ifndef CONTENT_COMMON_GPU_MEDIA_EXYNOS_V4L2_VIDEO_DEVICE_H_ +#define CONTENT_COMMON_GPU_MEDIA_EXYNOS_V4L2_VIDEO_DEVICE_H_ #include "content/common/gpu/media/v4l2_video_device.h" namespace content { -class GenericV4L2Device : public V4L2Device { +class ExynosV4L2Device : public V4L2Device { public: - explicit GenericV4L2Device(Type type); - virtual ~GenericV4L2Device(); + explicit ExynosV4L2Device(Type type); + virtual ~ExynosV4L2Device(); // V4L2Device implementation. virtual int Ioctl(int request, void* arg) override; @@ -51,8 +51,8 @@ // interrupted. int device_poll_interrupt_fd_; - DISALLOW_COPY_AND_ASSIGN(GenericV4L2Device); + DISALLOW_COPY_AND_ASSIGN(ExynosV4L2Device); }; } // namespace content -#endif // CONTENT_COMMON_GPU_MEDIA_GENERIC_V4L2_VIDEO_DEVICE_H_ +#endif // CONTENT_COMMON_GPU_MEDIA_EXYNOS_V4L2_VIDEO_DEVICE_H_
diff --git a/content/common/gpu/media/v4l2_video_device.cc b/content/common/gpu/media/v4l2_video_device.cc index 59775c38..58b935a 100644 --- a/content/common/gpu/media/v4l2_video_device.cc +++ b/content/common/gpu/media/v4l2_video_device.cc
@@ -5,7 +5,7 @@ #include <linux/videodev2.h> #include "base/numerics/safe_conversions.h" -#include "content/common/gpu/media/generic_v4l2_video_device.h" +#include "content/common/gpu/media/exynos_v4l2_video_device.h" #include "content/common/gpu/media/tegra_v4l2_video_device.h" namespace content { @@ -16,9 +16,9 @@ scoped_ptr<V4L2Device> V4L2Device::Create(Type type) { DVLOG(3) << __PRETTY_FUNCTION__; - scoped_ptr<GenericV4L2Device> generic_device(new GenericV4L2Device(type)); - if (generic_device->Initialize()) - return generic_device.Pass(); + scoped_ptr<ExynosV4L2Device> exynos_device(new ExynosV4L2Device(type)); + if (exynos_device->Initialize()) + return exynos_device.Pass(); scoped_ptr<TegraV4L2Device> tegra_device(new TegraV4L2Device(type)); if (tegra_device->Initialize())
diff --git a/content/common/gpu/media/vt.sig b/content/common/gpu/media/vt.sig index 236a52a..a9639a3 100644 --- a/content/common/gpu/media/vt.sig +++ b/content/common/gpu/media/vt.sig
@@ -13,4 +13,4 @@ Boolean VTDecompressionSessionCanAcceptFormatDescription(VTDecompressionSessionRef session, CMFormatDescriptionRef newFormatDesc); OSStatus VTDecompressionSessionCreate(CFAllocatorRef allocator, CMVideoFormatDescriptionRef videoFormatDescription, CFDictionaryRef videoDecoderSpecification, CFDictionaryRef destinationImageBufferAttributes, const VTDecompressionOutputCallbackRecord *outputCallback, VTDecompressionSessionRef *decompressionSessionOut); OSStatus VTDecompressionSessionDecodeFrame(VTDecompressionSessionRef session, CMSampleBufferRef sampleBuffer, VTDecodeFrameFlags decodeFlags, void *sourceFrameRefCon, VTDecodeInfoFlags *infoFlagsOut); -OSStatus VTDecompressionSessionFinishDelayedFrames(VTDecompressionSessionRef session); +OSStatus VTDecompressionSessionWaitForAsynchronousFrames(VTDecompressionSessionRef session);
diff --git a/content/common/gpu/media/vt_video_decode_accelerator.cc b/content/common/gpu/media/vt_video_decode_accelerator.cc index 9a91c9c..d4ad116c 100644 --- a/content/common/gpu/media/vt_video_decode_accelerator.cc +++ b/content/common/gpu/media/vt_video_decode_accelerator.cc
@@ -246,9 +246,10 @@ bool VTVideoDecodeAccelerator::FinishDelayedFrames() { DCHECK(decoder_thread_.message_loop_proxy()->BelongsToCurrentThread()); if (session_) { - OSStatus status = VTDecompressionSessionFinishDelayedFrames(session_); + OSStatus status = VTDecompressionSessionWaitForAsynchronousFrames(session_); if (status) { - NOTIFY_STATUS("VTDecompressionSessionFinishDelayedFrames()", status); + NOTIFY_STATUS("VTDecompressionSessionWaitForAsynchronousFrames()", + status); return false; } } @@ -318,7 +319,8 @@ base::ScopedCFTypeRef<CFMutableDictionaryRef> image_config( BuildImageConfig(coded_dimensions)); - // TODO(sandersd): Does the old session need to be flushed first? + if (!FinishDelayedFrames()) + return false; session_.reset(); status = VTDecompressionSessionCreate( kCFAllocatorDefault,
diff --git a/content/common/host_shared_bitmap_manager.cc b/content/common/host_shared_bitmap_manager.cc index 521af12..3c17bc7 100644 --- a/content/common/host_shared_bitmap_manager.cc +++ b/content/common/host_shared_bitmap_manager.cc
@@ -14,13 +14,10 @@ class BitmapData : public base::RefCountedThreadSafe<BitmapData> { public: BitmapData(base::ProcessHandle process_handle, - base::SharedMemoryHandle memory_handle, size_t buffer_size) : process_handle(process_handle), - memory_handle(memory_handle), buffer_size(buffer_size) {} base::ProcessHandle process_handle; - base::SharedMemoryHandle memory_handle; scoped_ptr<base::SharedMemory> memory; scoped_ptr<uint8[]> pixels; size_t buffer_size; @@ -78,7 +75,6 @@ scoped_refptr<BitmapData> data( new BitmapData(base::GetCurrentProcessHandle(), - base::SharedMemory::NULLHandle(), bitmap_size)); // Bitmaps allocated in host don't need to be shared to other processes, so // allocate them with new instead. @@ -135,16 +131,16 @@ if (handle_map_.find(id) != handle_map_.end()) return; scoped_refptr<BitmapData> data( - new BitmapData(process_handle, handle, buffer_size)); + new BitmapData(process_handle, buffer_size)); handle_map_[id] = data; process_map_[process_handle].insert(id); #if defined(OS_WIN) data->memory = make_scoped_ptr( - new base::SharedMemory(data->memory_handle, false, data->process_handle)); + new base::SharedMemory(handle, false, data->process_handle)); #else data->memory = - make_scoped_ptr(new base::SharedMemory(data->memory_handle, false)); + make_scoped_ptr(new base::SharedMemory(handle, false)); #endif } @@ -166,7 +162,7 @@ } scoped_refptr<BitmapData> data( - new BitmapData(process_handle, shared_memory->handle(), buffer_size)); + new BitmapData(process_handle, buffer_size)); data->memory = shared_memory.Pass(); handle_map_[id] = data;
diff --git a/content/common/push_messaging_messages.h b/content/common/push_messaging_messages.h index f6dbdd1..33de790 100644 --- a/content/common/push_messaging_messages.h +++ b/content/common/push_messaging_messages.h
@@ -18,34 +18,62 @@ IPC_ENUM_TRAITS_MAX_VALUE( blink::WebPushPermissionStatus, blink::WebPushPermissionStatus::WebPushPermissionStatusLast) -// Messages sent from the browser to the renderer. -IPC_MESSAGE_ROUTED3(PushMessagingMsg_RegisterSuccess, - int32 /* callbacks_id */, +// Messages sent from the browser to the child process. + +IPC_MESSAGE_ROUTED3(PushMessagingMsg_RegisterFromDocumentSuccess, + int32 /* request_id */, GURL /* push_endpoint */, std::string /* push_registration_id */) -IPC_MESSAGE_ROUTED2(PushMessagingMsg_RegisterError, - int32 /* callbacks_id */, +IPC_MESSAGE_CONTROL3(PushMessagingMsg_RegisterFromWorkerSuccess, + int32 /* request_id */, + GURL /* push_endpoint */, + std::string /* push_registration_id */) + +IPC_MESSAGE_ROUTED2(PushMessagingMsg_RegisterFromDocumentError, + int32 /* request_id */, content::PushRegistrationStatus /* status */) +IPC_MESSAGE_CONTROL2(PushMessagingMsg_RegisterFromWorkerError, + int32 /* request_id */, + content::PushRegistrationStatus /* status */) + +// TODO(mvanouwerkerk): Delete this after switching to the platform code path. IPC_MESSAGE_ROUTED2(PushMessagingMsg_PermissionStatusResult, int32 /* callback_id */, blink::WebPushPermissionStatus /* status */) +IPC_MESSAGE_CONTROL2(PushMessagingMsg_GetPermissionStatusSuccess, + int32 /* request_id */, + blink::WebPushPermissionStatus /* status */) + +// TODO(mvanouwerkerk): Delete this after switching to the platform code path. IPC_MESSAGE_ROUTED1(PushMessagingMsg_PermissionStatusFailure, int32 /* callback_id */) -// Messages sent from the renderer to the browser. +IPC_MESSAGE_CONTROL1(PushMessagingMsg_GetPermissionStatusError, + int32 /* request_id */) -IPC_MESSAGE_CONTROL5(PushMessagingHostMsg_Register, +// Messages sent from the child process to the browser. + +IPC_MESSAGE_CONTROL5(PushMessagingHostMsg_RegisterFromDocument, int32 /* render_frame_id */, - int32 /* callbacks_id */, + int32 /* request_id */, std::string /* sender_id */, bool /* user_gesture */, int32 /* service_worker_provider_id */) +IPC_MESSAGE_CONTROL2(PushMessagingHostMsg_RegisterFromWorker, + int32 /* request_id */, + int64 /* service_worker_registration_id */) + +// TODO(mvanouwerkerk): Delete this after switching to the platform code path. IPC_MESSAGE_CONTROL3(PushMessagingHostMsg_PermissionStatus, int32 /* render_frame_id */, int32 /* service_worker_provider_id */, int32 /* permission_callback_id */) + +IPC_MESSAGE_CONTROL2(PushMessagingHostMsg_GetPermissionStatus, + int32 /* request_id */, + int64 /* service_worker_registration_id */)
diff --git a/content/common/service_worker/service_worker_messages.h b/content/common/service_worker/service_worker_messages.h index 3d6a459..476f39a 100644 --- a/content/common/service_worker/service_worker_messages.h +++ b/content/common/service_worker/service_worker_messages.h
@@ -363,7 +363,7 @@ int /* request_id */) IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_NotificationClickEvent, int /* request_id */, - std::string /* notification_id */); + std::string /* notification_id */) IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_PushEvent, int /* request_id */, std::string /* data */)
diff --git a/content/content.gyp b/content/content.gyp index cfa5b215..cbb21cdc 100644 --- a/content/content.gyp +++ b/content/content.gyp
@@ -461,13 +461,6 @@ 'R_package': 'org.chromium.content', 'R_package_relpath': 'org/chromium/content', }, - 'conditions': [ - ['android_webview_build == 0', { - 'dependencies': [ - '../third_party/eyesfree/eyesfree.gyp:eyesfree_java', - ], - }], - ], 'includes': [ '../build/java.gypi' ], }, {
diff --git a/content/content_browser.gypi b/content/content_browser.gypi index df406498..819ce32 100644 --- a/content/content_browser.gypi +++ b/content/content_browser.gypi
@@ -1472,8 +1472,6 @@ 'browser/renderer_host/p2p/socket_dispatcher_host.h', ], 'compositor_browser_sources': [ - 'browser/compositor/browser_compositor_ca_layer_tree_mac.mm', - 'browser/compositor/browser_compositor_ca_layer_tree_mac.h', 'browser/compositor/browser_compositor_output_surface.cc', 'browser/compositor/browser_compositor_output_surface.h', 'browser/compositor/browser_compositor_output_surface_proxy.cc', @@ -1488,12 +1486,6 @@ 'browser/compositor/gpu_process_transport_factory.h', 'browser/compositor/image_transport_factory.cc', 'browser/compositor/image_transport_factory.h', - 'browser/compositor/io_surface_context_mac.h', - 'browser/compositor/io_surface_context_mac.mm', - 'browser/compositor/io_surface_layer_mac.h', - 'browser/compositor/io_surface_layer_mac.mm', - 'browser/compositor/io_surface_texture_mac.h', - 'browser/compositor/io_surface_texture_mac.mm', 'browser/compositor/overlay_candidate_validator_ozone.cc', 'browser/compositor/overlay_candidate_validator_ozone.h', 'browser/compositor/owned_mailbox.h', @@ -1502,8 +1494,6 @@ 'browser/compositor/reflector_impl.h', 'browser/compositor/resize_lock.cc', 'browser/compositor/resize_lock.h', - 'browser/compositor/software_layer_mac.mm', - 'browser/compositor/software_layer_mac.h', 'browser/compositor/gpu_browser_compositor_output_surface.cc', 'browser/compositor/gpu_browser_compositor_output_surface.h', 'browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc', @@ -1863,6 +1853,7 @@ 'dependencies': [ '../third_party/mozilla/mozilla.gyp:mozilla', '../third_party/sudden_motion_sensor/sudden_motion_sensor.gyp:sudden_motion_sensor', + '../ui/accelerated_widget_mac/accelerated_widget_mac.gyp:accelerated_widget_mac', ], 'link_settings': { 'libraries': [
diff --git a/content/content_child.gypi b/content/content_child.gypi index d32986a7..8775911 100644 --- a/content/content_child.gypi +++ b/content/content_child.gypi
@@ -159,6 +159,10 @@ 'child/plugin_param_traits.h', 'child/power_monitor_broadcast_source.cc', 'child/power_monitor_broadcast_source.h', + 'child/push_messaging/push_dispatcher.cc', + 'child/push_messaging/push_dispatcher.h', + 'child/push_messaging/push_provider.cc', + 'child/push_messaging/push_provider.h', 'child/quota_dispatcher.cc', 'child/quota_dispatcher.h', 'child/quota_message_filter.cc',
diff --git a/content/content_common.gypi b/content/content_common.gypi index 63c8166..d64d50c 100644 --- a/content/content_common.gypi +++ b/content/content_common.gypi
@@ -324,8 +324,6 @@ 'common/gpu/null_transport_surface.h', 'common/gpu/stream_texture_android.cc', 'common/gpu/stream_texture_android.h', - 'common/gpu/surface_handle_types_mac.cc', - 'common/gpu/surface_handle_types_mac.h', 'common/handle_enumerator_win.cc', 'common/handle_enumerator_win.h', 'common/host_discardable_shared_memory_manager.cc', @@ -606,6 +604,7 @@ 'dependencies': [ '../media/media.gyp:media', 'app/resources/content_resources.gyp:content_resources', + '../ui/accelerated_widget_mac/accelerated_widget_mac.gyp:accelerated_widget_mac' ], 'sources': [ 'common/gpu/client/gpu_memory_buffer_impl_io_surface.cc', @@ -753,8 +752,8 @@ '../media/media.gyp:media', ], 'sources': [ - 'common/gpu/media/generic_v4l2_video_device.cc', - 'common/gpu/media/generic_v4l2_video_device.h', + 'common/gpu/media/exynos_v4l2_video_device.cc', + 'common/gpu/media/exynos_v4l2_video_device.h', 'common/gpu/media/tegra_v4l2_video_device.cc', 'common/gpu/media/tegra_v4l2_video_device.h', 'common/gpu/media/v4l2_image_processor.cc',
diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi index cea46f0..5d01d94 100644 --- a/content/content_renderer.gypi +++ b/content/content_renderer.gypi
@@ -53,6 +53,7 @@ 'public/renderer/navigation_state.h', 'public/renderer/pepper_plugin_instance.h', 'public/renderer/platform_event_observer.h', + 'public/renderer/plugin_power_saver_helper.h', 'public/renderer/renderer_ppapi_host.h', 'public/renderer/render_frame.h', 'public/renderer/render_frame_observer.cc', @@ -201,6 +202,8 @@ 'renderer/input/input_handler_wrapper.h', 'renderer/input/input_scroll_elasticity_controller.cc', 'renderer/input/input_scroll_elasticity_controller.h', + 'renderer/input/main_thread_input_event_filter.cc', + 'renderer/input/main_thread_input_event_filter.h', 'renderer/internal_document_state_data.cc', 'renderer/internal_document_state_data.h', 'renderer/java/gin_java_bridge_dispatcher.cc', @@ -504,8 +507,8 @@ 'renderer/pepper/plugin_module.h', 'renderer/pepper/plugin_object.cc', 'renderer/pepper/plugin_object.h', - 'renderer/pepper/plugin_power_saver_helper.cc', - 'renderer/pepper/plugin_power_saver_helper.h', + 'renderer/pepper/plugin_power_saver_helper_impl.cc', + 'renderer/pepper/plugin_power_saver_helper_impl.h', 'renderer/pepper/ppapi_preferences_builder.cc', 'renderer/pepper/ppapi_preferences_builder.h', 'renderer/pepper/ppb_audio_impl.cc', @@ -822,6 +825,9 @@ 'renderer/media/crypto/renderer_cdm_manager.h', ], }], + ['use_seccomp_bpf==1', { + 'defines': ['USE_SECCOMP_BPF'], + }], ], 'target_conditions': [ ['OS=="android"', {
diff --git a/content/public/android/BUILD.gn b/content/public/android/BUILD.gn index 94bb8780..f393c70b 100644 --- a/content/public/android/BUILD.gn +++ b/content/public/android/BUILD.gn
@@ -49,11 +49,6 @@ ] DEPRECATED_java_in_dir = "java/src" - if (!is_android_webview_build) { - deps += [ - "//third_party/eyesfree:eyesfree_java", - ] - } } java_strings_grd("content_strings_grd") {
diff --git a/content/public/android/java/src/org/chromium/content/browser/InterstitialPageDelegateAndroid.java b/content/public/android/java/src/org/chromium/content/browser/InterstitialPageDelegateAndroid.java index 299e1b34..0b3173a7 100644 --- a/content/public/android/java/src/org/chromium/content/browser/InterstitialPageDelegateAndroid.java +++ b/content/public/android/java/src/org/chromium/content/browser/InterstitialPageDelegateAndroid.java
@@ -6,6 +6,7 @@ import org.chromium.base.CalledByNative; import org.chromium.base.JNINamespace; +import org.chromium.base.VisibleForTesting; /** * Allows the specification and handling of Interstitial pages in java. @@ -20,6 +21,7 @@ * * @param htmlContent The HTML content for the interstitial. */ + @VisibleForTesting public InterstitialPageDelegateAndroid(String htmlContent) { mNativePtr = nativeInit(htmlContent); } @@ -27,6 +29,7 @@ /** * @return The pointer to the underlying native counterpart. */ + @VisibleForTesting public long getNative() { return mNativePtr; }
diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/AccessibilityInjector.java b/content/public/android/java/src/org/chromium/content/browser/accessibility/AccessibilityInjector.java index 802a656..c7d6b55 100644 --- a/content/public/android/java/src/org/chromium/content/browser/accessibility/AccessibilityInjector.java +++ b/content/public/android/java/src/org/chromium/content/browser/accessibility/AccessibilityInjector.java
@@ -11,14 +11,10 @@ import android.os.Bundle; import android.os.Vibrator; import android.speech.tts.TextToSpeech; -import android.util.Log; import android.view.View; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeInfo; -import com.googlecode.eyesfree.braille.selfbraille.SelfBrailleClient; -import com.googlecode.eyesfree.braille.selfbraille.WriteData; - import org.apache.http.NameValuePair; import org.apache.http.client.utils.URLEncodedUtils; import org.chromium.base.CommandLine; @@ -39,8 +35,6 @@ * Responsible for accessibility injection and management of a {@link ContentViewCore}. */ public class AccessibilityInjector extends WebContentsObserver { - private static final String TAG = "AccessibilityInjector"; - // The ContentView this injector is responsible for managing. protected ContentViewCore mContentViewCore; @@ -401,14 +395,11 @@ */ protected static class TextToSpeechWrapper { protected final TextToSpeech mTextToSpeech; - private final SelfBrailleClient mSelfBrailleClient; private final View mView; protected TextToSpeechWrapper(View view, Context context) { mView = view; mTextToSpeech = new TextToSpeech(context, null, null); - mSelfBrailleClient = new SelfBrailleClient(context, CommandLine.getInstance().hasSwitch( - ContentSwitches.ACCESSIBILITY_DEBUG_BRAILLE_SERVICE)); } @JavascriptInterface @@ -455,23 +446,13 @@ @JavascriptInterface @SuppressWarnings("unused") public void braille(String jsonString) { - try { - JSONObject jsonObj = new JSONObject(jsonString); - - WriteData data = WriteData.forView(mView); - data.setText(jsonObj.getString("text")); - data.setSelectionStart(jsonObj.getInt("startIndex")); - data.setSelectionEnd(jsonObj.getInt("endIndex")); - mSelfBrailleClient.write(data); - } catch (JSONException ex) { - Log.w(TAG, "Error parsing JS JSON object", ex); - } + // This is here because AndroidVox depends on the existence + // of this method. } @SuppressWarnings("unused") protected void shutdownInternal() { mTextToSpeech.shutdown(); - mSelfBrailleClient.shutdown(); } } }
diff --git a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java index 08d8ac3..b05fe76 100644 --- a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java +++ b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
@@ -6,6 +6,7 @@ import org.chromium.base.CalledByNative; import org.chromium.base.JNINamespace; +import org.chromium.base.VisibleForTesting; import org.chromium.content_public.browser.JavaScriptCallback; import org.chromium.content_public.browser.NavigationController; import org.chromium.content_public.browser.NavigationTransitionDelegate; @@ -109,6 +110,7 @@ nativeAddStyleSheetByURL(mNativeWebContentsAndroid, url); } + @VisibleForTesting @Override public void showInterstitialPage( String url, long interstitialPageDelegateAndroid) {
diff --git a/content/public/android/java/src/org/chromium/content/common/ContentSwitches.java b/content/public/android/java/src/org/chromium/content/common/ContentSwitches.java index ed9cfac..5145b4f7 100644 --- a/content/public/android/java/src/org/chromium/content/common/ContentSwitches.java +++ b/content/public/android/java/src/org/chromium/content/common/ContentSwitches.java
@@ -27,10 +27,6 @@ // Change the url of the JavaScript that gets injected when accessibility mode is enabled. public static final String ACCESSIBILITY_JAVASCRIPT_URL = "accessibility-js-url"; - // Whether to ignore signature mismatches when connecting to BrailleBack's - // SelfBrailleService. - public static final String ACCESSIBILITY_DEBUG_BRAILLE_SERVICE = "debug-braille-service"; - // Indicates Chrome is running for performance benchmark. public static final String RUNNING_PERFORMANCE_BENCHMARK = "running-performance-benchmark";
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBasicsTest.java b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBasicsTest.java index 6745a408..768f4c63 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBasicsTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/JavaBridgeBasicsTest.java
@@ -172,15 +172,27 @@ @SmallTest @Feature({"AndroidWebView", "Android-JavaBridge"}) public void testRemovalNotReflectedUntilReload() throws Throwable { - injectObjectAndReload(new Object(), "testObject"); + injectObjectAndReload(new Object() { + public void method() { + mTestController.setStringValue("I'm here"); + } + }, "testObject"); assertEquals("object", executeJavaScriptAndGetStringResult("typeof testObject")); + executeJavaScript("testObject.method()"); + assertEquals("I'm here", mTestController.waitForStringValue()); runTestOnUiThread(new Runnable() { @Override public void run() { getContentViewCore().removeJavascriptInterface("testObject"); } }); + // Check that the Java object is being held by the Java bridge, thus it's not + // collected. Note that despite that what JavaDoc says about invoking "gc()", both Dalvik + // and ART actually run the collector if called via Runtime. + Runtime.getRuntime().gc(); assertEquals("object", executeJavaScriptAndGetStringResult("typeof testObject")); + executeJavaScript("testObject.method()"); + assertEquals("I'm here", mTestController.waitForStringValue()); synchronousPageReload(); assertEquals("undefined", executeJavaScriptAndGetStringResult("typeof testObject")); }
diff --git a/content/public/browser/devtools_http_handler.h b/content/public/browser/devtools_http_handler.h index 01a97fa..25dc327 100644 --- a/content/public/browser/devtools_http_handler.h +++ b/content/public/browser/devtools_http_handler.h
@@ -72,8 +72,8 @@ DevToolsHttpHandlerDelegate* delegate, const base::FilePath& active_port_output_directory); - // Returns the URL for the address to debug |agent_host|. - virtual GURL GetFrontendURL() = 0; + // Returns the URL for the file at |path| in frontend. + virtual GURL GetFrontendURL(const std::string& path) = 0; virtual ~DevToolsHttpHandler() {} };
diff --git a/content/public/browser/push_messaging_service.h b/content/public/browser/push_messaging_service.h index d0cd124..caa0031 100644 --- a/content/public/browser/push_messaging_service.h +++ b/content/public/browser/push_messaging_service.h
@@ -19,28 +19,51 @@ // push messaging services like GCM. class CONTENT_EXPORT PushMessagingService { public: - typedef base::Callback<void(const GURL& /* endpoint */, - const std::string& /* registration_id */, + typedef base::Callback<void(const std::string& /* registration_id */, PushRegistrationStatus /* status */)> RegisterCallback; virtual ~PushMessagingService() {} - // Register the given |sender_id| with GCM. - virtual void Register(const GURL& origin, - int64 service_worker_registration_id, - const std::string& sender_id, - int renderer_id, - int render_frame_id, - bool user_gesture, - const RegisterCallback& callback) = 0; + // Returns the absolute URL exposed by the push server where the webapp server + // can send push messages. This is currently assumed to be the same for all + // origins and push registrations. + virtual GURL PushEndpoint() = 0; + + // Register the given |sender_id| with the push messaging service in a + // document context. The frame is known and a permission UI may be displayed + // to the user. + virtual void RegisterFromDocument(const GURL& requesting_origin, + int64 service_worker_registration_id, + const std::string& sender_id, + int renderer_id, + int render_frame_id, + bool user_gesture, + const RegisterCallback& callback) = 0; + + // Register the given |sender_id| with the push messaging service. The frame + // is not known so if permission was not previously granted by the user this + // request should fail. + virtual void RegisterFromWorker(const GURL& requesting_origin, + int64 service_worker_registration_id, + const std::string& sender_id, + const RegisterCallback& callback) = 0; // Check whether the requester has permission to register for Push // Messages + // TODO(mvanouwerkerk): Delete once the Push API flows through platform. + // https://crbug.com/389194 virtual blink::WebPushPermissionStatus GetPermissionStatus( const GURL& requesting_origin, int renderer_id, int render_frame_id) = 0; + + // Checks the permission status for the requesting origin. Permission is only + // ever granted when the requesting origin matches the top level embedding + // origin. + virtual blink::WebPushPermissionStatus GetPermissionStatus( + const GURL& requesting_origin, + const GURL& embedding_origin) = 0; }; } // namespace content
diff --git a/content/public/browser/render_process_host.h b/content/public/browser/render_process_host.h index 4ae7f3a2..dcec7d8 100644 --- a/content/public/browser/render_process_host.h +++ b/content/public/browser/render_process_host.h
@@ -42,14 +42,11 @@ // Details for RENDERER_PROCESS_CLOSED notifications. struct RendererClosedDetails { - RendererClosedDetails(base::ProcessHandle handle, - base::TerminationStatus status, + RendererClosedDetails(base::TerminationStatus status, int exit_code) { - this->handle = handle; this->status = status; this->exit_code = exit_code; } - base::ProcessHandle handle; base::TerminationStatus status; int exit_code; };
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h index ceef6a4eb..680213f 100644 --- a/content/public/common/content_switches.h +++ b/content/public/common/content_switches.h
@@ -126,9 +126,9 @@ CONTENT_EXPORT extern const char kEnableRegionBasedColumns[]; CONTENT_EXPORT extern const char kEnableRendererMojoChannel[]; CONTENT_EXPORT extern const char kEnableSandboxLogging[]; -extern const char kEnableSeccompFilterSandbox[]; +CONTENT_EXPORT extern const char kEnableSeccompFilterSandbox[]; extern const char kEnableSkiaBenchmarking[]; -extern const char kEnableSlimmingPaint[]; +CONTENT_EXPORT extern const char kEnableSlimmingPaint[]; CONTENT_EXPORT extern const char kEnableSmoothScrolling[]; CONTENT_EXPORT extern const char kEnableSpatialNavigation[]; CONTENT_EXPORT extern const char kEnableStatsTable[];
diff --git a/content/public/renderer/plugin_power_saver_helper.h b/content/public/renderer/plugin_power_saver_helper.h new file mode 100644 index 0000000..1b780e7 --- /dev/null +++ b/content/public/renderer/plugin_power_saver_helper.h
@@ -0,0 +1,44 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_PUBLIC_RENDERER_PLUGIN_POWER_SAVER_HELPER_H_ +#define CONTENT_PUBLIC_RENDERER_PLUGIN_POWER_SAVER_HELPER_H_ + +#include "base/callback_forward.h" +#include "content/common/content_export.h" + +class GURL; + +namespace blink { +struct WebPluginParams; +} + +namespace content { + +// PluginPowerSaverHelper manages the plugin content origin whitelist for +// a single RenderFrame. +class CONTENT_EXPORT PluginPowerSaverHelper { + public: + virtual ~PluginPowerSaverHelper() {} + + // Returns the absolute URL of the poster image if all the following are true: + // a) Power Saver feature is enabled. + // b) This plugin instance has a poster image. + // c) The content origin and dimensions imply throttling is needed. + // Returns an empty GURL otherwise. + virtual GURL GetPluginInstancePosterImage( + const blink::WebPluginParams& params, + const GURL& base_url) const = 0; + + // Registers a plugin that has been marked peripheral. If the origin + // whitelist is later updated and includes |content_origin|, then + // |unthrottle_callback| will be called. + virtual void RegisterPeripheralPlugin( + const GURL& content_origin, + const base::Closure& unthrottle_callback) = 0; +}; + +} // namespace content + +#endif // CONTENT_RENDERER_PEPPER_PLUGIN_POWER_SAVER_HELPER_H_
diff --git a/content/public/renderer/render_frame.h b/content/public/renderer/render_frame.h index 5a619ad..5042a91 100644 --- a/content/public/renderer/render_frame.h +++ b/content/public/renderer/render_frame.h
@@ -33,6 +33,7 @@ namespace content { class ContextMenuClient; +class PluginPowerSaverHelper; class RenderView; class ServiceRegistry; struct ContextMenuParams; @@ -108,6 +109,11 @@ // Returns the ServiceRegistry for this frame. virtual ServiceRegistry* GetServiceRegistry() = 0; +#if defined(ENABLE_PLUGINS) + // Returns the PluginPowerSaverHelper for this frame. + virtual PluginPowerSaverHelper* GetPluginPowerSaverHelper() = 0; +#endif + // Returns true if this frame is a FTP directory listing. virtual bool IsFTPDirectoryListing() = 0;
diff --git a/content/public/test/content_test_suite_base.cc b/content/public/test/content_test_suite_base.cc index 4144d30..afaeea7 100644 --- a/content/public/test/content_test_suite_base.cc +++ b/content/public/test/content_test_suite_base.cc
@@ -29,6 +29,7 @@ #include "base/android/jni_android.h" #include "content/browser/android/browser_jni_registrar.h" #include "content/common/android/common_jni_registrar.h" +#include "content/public/browser/android/compositor.h" #include "media/base/android/media_jni_registrar.h" #include "net/android/net_jni_registrar.h" #include "ui/base/android/ui_base_jni_registrar.h" @@ -85,6 +86,8 @@ ui::android::RegisterJni(env); ui::gl::android::RegisterJni(env); ui::shell_dialogs::RegisterJni(env); + + content::Compositor::Initialize(); #endif #if defined(USE_OZONE)
diff --git a/content/public/test/test_renderer_host.cc b/content/public/test/test_renderer_host.cc index 28735e4..d8faf26 100644 --- a/content/public/test/test_renderer_host.cc +++ b/content/public/test/test_renderer_host.cc
@@ -4,6 +4,7 @@ #include "content/public/test/test_renderer_host.h" +#include "base/command_line.h" #include "base/run_loop.h" #include "content/browser/frame_host/navigation_entry_impl.h" #include "content/browser/renderer_host/render_view_host_factory.h" @@ -11,8 +12,10 @@ #include "content/browser/site_instance_impl.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/web_contents.h" +#include "content/public/common/content_switches.h" #include "content/public/test/mock_render_process_host.h" #include "content/public/test/test_browser_context.h" +#include "content/test/browser_side_navigation_test_utils.h" #include "content/test/test_render_frame_host.h" #include "content/test/test_render_frame_host_factory.h" #include "content/test/test_render_view_host.h" @@ -193,9 +196,19 @@ browser_context_.reset(CreateBrowserContext()); SetContents(CreateTestWebContents()); + + if (CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableBrowserSideNavigation)) { + BrowserSideNavigationSetUp(); + } } void RenderViewHostTestHarness::TearDown() { + if (CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableBrowserSideNavigation)) { + BrowserSideNavigationTearDown(); + } + SetContents(NULL); #if defined(USE_AURA) aura_test_helper_->TearDown();
diff --git a/content/renderer/accessibility/blink_ax_enum_conversion.cc b/content/renderer/accessibility/blink_ax_enum_conversion.cc index 3f201cce..97ec0da 100644 --- a/content/renderer/accessibility/blink_ax_enum_conversion.cc +++ b/content/renderer/accessibility/blink_ax_enum_conversion.cc
@@ -73,8 +73,10 @@ if (o.isEnabled()) state |= (1 << ui::AX_STATE_ENABLED); - if (o.isVertical()) + if (o.orientation() == blink::WebAXOrientationVertical) state |= (1 << ui::AX_STATE_VERTICAL); + else if (o.orientation() == blink::WebAXOrientationHorizontal) + state |= (1 << ui::AX_STATE_HORIZONTAL); if (o.isVisited()) state |= (1 << ui::AX_STATE_VISITED); @@ -144,8 +146,6 @@ return ui::AX_ROLE_DIV; case blink::WebAXRoleDocument: return ui::AX_ROLE_DOCUMENT; - case blink::WebAXRoleEditableText: - return ui::AX_ROLE_EDITABLE_TEXT; case blink::WebAXRoleEmbeddedObject: return ui::AX_ROLE_EMBEDDED_OBJECT; case blink::WebAXRoleFigcaption: @@ -160,8 +160,6 @@ return ui::AX_ROLE_GRID; case blink::WebAXRoleGroup: return ui::AX_ROLE_GROUP; - case blink::WebAXRoleGrowArea: - return ui::AX_ROLE_GROW_AREA; case blink::WebAXRoleHeading: return ui::AX_ROLE_HEADING; case blink::WebAXRoleIframe: @@ -270,8 +268,6 @@ return ui::AX_ROLE_SPIN_BUTTON; case blink::WebAXRoleSpinButtonPart: return ui::AX_ROLE_SPIN_BUTTON_PART; - case blink::WebAXRoleSplitGroup: - return ui::AX_ROLE_SPLIT_GROUP; case blink::WebAXRoleSplitter: return ui::AX_ROLE_SPLITTER; case blink::WebAXRoleStaticText:
diff --git a/content/renderer/accessibility/blink_ax_tree_source.cc b/content/renderer/accessibility/blink_ax_tree_source.cc index 09607472..c55d3266 100644 --- a/content/renderer/accessibility/blink_ax_tree_source.cc +++ b/content/renderer/accessibility/blink_ax_tree_source.cc
@@ -337,8 +337,7 @@ dst->html_attributes.push_back(std::make_pair(name, value)); } - if (dst->role == ui::AX_ROLE_EDITABLE_TEXT || - dst->role == ui::AX_ROLE_TEXT_AREA || + if (dst->role == ui::AX_ROLE_TEXT_AREA || dst->role == ui::AX_ROLE_TEXT_FIELD) { dst->AddIntAttribute(ui::AX_ATTR_TEXT_SEL_START, src.selectionStart()); dst->AddIntAttribute(ui::AX_ATTR_TEXT_SEL_END, src.selectionEnd());
diff --git a/content/renderer/gpu/compositor_forwarding_message_filter_unittest.cc b/content/renderer/gpu/compositor_forwarding_message_filter_unittest.cc index 6a21a84b..97f67a36 100644 --- a/content/renderer/gpu/compositor_forwarding_message_filter_unittest.cc +++ b/content/renderer/gpu/compositor_forwarding_message_filter_unittest.cc
@@ -44,7 +44,8 @@ new base::TestSimpleTaskRunner); int route_id = 0; - ViewMsg_BeginFrame msg(route_id, cc::CreateBeginFrameArgsForTesting()); + ViewMsg_BeginFrame msg( + route_id, cc::CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE)); CompositorForwardingMessageFilter::Handler plus_handler = base::Bind(&CompositorForwardingMessageFilterTestHandler::OnPlusMethod,
diff --git a/content/renderer/gpu/render_widget_compositor.cc b/content/renderer/gpu/render_widget_compositor.cc index 33e98f8..5aab6d1c 100644 --- a/content/renderer/gpu/render_widget_compositor.cc +++ b/content/renderer/gpu/render_widget_compositor.cc
@@ -184,6 +184,7 @@ settings.report_overscroll_only_for_scrollable_axes = true; settings.accelerated_animation_enabled = !cmd->HasSwitch(cc::switches::kDisableThreadedAnimation); + settings.use_display_lists = cmd->HasSwitch(switches::kEnableSlimmingPaint); settings.default_tile_size = CalculateDefaultTileSize(); if (cmd->HasSwitch(switches::kDefaultTileWidth)) {
diff --git a/content/renderer/gpu/render_widget_compositor_unittest.cc b/content/renderer/gpu/render_widget_compositor_unittest.cc index 642aae3..6a7a8cc 100644 --- a/content/renderer/gpu/render_widget_compositor_unittest.cc +++ b/content/renderer/gpu/render_widget_compositor_unittest.cc
@@ -62,8 +62,9 @@ base::TimeDelta::FromSeconds(1)); base::TimeTicks deadline(base::TimeTicks() + base::TimeDelta::FromSeconds(2)); base::TimeDelta interval(base::TimeDelta::FromSeconds(3)); - cc::BeginFrameArgs args(cc::BeginFrameArgs::Create( - frame_time, deadline, interval, cc::BeginFrameArgs::NORMAL)); + cc::BeginFrameArgs args( + cc::BeginFrameArgs::Create(BEGINFRAME_FROM_HERE, frame_time, deadline, + interval, cc::BeginFrameArgs::NORMAL)); EXPECT_CALL(render_widget_->mock_webwidget_, beginFrame(AllOf(
diff --git a/content/renderer/input/input_event_filter.cc b/content/renderer/input/input_event_filter.cc index d2e4f7fd..ff9da937 100644 --- a/content/renderer/input/input_event_filter.cc +++ b/content/renderer/input/input_event_filter.cc
@@ -40,7 +40,7 @@ namespace content { InputEventFilter::InputEventFilter( - IPC::Listener* main_listener, + const base::Callback<void(const IPC::Message&)>& main_listener, const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner, const scoped_refptr<base::MessageLoopProxy>& target_loop) : main_task_runner_(main_task_runner), @@ -127,10 +127,6 @@ DCHECK(!current_overscroll_params_); } -void InputEventFilter::ForwardToMainListener(const IPC::Message& message) { - main_listener_->OnMessageReceived(message); -} - void InputEventFilter::ForwardToHandler(const IPC::Message& message) { DCHECK(!handler_.is_null()); DCHECK(target_loop_->BelongsToCurrentThread()); @@ -142,9 +138,7 @@ "input", "InputEventFilter::ForwardToHandler::ForwardToMainListener", TRACE_EVENT_SCOPE_THREAD); - main_task_runner_->PostTask( - FROM_HERE, - base::Bind(&InputEventFilter::ForwardToMainListener, this, message)); + main_task_runner_->PostTask(FROM_HERE, base::Bind(main_listener_, message)); return; } @@ -176,9 +170,7 @@ TRACE_EVENT_SCOPE_THREAD); IPC::Message new_msg = InputMsg_HandleInputEvent( routing_id, event, latency_info, is_keyboard_shortcut); - main_task_runner_->PostTask( - FROM_HERE, - base::Bind(&InputEventFilter::ForwardToMainListener, this, new_msg)); + main_task_runner_->PostTask(FROM_HERE, base::Bind(main_listener_, new_msg)); return; }
diff --git a/content/renderer/input/input_event_filter.h b/content/renderer/input/input_event_filter.h index 19eac67..e58798d 100644 --- a/content/renderer/input/input_event_filter.h +++ b/content/renderer/input/input_event_filter.h
@@ -8,7 +8,7 @@ #include <queue> #include <set> -#include "base/callback_forward.h" +#include "base/callback.h" #include "base/synchronization/lock.h" #include "content/common/content_export.h" #include "content/common/input/input_event_ack_state.h" @@ -40,7 +40,7 @@ public IPC::MessageFilter { public: InputEventFilter( - IPC::Listener* main_listener, + const base::Callback<void(const IPC::Message&)>& main_listener, const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner, const scoped_refptr<base::MessageLoopProxy>& target_loop); @@ -71,13 +71,12 @@ private: ~InputEventFilter() override; - void ForwardToMainListener(const IPC::Message& message); void ForwardToHandler(const IPC::Message& message); void SendMessage(scoped_ptr<IPC::Message> message); void SendMessageOnIOThread(scoped_ptr<IPC::Message> message); scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; - IPC::Listener* main_listener_; + base::Callback<void(const IPC::Message&)> main_listener_; // The sender_ only gets invoked on the thread corresponding to io_loop_. scoped_refptr<base::MessageLoopProxy> io_loop_;
diff --git a/content/renderer/input/input_event_filter_unittest.cc b/content/renderer/input/input_event_filter_unittest.cc index b7befdb..df08796 100644 --- a/content/renderer/input/input_event_filter_unittest.cc +++ b/content/renderer/input/input_event_filter_unittest.cc
@@ -126,19 +126,18 @@ class InputEventFilterTest : public testing::Test { public: void SetUp() override { - filter_ = new InputEventFilter(&message_recorder_, - base::MessageLoopProxy::current(), - message_loop_.message_loop_proxy()); - filter_->SetBoundHandler( - base::Bind(&InputEventRecorder::HandleInputEvent, - base::Unretained(&event_recorder_))); + filter_ = new InputEventFilter( + base::Bind(base::IgnoreResult(&IPCMessageRecorder::OnMessageReceived), + base::Unretained(&message_recorder_)), + base::MessageLoopProxy::current(), message_loop_.message_loop_proxy()); + filter_->SetBoundHandler(base::Bind(&InputEventRecorder::HandleInputEvent, + base::Unretained(&event_recorder_))); event_recorder_.set_filter(filter_.get()); filter_->OnFilterAdded(&ipc_sink_); } - protected: base::MessageLoop message_loop_;
diff --git a/content/renderer/input/main_thread_input_event_filter.cc b/content/renderer/input/main_thread_input_event_filter.cc new file mode 100644 index 0000000..cd6c2ea --- /dev/null +++ b/content/renderer/input/main_thread_input_event_filter.cc
@@ -0,0 +1,40 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/renderer/input/main_thread_input_event_filter.h" + +#include "base/bind.h" +#include "base/location.h" +#include "base/single_thread_task_runner.h" +#include "content/common/input_messages.h" +#include "ipc/ipc_listener.h" + +namespace content { + +MainThreadInputEventFilter::MainThreadInputEventFilter( + const base::Callback<void(const IPC::Message&)>& main_listener, + const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner) + : main_listener_(main_listener), main_task_runner_(main_task_runner) { + DCHECK(main_task_runner.get()); +} + +bool MainThreadInputEventFilter::OnMessageReceived( + const IPC::Message& message) { + DCHECK_EQ(static_cast<int>(IPC_MESSAGE_ID_CLASS(message.type())), + InputMsgStart); + bool handled = main_task_runner_->PostTask( + FROM_HERE, base::Bind(main_listener_, message)); + return handled; +} + +bool MainThreadInputEventFilter::GetSupportedMessageClasses( + std::vector<uint32>* supported_message_classes) const { + supported_message_classes->push_back(InputMsgStart); + return true; +} + +MainThreadInputEventFilter::~MainThreadInputEventFilter() { +} + +} // namespace content
diff --git a/content/renderer/input/main_thread_input_event_filter.h b/content/renderer/input/main_thread_input_event_filter.h new file mode 100644 index 0000000..f540a9cd --- /dev/null +++ b/content/renderer/input/main_thread_input_event_filter.h
@@ -0,0 +1,45 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_RENDERER_INPUT_MAIN_THREAD_INPUT_EVENT_FILTER_H_ +#define CONTENT_RENDERER_INPUT_MAIN_THREAD_INPUT_EVENT_FILTER_H_ + +#include "base/callback.h" +#include "ipc/message_filter.h" + +namespace base { +class SingleThreadTaskRunner; +} + +namespace IPC { +class Listener; +} + +namespace content { + +// Used to intercept InputMsg* messages and deliver them to the given listener +// via the provided main thread task runner. Note that usage should be +// restricted to cases where compositor-thread event filtering (via +// |InputEventFilter|) is disabled or otherwise unavailable. +class MainThreadInputEventFilter : public IPC::MessageFilter { + public: + MainThreadInputEventFilter( + const base::Callback<void(const IPC::Message&)>& main_listener, + const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner); + + // IPC::MessageFilter implementation. + bool OnMessageReceived(const IPC::Message& message) override; + bool GetSupportedMessageClasses( + std::vector<uint32>* supported_message_classes) const override; + + private: + ~MainThreadInputEventFilter() override; + + base::Callback<void(const IPC::Message&)> main_listener_; + scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; +}; + +} // namespace content + +#endif // CONTENT_RENDERER_INPUT_MAIN_THREAD_INPUT_EVENT_FILTER_H_
diff --git a/content/renderer/media/android/media_source_delegate.cc b/content/renderer/media/android/media_source_delegate.cc index 3422fc9a..c5229c4 100644 --- a/content/renderer/media/android/media_source_delegate.cc +++ b/content/renderer/media/android/media_source_delegate.cc
@@ -667,13 +667,13 @@ chunk_demuxer_.get(), base::Bind(&LogMediaSourceError, media_log_))); } -void MediaSourceDelegate::OnNeedKey(const std::string& type, +void MediaSourceDelegate::OnNeedKey(const std::string& init_data_type, const std::vector<uint8>& init_data) { DCHECK(main_task_runner_->BelongsToCurrentThread()); if (need_key_cb_.is_null()) return; - need_key_cb_.Run(type, init_data); + need_key_cb_.Run(init_data_type, init_data); } bool MediaSourceDelegate::IsSeeking() const {
diff --git a/content/renderer/media/android/media_source_delegate.h b/content/renderer/media/android/media_source_delegate.h index c451e07..e4d9e85e 100644 --- a/content/renderer/media/android/media_source_delegate.h +++ b/content/renderer/media/android/media_source_delegate.h
@@ -136,7 +136,7 @@ void FinishResettingDecryptingDemuxerStreams(); void OnDemuxerOpened(); - void OnNeedKey(const std::string& type, + void OnNeedKey(const std::string& init_data_type, const std::vector<uint8>& init_data); void NotifyDemuxerReady();
diff --git a/content/renderer/media/android/webmediaplayer_android.cc b/content/renderer/media/android/webmediaplayer_android.cc index 4120b36..c2f0dd6 100644 --- a/content/renderer/media/android/webmediaplayer_android.cc +++ b/content/renderer/media/android/webmediaplayer_android.cc
@@ -1731,7 +1731,7 @@ client_->mediaSourceOpened(web_media_source); } -void WebMediaPlayerAndroid::OnNeedKey(const std::string& type, +void WebMediaPlayerAndroid::OnNeedKey(const std::string& init_data_type, const std::vector<uint8>& init_data) { DCHECK(main_thread_checker_.CalledOnValidThread()); @@ -1743,13 +1743,16 @@ UMA_HISTOGRAM_COUNTS(kMediaEme + std::string("NeedKey"), 1); - DCHECK(init_data_type_.empty() || type.empty() || type == init_data_type_); + DCHECK(!init_data_type.empty()); + DLOG_IF(WARNING, + !init_data_type_.empty() && init_data_type != init_data_type_) + << "Mixed init data type not supported. The new type is ignored."; if (init_data_type_.empty()) - init_data_type_ = type; + init_data_type_ = init_data_type; const uint8* init_data_ptr = init_data.empty() ? NULL : &init_data[0]; - client_->encrypted( - WebString::fromUTF8(type), init_data_ptr, init_data.size()); + client_->encrypted(WebString::fromUTF8(init_data_type), init_data_ptr, + init_data.size()); } void WebMediaPlayerAndroid::SetDecryptorReadyCB(
diff --git a/content/renderer/media/android/webmediaplayer_android.h b/content/renderer/media/android/webmediaplayer_android.h index 8b00378..1134693 100644 --- a/content/renderer/media/android/webmediaplayer_android.h +++ b/content/renderer/media/android/webmediaplayer_android.h
@@ -254,12 +254,9 @@ void OnMediaSourceOpened(blink::WebMediaSource* web_media_source); - void OnNeedKey(const std::string& type, + void OnNeedKey(const std::string& init_data_type, const std::vector<uint8>& init_data); - // TODO(xhwang): Implement WebMediaPlayer::setContentDecryptionModule(). - // See: http://crbug.com/224786 - protected: // Helper method to update the playing state. void UpdatePlayingState(bool is_playing_);
diff --git a/content/renderer/media/renderer_gpu_video_accelerator_factories.cc b/content/renderer/media/renderer_gpu_video_accelerator_factories.cc index ab3d2f7..9c24682 100644 --- a/content/renderer/media/renderer_gpu_video_accelerator_factories.cc +++ b/content/renderer/media/renderer_gpu_video_accelerator_factories.cc
@@ -235,10 +235,14 @@ gl_helper->DeleteTexture(tmp_texture); } -base::SharedMemory* RendererGpuVideoAcceleratorFactories::CreateSharedMemory( - size_t size) { +scoped_ptr<base::SharedMemory> +RendererGpuVideoAcceleratorFactories::CreateSharedMemory(size_t size) { DCHECK(task_runner_->BelongsToCurrentThread()); - return ChildThread::AllocateSharedMemory(size, thread_safe_sender_.get()); + scoped_ptr<base::SharedMemory> mem( + ChildThread::AllocateSharedMemory(size, thread_safe_sender_.get())); + if (mem && !mem->Map(size)) + return nullptr; + return mem; } scoped_refptr<base::SingleThreadTaskRunner>
diff --git a/content/renderer/media/renderer_gpu_video_accelerator_factories.h b/content/renderer/media/renderer_gpu_video_accelerator_factories.h index 4723230..dccabfab 100644 --- a/content/renderer/media/renderer_gpu_video_accelerator_factories.h +++ b/content/renderer/media/renderer_gpu_video_accelerator_factories.h
@@ -61,7 +61,7 @@ void ReadPixels(uint32 texture_id, const gfx::Rect& visible_rect, const SkBitmap& pixels) override; - base::SharedMemory* CreateSharedMemory(size_t size) override; + scoped_ptr<base::SharedMemory> CreateSharedMemory(size_t size) override; scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner() override; std::vector<media::VideoEncodeAccelerator::SupportedProfile> GetVideoEncodeAcceleratorSupportedProfiles() override;
diff --git a/content/renderer/media/rtc_video_decoder.cc b/content/renderer/media/rtc_video_decoder.cc index 60ae893d..0cc66a7 100644 --- a/content/renderer/media/rtc_video_decoder.cc +++ b/content/renderer/media/rtc_video_decoder.cc
@@ -48,16 +48,19 @@ // of |shm|. class RTCVideoDecoder::SHMBuffer { public: - SHMBuffer(base::SharedMemory* shm, size_t size); + SHMBuffer(scoped_ptr<base::SharedMemory> shm, size_t size); ~SHMBuffer(); - base::SharedMemory* const shm; + scoped_ptr<base::SharedMemory> const shm; const size_t size; }; -RTCVideoDecoder::SHMBuffer::SHMBuffer(base::SharedMemory* shm, size_t size) - : shm(shm), size(size) {} +RTCVideoDecoder::SHMBuffer::SHMBuffer(scoped_ptr<base::SharedMemory> shm, + size_t size) + : shm(shm.Pass()), size(size) { +} -RTCVideoDecoder::SHMBuffer::~SHMBuffer() { shm->Close(); } +RTCVideoDecoder::SHMBuffer::~SHMBuffer() { +} RTCVideoDecoder::BufferData::BufferData(int32 bitstream_buffer_id, uint32_t timestamp, @@ -761,12 +764,13 @@ } size_t size_to_allocate = std::max(min_size, kSharedMemorySegmentBytes); for (int i = 0; i < number_to_allocate; i++) { - base::SharedMemory* shm = factories_->CreateSharedMemory(size_to_allocate); - if (shm != NULL) { + scoped_ptr<base::SharedMemory> shm = + factories_->CreateSharedMemory(size_to_allocate); + if (shm) { base::AutoLock auto_lock(lock_); num_shm_buffers_++; PutSHM_Locked( - scoped_ptr<SHMBuffer>(new SHMBuffer(shm, size_to_allocate))); + scoped_ptr<SHMBuffer>(new SHMBuffer(shm.Pass(), size_to_allocate))); } } // Kick off the decoding.
diff --git a/content/renderer/media/rtc_video_decoder_unittest.cc b/content/renderer/media/rtc_video_decoder_unittest.cc index da1804d..dcb9c4f 100644 --- a/content/renderer/media/rtc_video_decoder_unittest.cc +++ b/content/renderer/media/rtc_video_decoder_unittest.cc
@@ -39,8 +39,6 @@ .WillRepeatedly(Return(vda_task_runner_)); EXPECT_CALL(*mock_gpu_factories_.get(), DoCreateVideoDecodeAccelerator()) .WillRepeatedly(Return(mock_vda_)); - EXPECT_CALL(*mock_gpu_factories_.get(), CreateSharedMemory(_)) - .WillRepeatedly(Return(static_cast<base::SharedMemory*>(NULL))); EXPECT_CALL(*mock_vda_, Initialize(_, _)) .Times(1) .WillRepeatedly(Return(true));
diff --git a/content/renderer/media/rtc_video_encoder.cc b/content/renderer/media/rtc_video_encoder.cc index e1119d9..c64e9df 100644 --- a/content/renderer/media/rtc_video_encoder.cc +++ b/content/renderer/media/rtc_video_encoder.cc
@@ -356,7 +356,7 @@ input_frame_coded_size_ = input_coded_size; for (unsigned int i = 0; i < input_count + kInputBufferExtraCount; ++i) { - base::SharedMemory* shm = + scoped_ptr<base::SharedMemory> shm = gpu_factories_->CreateSharedMemory(media::VideoFrame::AllocationSize( media::VideoFrame::I420, input_coded_size)); if (!shm) { @@ -365,12 +365,12 @@ NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError); return; } - input_buffers_.push_back(shm); + input_buffers_.push_back(shm.release()); input_buffers_free_.push_back(i); } for (int i = 0; i < kOutputBufferCount; ++i) { - base::SharedMemory* shm = + scoped_ptr<base::SharedMemory> shm = gpu_factories_->CreateSharedMemory(output_buffer_size); if (!shm) { DLOG(ERROR) << "Impl::RequireBitstreamBuffers(): " @@ -378,7 +378,7 @@ NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError); return; } - output_buffers_.push_back(shm); + output_buffers_.push_back(shm.release()); } // Immediately provide all output buffers to the VEA.
diff --git a/content/renderer/media/speech_recognition_audio_sink_unittest.cc b/content/renderer/media/speech_recognition_audio_sink_unittest.cc index c517beef..bd193b0 100644 --- a/content/renderer/media/speech_recognition_audio_sink_unittest.cc +++ b/content/renderer/media/speech_recognition_audio_sink_unittest.cc
@@ -224,7 +224,7 @@ output_sample_rate, kOutputBitsPerSample, output_frames_per_buffer); - source_data_.reset(new int16[input_frames_per_buffer * kInputChannels]{}); + source_data_.reset(new int16[input_frames_per_buffer * kInputChannels]()); // Prepare the track and audio source. blink::WebMediaStreamTrack blink_track;
diff --git a/content/renderer/npapi/webplugin_delegate_proxy.cc b/content/renderer/npapi/webplugin_delegate_proxy.cc index aa44291..5913a90 100644 --- a/content/renderer/npapi/webplugin_delegate_proxy.cc +++ b/content/renderer/npapi/webplugin_delegate_proxy.cc
@@ -18,7 +18,9 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/version.h" +#include "cc/resources/shared_bitmap.h" #include "content/child/child_process.h" +#include "content/child/child_shared_bitmap_manager.h" #include "content/child/npapi/npobject_proxy.h" #include "content/child/npapi/npobject_stub.h" #include "content/child/npapi/npobject_util.h" @@ -496,12 +498,12 @@ #endif } -static void CopyTransportDIBHandleForMessage( - const TransportDIB::Handle& handle_in, - TransportDIB::Handle* handle_out, +static void CopySharedMemoryHandleForMessage( + const base::SharedMemoryHandle& handle_in, + base::SharedMemoryHandle* handle_out, base::ProcessId peer_pid) { -#if defined(OS_MACOSX) - // On Mac, TransportDIB::Handle is typedef'ed to FileDescriptor, and +#if defined(OS_POSIX) + // On POSIX, base::ShardMemoryHandle is typedef'ed to FileDescriptor, and // FileDescriptor message fields needs to remain valid until the message is // sent or else the sendmsg() call will fail. if ((handle_out->fd = HANDLE_EINTR(dup(handle_in.fd))) < 0) { @@ -516,8 +518,7 @@ FILE_MAP_READ | FILE_MAP_WRITE, 0); DCHECK(*handle_out != NULL); #else - // Don't need to do anything special for other platforms. - *handle_out = handle_in; +#error Shared memory copy not implemented. #endif } @@ -529,8 +530,8 @@ PluginMsg_UpdateGeometry_Param param; param.window_rect = plugin_rect_; param.clip_rect = clip_rect_; - param.windowless_buffer0 = TransportDIB::DefaultHandleValue(); - param.windowless_buffer1 = TransportDIB::DefaultHandleValue(); + param.windowless_buffer0 = base::SharedMemory::NULLHandle(); + param.windowless_buffer1 = base::SharedMemory::NULLHandle(); param.windowless_buffer_index = back_buffer_index(); #if defined(OS_POSIX) @@ -540,15 +541,15 @@ if (bitmaps_changed) #endif { - if (transport_stores_[0].dib) - CopyTransportDIBHandleForMessage(transport_stores_[0].dib->handle(), - ¶m.windowless_buffer0, - channel_host_->peer_pid()); + if (transport_stores_[0].bitmap) + CopySharedMemoryHandleForMessage( + transport_stores_[0].bitmap->memory()->handle(), + ¶m.windowless_buffer0, channel_host_->peer_pid()); - if (transport_stores_[1].dib) - CopyTransportDIBHandleForMessage(transport_stores_[1].dib->handle(), - ¶m.windowless_buffer1, - channel_host_->peer_pid()); + if (transport_stores_[1].bitmap) + CopySharedMemoryHandleForMessage( + transport_stores_[1].bitmap->memory()->handle(), + ¶m.windowless_buffer1, channel_host_->peer_pid()); } IPC::Message* msg; @@ -594,9 +595,9 @@ // asynchronously. ResetWindowlessBitmaps(); if (!window_rect.IsEmpty()) { - if (!CreateSharedBitmap(&transport_stores_[0].dib, + if (!CreateSharedBitmap(&transport_stores_[0].bitmap, &transport_stores_[0].canvas) || - !CreateSharedBitmap(&transport_stores_[1].dib, + !CreateSharedBitmap(&transport_stores_[1].bitmap, &transport_stores_[1].canvas)) { DCHECK(false); ResetWindowlessBitmaps(); @@ -610,8 +611,8 @@ } void WebPluginDelegateProxy::ResetWindowlessBitmaps() { - transport_stores_[0].dib.reset(); - transport_stores_[1].dib.reset(); + transport_stores_[0].bitmap.reset(); + transport_stores_[1].bitmap.reset(); transport_stores_[0].canvas.reset(); transport_stores_[1].canvas.reset(); @@ -641,28 +642,23 @@ #endif bool WebPluginDelegateProxy::CreateSharedBitmap( - scoped_ptr<TransportDIB>* memory, + scoped_ptr<cc::SharedBitmap>* memory, scoped_ptr<skia::PlatformCanvas>* canvas) { - const size_t size = BitmapSizeForPluginRect(plugin_rect_); -#if defined(OS_POSIX) && !defined(OS_MACOSX) - memory->reset(TransportDIB::Create(size, 0)); + *memory = + ChildThread::current()->shared_bitmap_manager()->AllocateSharedBitmap( + plugin_rect_.size()); if (!memory->get()) return false; -#endif -#if defined(OS_POSIX) && !defined(OS_ANDROID) - TransportDIB::Handle handle; - IPC::Message* msg = new ViewHostMsg_AllocTransportDIB(size, false, &handle); - if (!RenderThreadImpl::current()->Send(msg)) - return false; - if (handle.fd < 0) - return false; - memory->reset(TransportDIB::Map(handle)); + DCHECK((*memory)->memory()); +#if defined(OS_POSIX) + canvas->reset(skia::CreatePlatformCanvas( + plugin_rect_.width(), plugin_rect_.height(), true, (*memory)->pixels(), + skia::RETURN_NULL_ON_FAILURE)); #else - static uint32 sequence_number = 0; - memory->reset(TransportDIB::Create(size, sequence_number++)); + canvas->reset(skia::CreatePlatformCanvas( + plugin_rect_.width(), plugin_rect_.height(), true, + (*memory)->memory()->handle(), skia::RETURN_NULL_ON_FAILURE)); #endif - canvas->reset((*memory)->GetPlatformCanvas(plugin_rect_.width(), - plugin_rect_.height())); return !!canvas->get(); } @@ -721,7 +717,7 @@ if (invalidate_pending_) { // Only send the PaintAck message if this paint is in response to an // invalidate from the plugin, since this message acts as an access token - // to ensure only one process is using the transport dib at a time. + // to ensure only one process is using the shared bitmap at a time. invalidate_pending_ = false; Send(new PluginMsg_DidPaint(instance_id_)); } @@ -1023,12 +1019,12 @@ const size_t stride = skia::PlatformCanvasStrideForWidth(plugin_rect_.width()); const size_t chunk_size = 4 * rect.width(); - DCHECK(back_buffer_dib() != NULL); - uint8* source_data = static_cast<uint8*>(back_buffer_dib()->memory()) + - rect.y() * stride + 4 * rect.x(); - DCHECK(front_buffer_dib() != NULL); - uint8* target_data = static_cast<uint8*>(front_buffer_dib()->memory()) + - rect.y() * stride + 4 * rect.x(); + DCHECK(back_buffer_bitmap() != NULL); + uint8* source_data = + back_buffer_bitmap()->pixels() + rect.y() * stride + 4 * rect.x(); + DCHECK(front_buffer_bitmap() != NULL); + uint8* target_data = + front_buffer_bitmap()->pixels() + rect.y() * stride + 4 * rect.x(); for (int row = 0; row < rect.height(); ++row) { memcpy(target_data, source_data, chunk_size); source_data += stride;
diff --git a/content/renderer/npapi/webplugin_delegate_proxy.h b/content/renderer/npapi/webplugin_delegate_proxy.h index 9192b5c..82071b8 100644 --- a/content/renderer/npapi/webplugin_delegate_proxy.h +++ b/content/renderer/npapi/webplugin_delegate_proxy.h
@@ -19,7 +19,6 @@ #include "ipc/ipc_sender.h" #include "ui/gfx/native_widget_types.h" #include "ui/gfx/rect.h" -#include "ui/surface/transport_dib.h" #include "url/gurl.h" #if defined(OS_MACOSX) @@ -35,6 +34,10 @@ class WaitableEvent; } +namespace cc { +class SharedBitmap; +} + namespace content { class NPObjectStub; class PluginChannelHost; @@ -155,7 +158,7 @@ SharedBitmap(); ~SharedBitmap(); - scoped_ptr<TransportDIB> dib; + scoped_ptr<cc::SharedBitmap> bitmap; scoped_ptr<SkCanvas> canvas; }; @@ -229,12 +232,12 @@ return transport_stores_[back_buffer_index()].canvas.get(); } - TransportDIB* front_buffer_dib() const { - return transport_stores_[front_buffer_index()].dib.get(); + cc::SharedBitmap* front_buffer_bitmap() const { + return transport_stores_[front_buffer_index()].bitmap.get(); } - TransportDIB* back_buffer_dib() const { - return transport_stores_[back_buffer_index()].dib.get(); + cc::SharedBitmap* back_buffer_bitmap() const { + return transport_stores_[back_buffer_index()].bitmap.get(); } #if !defined(OS_WIN) @@ -245,7 +248,7 @@ #endif // Creates a shared memory section and canvas. - bool CreateSharedBitmap(scoped_ptr<TransportDIB>* memory, + bool CreateSharedBitmap(scoped_ptr<cc::SharedBitmap>* memory, scoped_ptr<SkCanvas>* canvas); // Called for cleanup during plugin destruction. Normally right before the
diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.cc b/content/renderer/pepper/pepper_plugin_instance_impl.cc index 96cbe65..71af512 100644 --- a/content/renderer/pepper/pepper_plugin_instance_impl.cc +++ b/content/renderer/pepper/pepper_plugin_instance_impl.cc
@@ -44,6 +44,7 @@ #include "content/renderer/pepper/pepper_url_loader_host.h" #include "content/renderer/pepper/plugin_module.h" #include "content/renderer/pepper/plugin_object.h" +#include "content/renderer/pepper/plugin_power_saver_helper_impl.h" #include "content/renderer/pepper/ppapi_preferences_builder.h" #include "content/renderer/pepper/ppb_buffer_impl.h" #include "content/renderer/pepper/ppb_graphics_3d_impl.h" @@ -837,7 +838,7 @@ return false; throttler_.reset(new PepperPluginInstanceThrottler( - render_frame()->plugin_power_saver_helper(), + render_frame()->GetPluginPowerSaverHelper(), container()->element().boundsInViewportSpace(), module()->name(), plugin_url_, base::Bind(&PepperPluginInstanceImpl::SendDidChangeView, weak_factory_.GetWeakPtr())));
diff --git a/content/renderer/pepper/pepper_plugin_instance_throttler.cc b/content/renderer/pepper/pepper_plugin_instance_throttler.cc index 84cbb7a..80b7f611 100644 --- a/content/renderer/pepper/pepper_plugin_instance_throttler.cc +++ b/content/renderer/pepper/pepper_plugin_instance_throttler.cc
@@ -11,7 +11,7 @@ #include "base/time/time.h" #include "content/public/common/content_constants.h" #include "content/public/common/content_switches.h" -#include "content/renderer/pepper/plugin_power_saver_helper.h" +#include "content/renderer/pepper/plugin_power_saver_helper_impl.h" #include "content/renderer/render_thread_impl.h" #include "third_party/WebKit/public/web/WebInputEvent.h" #include "ui/gfx/color_utils.h" @@ -107,7 +107,7 @@ } // namespace PepperPluginInstanceThrottler::PepperPluginInstanceThrottler( - PluginPowerSaverHelper* power_saver_helper, + PluginPowerSaverHelperImpl* power_saver_helper, const blink::WebRect& bounds, const std::string& module_name, const GURL& plugin_url,
diff --git a/content/renderer/pepper/pepper_plugin_instance_throttler.h b/content/renderer/pepper/pepper_plugin_instance_throttler.h index 74c4ab7..8f5445af 100644 --- a/content/renderer/pepper/pepper_plugin_instance_throttler.h +++ b/content/renderer/pepper/pepper_plugin_instance_throttler.h
@@ -21,7 +21,7 @@ namespace content { -class PluginPowerSaverHelper; +class PluginPowerSaverHelperImpl; // Manages the Plugin Power Saver feature for a single Pepper plugin instance. // @@ -44,7 +44,7 @@ // representative keyframe. class CONTENT_EXPORT PepperPluginInstanceThrottler { public: - PepperPluginInstanceThrottler(PluginPowerSaverHelper* power_saver_helper, + PepperPluginInstanceThrottler(PluginPowerSaverHelperImpl* power_saver_helper, const blink::WebRect& bounds, const std::string& module_name, const GURL& plugin_url,
diff --git a/content/renderer/pepper/pepper_plugin_instance_throttler_unittest.cc b/content/renderer/pepper/pepper_plugin_instance_throttler_unittest.cc index ca69cda4..ba0463d 100644 --- a/content/renderer/pepper/pepper_plugin_instance_throttler_unittest.cc +++ b/content/renderer/pepper/pepper_plugin_instance_throttler_unittest.cc
@@ -10,26 +10,32 @@ #include "content/public/common/content_constants.h" #include "content/public/common/content_switches.h" #include "content/renderer/pepper/pepper_plugin_instance_throttler.h" -#include "content/renderer/pepper/plugin_power_saver_helper.h" +#include "content/renderer/pepper/plugin_power_saver_helper_impl.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/WebKit/public/web/WebInputEvent.h" +#include "third_party/WebKit/public/web/WebPluginParams.h" #include "ui/gfx/canvas.h" using testing::_; using testing::Return; +class GURL; + namespace content { namespace { -class MockPluginPowerSaverHelper : public PluginPowerSaverHelper { +class MockPluginPowerSaverHelper : public PluginPowerSaverHelperImpl { public: - MockPluginPowerSaverHelper() : PluginPowerSaverHelper(NULL) { + MockPluginPowerSaverHelper() : PluginPowerSaverHelperImpl(nullptr) { EXPECT_CALL(*this, ShouldThrottleContent(_, _, _, _)) .WillRepeatedly(Return(true)); } + MOCK_CONST_METHOD2(GetPluginInstancePosterImage, + GURL(const blink::WebPluginParams&, const GURL& base_url)); + MOCK_CONST_METHOD4(ShouldThrottleContent, bool(const GURL&, int, int, bool*)); void RegisterPeripheralPlugin(
diff --git a/content/renderer/pepper/plugin_power_saver_helper.cc b/content/renderer/pepper/plugin_power_saver_helper.cc deleted file mode 100644 index feec04f..0000000 --- a/content/renderer/pepper/plugin_power_saver_helper.cc +++ /dev/null
@@ -1,158 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/callback.h" -#include "base/metrics/histogram.h" -#include "content/common/frame_messages.h" -#include "content/public/renderer/document_state.h" -#include "content/public/renderer/navigation_state.h" -#include "content/public/renderer/render_frame.h" -#include "content/renderer/pepper/plugin_power_saver_helper.h" -#include "third_party/WebKit/public/web/WebDocument.h" -#include "third_party/WebKit/public/web/WebLocalFrame.h" -#include "third_party/WebKit/public/web/WebView.h" - -namespace content { - -namespace { - -// Initial decision of the peripheral content decision. -// These numeric values are used in UMA logs; do not change them. -enum PeripheralHeuristicDecision { - HEURISTIC_DECISION_PERIPHERAL = 0, - HEURISTIC_DECISION_ESSENTIAL_SAME_ORIGIN = 1, - HEURISTIC_DECISION_ESSENTIAL_CROSS_ORIGIN_BIG = 2, - HEURISTIC_DECISION_ESSENTIAL_CROSS_ORIGIN_WHITELISTED = 3, - HEURISTIC_DECISION_NUM_ITEMS -}; - -const char kPeripheralHeuristicHistogram[] = - "Plugin.PowerSaver.PeripheralHeuristic"; - -// Maximum dimensions plug-in content may have while still being considered -// peripheral content. These match the sizes used by Safari. -const int kPeripheralContentMaxWidth = 400; -const int kPeripheralContentMaxHeight = 300; - -void RecordDecisionMetric(PeripheralHeuristicDecision decision) { - UMA_HISTOGRAM_ENUMERATION(kPeripheralHeuristicHistogram, decision, - HEURISTIC_DECISION_NUM_ITEMS); -} - -} // namespace - -PluginPowerSaverHelper::PeripheralPlugin::PeripheralPlugin( - const GURL& content_origin, - const base::Closure& unthrottle_callback) - : content_origin(content_origin), unthrottle_callback(unthrottle_callback) { -} - -PluginPowerSaverHelper::PeripheralPlugin::~PeripheralPlugin() { -} - -PluginPowerSaverHelper::PluginPowerSaverHelper(RenderFrame* render_frame) - : RenderFrameObserver(render_frame) { -} - -PluginPowerSaverHelper::~PluginPowerSaverHelper() { -} - -void PluginPowerSaverHelper::DidCommitProvisionalLoad(bool is_new_navigation) { - blink::WebFrame* frame = render_frame()->GetWebFrame(); - if (frame->parent()) - return; // Not a top-level navigation. - - DocumentState* document_state = - DocumentState::FromDataSource(frame->dataSource()); - NavigationState* navigation_state = document_state->navigation_state(); - if (!navigation_state->was_within_same_page()) - origin_whitelist_.clear(); -} - -bool PluginPowerSaverHelper::OnMessageReceived(const IPC::Message& message) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(PluginPowerSaverHelper, message) - IPC_MESSAGE_HANDLER(FrameMsg_UpdatePluginContentOriginWhitelist, - OnUpdatePluginContentOriginWhitelist) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; -} - -void PluginPowerSaverHelper::OnUpdatePluginContentOriginWhitelist( - const std::set<GURL>& origin_whitelist) { - origin_whitelist_ = origin_whitelist; - - // Check throttled plugin instances to see if any can be unthrottled. - auto it = peripheral_plugins_.begin(); - while (it != peripheral_plugins_.end()) { - if (origin_whitelist.count(it->content_origin)) { - it->unthrottle_callback.Run(); - it = peripheral_plugins_.erase(it); - } else { - ++it; - } - } -} - -bool PluginPowerSaverHelper::ShouldThrottleContent(const GURL& content_origin, - int width, - int height, - bool* cross_origin) const { - DCHECK(cross_origin); - *cross_origin = true; - - // TODO(alexmos): Update this to use the origin of the RemoteFrame when 426512 - // is fixed. For now, case 3 in the class level comment doesn't work in - // --site-per-process mode. - blink::WebFrame* main_frame = - render_frame()->GetWebFrame()->view()->mainFrame(); - if (main_frame->isWebRemoteFrame()) { - RecordDecisionMetric(HEURISTIC_DECISION_PERIPHERAL); - return true; - } - - // All same-origin plugin content is essential. - GURL main_frame_origin = GURL(main_frame->document().url()).GetOrigin(); - if (content_origin == main_frame_origin) { - RecordDecisionMetric(HEURISTIC_DECISION_ESSENTIAL_SAME_ORIGIN); - *cross_origin = false; - return false; - } - - // Whitelisted plugin origins are also essential. - if (origin_whitelist_.count(content_origin)) { - RecordDecisionMetric(HEURISTIC_DECISION_ESSENTIAL_CROSS_ORIGIN_WHITELISTED); - return false; - } - - // Cross-origin plugin content is peripheral if smaller than a maximum size. - bool content_is_small = width < kPeripheralContentMaxWidth || - height < kPeripheralContentMaxHeight; - - if (content_is_small) - RecordDecisionMetric(HEURISTIC_DECISION_PERIPHERAL); - else - RecordDecisionMetric(HEURISTIC_DECISION_ESSENTIAL_CROSS_ORIGIN_BIG); - - return content_is_small; -} - -void PluginPowerSaverHelper::RegisterPeripheralPlugin( - const GURL& content_origin, - const base::Closure& unthrottle_callback) { - peripheral_plugins_.push_back( - PeripheralPlugin(content_origin, unthrottle_callback)); -} - -void PluginPowerSaverHelper::WhitelistContentOrigin( - const GURL& content_origin) { - DCHECK_EQ(content_origin.GetOrigin(), content_origin); - if (origin_whitelist_.insert(content_origin).second) { - Send(new FrameHostMsg_PluginContentOriginAllowed( - render_frame()->GetRoutingID(), content_origin)); - } -} - -} // namespace content
diff --git a/content/renderer/pepper/plugin_power_saver_helper_browsertest.cc b/content/renderer/pepper/plugin_power_saver_helper_browsertest.cc index 0cdec0f..bba3ad2 100644 --- a/content/renderer/pepper/plugin_power_saver_helper_browsertest.cc +++ b/content/renderer/pepper/plugin_power_saver_helper_browsertest.cc
@@ -6,12 +6,13 @@ #include "content/common/frame_messages.h" #include "content/common/view_message_enums.h" #include "content/public/test/render_view_test.h" -#include "content/renderer/pepper/plugin_power_saver_helper.h" +#include "content/renderer/pepper/plugin_power_saver_helper_impl.h" #include "content/renderer/render_frame_impl.h" #include "content/renderer/render_view_impl.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/WebKit/public/web/WebDocument.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" +#include "third_party/WebKit/public/web/WebPluginParams.h" #include "url/gurl.h" namespace content { @@ -24,8 +25,8 @@ return static_cast<RenderFrameImpl*>(view_->GetMainRenderFrame()); } - PluginPowerSaverHelper* power_saver_helper() { - return frame()->plugin_power_saver_helper(); + PluginPowerSaverHelperImpl* power_saver_helper() { + return frame()->GetPluginPowerSaverHelper(); } void SetUp() override { @@ -39,6 +40,41 @@ DISALLOW_COPY_AND_ASSIGN(PluginPowerSaverHelperTest); }; +TEST_F(PluginPowerSaverHelperTest, PosterImage) { + size_t size = 3; + blink::WebVector<blink::WebString> names(size); + blink::WebVector<blink::WebString> values(size); + + blink::WebPluginParams params; + params.url = GURL("http://b.com/foo.swf"); + + params.attributeNames.swap(names); + params.attributeValues.swap(values); + + params.attributeNames[0] = "poster"; + params.attributeNames[1] = "height"; + params.attributeNames[2] = "width"; + params.attributeValues[0] = "poster.jpg"; + params.attributeValues[1] = "100"; + params.attributeValues[2] = "100"; + + EXPECT_EQ(GURL("http://a.com/poster.jpg"), + power_saver_helper()->GetPluginInstancePosterImage( + params, GURL("http://a.com/page.html"))); + + // Ignore empty poster paramaters. + params.attributeValues[0] = ""; + EXPECT_EQ(GURL(), power_saver_helper()->GetPluginInstancePosterImage( + params, GURL("http://a.com/page.html"))); + + // Ignore poster parameter when plugin is big (shouldn't be throttled). + params.attributeValues[0] = "poster.jpg"; + params.attributeValues[1] = "500"; + params.attributeValues[2] = "500"; + EXPECT_EQ(GURL(), power_saver_helper()->GetPluginInstancePosterImage( + params, GURL("http://a.com/page.html"))); +} + TEST_F(PluginPowerSaverHelperTest, AllowSameOrigin) { bool cross_origin = false; EXPECT_FALSE(power_saver_helper()->ShouldThrottleContent(
diff --git a/content/renderer/pepper/plugin_power_saver_helper_impl.cc b/content/renderer/pepper/plugin_power_saver_helper_impl.cc new file mode 100644 index 0000000..92fcb4d --- /dev/null +++ b/content/renderer/pepper/plugin_power_saver_helper_impl.cc
@@ -0,0 +1,217 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/renderer/pepper/plugin_power_saver_helper_impl.h" + +#include "base/metrics/histogram.h" +#include "base/strings/string_number_conversions.h" +#include "content/common/frame_messages.h" +#include "content/public/renderer/document_state.h" +#include "content/public/renderer/navigation_state.h" +#include "content/public/renderer/render_frame.h" +#include "third_party/WebKit/public/web/WebDocument.h" +#include "third_party/WebKit/public/web/WebLocalFrame.h" +#include "third_party/WebKit/public/web/WebPluginParams.h" +#include "third_party/WebKit/public/web/WebView.h" + +namespace content { + +namespace { + +const char kPosterParamName[] = "poster"; + +// Initial decision of the peripheral content decision. +// These numeric values are used in UMA logs; do not change them. +enum PeripheralHeuristicDecision { + HEURISTIC_DECISION_PERIPHERAL = 0, + HEURISTIC_DECISION_ESSENTIAL_SAME_ORIGIN = 1, + HEURISTIC_DECISION_ESSENTIAL_CROSS_ORIGIN_BIG = 2, + HEURISTIC_DECISION_ESSENTIAL_CROSS_ORIGIN_WHITELISTED = 3, + HEURISTIC_DECISION_NUM_ITEMS +}; + +const char kPeripheralHeuristicHistogram[] = + "Plugin.PowerSaver.PeripheralHeuristic"; + +// Maximum dimensions plug-in content may have while still being considered +// peripheral content. These match the sizes used by Safari. +const int kPeripheralContentMaxWidth = 400; +const int kPeripheralContentMaxHeight = 300; + +void RecordDecisionMetric(PeripheralHeuristicDecision decision) { + UMA_HISTOGRAM_ENUMERATION(kPeripheralHeuristicHistogram, decision, + HEURISTIC_DECISION_NUM_ITEMS); +} + +const char kWebPluginParamHeight[] = "height"; +const char kWebPluginParamWidth[] = "width"; + +// Returns true if valid non-negative height and width extracted. +// When this returns false, |width| and |height| are set to undefined values. +bool ExtractDimensions(const blink::WebPluginParams& params, + int* width, + int* height) { + DCHECK_EQ(params.attributeNames.size(), params.attributeValues.size()); + DCHECK(width); + DCHECK(height); + bool width_extracted = false; + bool height_extracted = false; + for (size_t i = 0; i < params.attributeNames.size(); ++i) { + if (params.attributeNames[i].utf8() == kWebPluginParamWidth) { + width_extracted = + base::StringToInt(params.attributeValues[i].utf8(), width); + } else if (params.attributeNames[i].utf8() == kWebPluginParamHeight) { + height_extracted = + base::StringToInt(params.attributeValues[i].utf8(), height); + } + } + return width_extracted && height_extracted && *width >= 0 && *height >= 0; +} + +} // namespace + +PluginPowerSaverHelperImpl::PeripheralPlugin::PeripheralPlugin( + const GURL& content_origin, + const base::Closure& unthrottle_callback) + : content_origin(content_origin), unthrottle_callback(unthrottle_callback) { +} + +PluginPowerSaverHelperImpl::PeripheralPlugin::~PeripheralPlugin() { +} + +PluginPowerSaverHelperImpl::PluginPowerSaverHelperImpl( + RenderFrame* render_frame) + : RenderFrameObserver(render_frame) { +} + +PluginPowerSaverHelperImpl::~PluginPowerSaverHelperImpl() { +} + +void PluginPowerSaverHelperImpl::DidCommitProvisionalLoad( + bool is_new_navigation) { + blink::WebFrame* frame = render_frame()->GetWebFrame(); + if (frame->parent()) + return; // Not a top-level navigation. + + DocumentState* document_state = + DocumentState::FromDataSource(frame->dataSource()); + NavigationState* navigation_state = document_state->navigation_state(); + if (!navigation_state->was_within_same_page()) + origin_whitelist_.clear(); +} + +bool PluginPowerSaverHelperImpl::OnMessageReceived( + const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PluginPowerSaverHelperImpl, message) + IPC_MESSAGE_HANDLER(FrameMsg_UpdatePluginContentOriginWhitelist, + OnUpdatePluginContentOriginWhitelist) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void PluginPowerSaverHelperImpl::OnUpdatePluginContentOriginWhitelist( + const std::set<GURL>& origin_whitelist) { + origin_whitelist_ = origin_whitelist; + + // Check throttled plugin instances to see if any can be unthrottled. + auto it = peripheral_plugins_.begin(); + while (it != peripheral_plugins_.end()) { + if (origin_whitelist.count(it->content_origin)) { + it->unthrottle_callback.Run(); + it = peripheral_plugins_.erase(it); + } else { + ++it; + } + } +} + +GURL PluginPowerSaverHelperImpl::GetPluginInstancePosterImage( + const blink::WebPluginParams& params, + const GURL& base_url) const { + DCHECK_EQ(params.attributeNames.size(), params.attributeValues.size()); + + GURL content_origin = GURL(params.url).GetOrigin(); + int width = 0; + int height = 0; + + bool cross_origin = false; + if (!ExtractDimensions(params, &width, &height)) + return GURL(); + + if (!ShouldThrottleContent(content_origin, width, height, &cross_origin)) + return GURL(); + + for (size_t i = 0; i < params.attributeNames.size(); ++i) { + if (params.attributeNames[i] == kPosterParamName) { + std::string poster_value(params.attributeValues[i].utf8()); + if (!poster_value.empty()) + return base_url.Resolve(poster_value); + } + } + return GURL(); +} + +void PluginPowerSaverHelperImpl::RegisterPeripheralPlugin( + const GURL& content_origin, + const base::Closure& unthrottle_callback) { + peripheral_plugins_.push_back( + PeripheralPlugin(content_origin, unthrottle_callback)); +} + +bool PluginPowerSaverHelperImpl::ShouldThrottleContent( + const GURL& content_origin, + int width, + int height, + bool* cross_origin) const { + DCHECK(cross_origin); + *cross_origin = true; + + // TODO(alexmos): Update this to use the origin of the RemoteFrame when 426512 + // is fixed. For now, case 3 in the class level comment doesn't work in + // --site-per-process mode. + blink::WebFrame* main_frame = + render_frame()->GetWebFrame()->view()->mainFrame(); + if (main_frame->isWebRemoteFrame()) { + RecordDecisionMetric(HEURISTIC_DECISION_PERIPHERAL); + return true; + } + + // All same-origin plugin content is essential. + GURL main_frame_origin = GURL(main_frame->document().url()).GetOrigin(); + if (content_origin == main_frame_origin) { + RecordDecisionMetric(HEURISTIC_DECISION_ESSENTIAL_SAME_ORIGIN); + *cross_origin = false; + return false; + } + + // Whitelisted plugin origins are also essential. + if (origin_whitelist_.count(content_origin)) { + RecordDecisionMetric(HEURISTIC_DECISION_ESSENTIAL_CROSS_ORIGIN_WHITELISTED); + return false; + } + + // Cross-origin plugin content is peripheral if smaller than a maximum size. + bool content_is_small = width < kPeripheralContentMaxWidth || + height < kPeripheralContentMaxHeight; + + if (content_is_small) + RecordDecisionMetric(HEURISTIC_DECISION_PERIPHERAL); + else + RecordDecisionMetric(HEURISTIC_DECISION_ESSENTIAL_CROSS_ORIGIN_BIG); + + return content_is_small; +} + +void PluginPowerSaverHelperImpl::WhitelistContentOrigin( + const GURL& content_origin) { + DCHECK_EQ(content_origin.GetOrigin(), content_origin); + if (origin_whitelist_.insert(content_origin).second) { + Send(new FrameHostMsg_PluginContentOriginAllowed( + render_frame()->GetRoutingID(), content_origin)); + } +} + +} // namespace content
diff --git a/content/renderer/pepper/plugin_power_saver_helper.h b/content/renderer/pepper/plugin_power_saver_helper_impl.h similarity index 65% rename from content/renderer/pepper/plugin_power_saver_helper.h rename to content/renderer/pepper/plugin_power_saver_helper_impl.h index 5cca041..55546fd 100644 --- a/content/renderer/pepper/plugin_power_saver_helper.h +++ b/content/renderer/pepper/plugin_power_saver_helper_impl.h
@@ -2,24 +2,32 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CONTENT_RENDERER_PEPPER_PLUGIN_POWER_SAVER_HELPER_H_ -#define CONTENT_RENDERER_PEPPER_PLUGIN_POWER_SAVER_HELPER_H_ +#ifndef CONTENT_RENDERER_PEPPER_PLUGIN_POWER_SAVER_HELPER_IMPL_H_ +#define CONTENT_RENDERER_PEPPER_PLUGIN_POWER_SAVER_HELPER_IMPL_H_ #include <set> #include <vector> -#include "base/callback_forward.h" +#include "base/callback.h" +#include "content/common/content_export.h" +#include "content/public/renderer/plugin_power_saver_helper.h" #include "content/public/renderer/render_frame_observer.h" #include "url/gurl.h" namespace content { -// PluginPowerSaverWhitelist manages the plugin content origin whitelist for -// a single render frame. -class CONTENT_EXPORT PluginPowerSaverHelper : public RenderFrameObserver { +class CONTENT_EXPORT PluginPowerSaverHelperImpl : public PluginPowerSaverHelper, + public RenderFrameObserver { public: - explicit PluginPowerSaverHelper(RenderFrame* render_frame); - virtual ~PluginPowerSaverHelper(); + explicit PluginPowerSaverHelperImpl(RenderFrame* render_frame); + ~PluginPowerSaverHelperImpl() override; + + // PluginPluginPowerSaverHelper implementation. + GURL GetPluginInstancePosterImage(const blink::WebPluginParams& params, + const GURL& base_url) const override; + void RegisterPeripheralPlugin( + const GURL& content_origin, + const base::Closure& unthrottle_callback) override; // Returns true if this plugin should have power saver enabled. // @@ -33,18 +41,14 @@ // - Same-origin: a.com -> b.com/iframe-to-a.html -> a.com/plugin.swf // // |cross_origin| may not be NULL. + // + // Virtual to allow overriding in tests. virtual bool ShouldThrottleContent(const GURL& content_origin, int width, int height, bool* cross_origin) const; - // Registers a plugin that has been marked peripheral. If the origin - // whitelist is later updated and includes |content_origin|, then - // |unthrottle_callback| will be called. - virtual void RegisterPeripheralPlugin( - const GURL& content_origin, - const base::Closure& unthrottle_callback); - + // Virtual to allow overriding in tests. virtual void WhitelistContentOrigin(const GURL& content_origin); private: @@ -70,9 +74,9 @@ // Set of peripheral plugins eligible to be unthrottled ex post facto. std::vector<PeripheralPlugin> peripheral_plugins_; - DISALLOW_COPY_AND_ASSIGN(PluginPowerSaverHelper); + DISALLOW_COPY_AND_ASSIGN(PluginPowerSaverHelperImpl); }; } // namespace content -#endif // CONTENT_RENDERER_PEPPER_PLUGIN_POWER_SAVER_HELPER_H_ +#endif // CONTENT_RENDERER_PEPPER_PLUGIN_POWER_SAVER_HELPER_IMPL_H_
diff --git a/content/renderer/push_messaging_dispatcher.cc b/content/renderer/push_messaging_dispatcher.cc index 3289257..763a8e9 100644 --- a/content/renderer/push_messaging_dispatcher.cc +++ b/content/renderer/push_messaging_dispatcher.cc
@@ -30,8 +30,10 @@ bool PushMessagingDispatcher::OnMessageReceived(const IPC::Message& message) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(PushMessagingDispatcher, message) - IPC_MESSAGE_HANDLER(PushMessagingMsg_RegisterSuccess, OnRegisterSuccess) - IPC_MESSAGE_HANDLER(PushMessagingMsg_RegisterError, OnRegisterError) + IPC_MESSAGE_HANDLER(PushMessagingMsg_RegisterFromDocumentSuccess, + OnRegisterFromDocumentSuccess) + IPC_MESSAGE_HANDLER(PushMessagingMsg_RegisterFromDocumentError, + OnRegisterFromDocumentError) IPC_MESSAGE_HANDLER(PushMessagingMsg_PermissionStatusResult, OnPermissionStatus) IPC_MESSAGE_HANDLER(PushMessagingMsg_PermissionStatusFailure, @@ -57,20 +59,20 @@ blink::WebPushRegistrationCallbacks* callbacks, blink::WebServiceWorkerProvider* service_worker_provider, const Manifest& manifest) { - int callbacks_id = registration_callbacks_.Add(callbacks); + int request_id = registration_callbacks_.Add(callbacks); int service_worker_provider_id = static_cast<WebServiceWorkerProviderImpl*>( service_worker_provider)->provider_id(); std::string sender_id = manifest.gcm_sender_id.is_null() ? std::string() : base::UTF16ToUTF8(manifest.gcm_sender_id.string()); if (sender_id.empty()) { - OnRegisterError(callbacks_id, PUSH_REGISTRATION_STATUS_NO_SENDER_ID); + OnRegisterFromDocumentError(request_id, + PUSH_REGISTRATION_STATUS_NO_SENDER_ID); return; } - Send(new PushMessagingHostMsg_Register( - routing_id(), - callbacks_id, + Send(new PushMessagingHostMsg_RegisterFromDocument( + routing_id(), request_id, manifest.gcm_sender_id.is_null() ? std::string() : base::UTF16ToUTF8(manifest.gcm_sender_id.string()), @@ -89,12 +91,12 @@ routing_id(), service_worker_provider_id, permission_callback_id)); } -void PushMessagingDispatcher::OnRegisterSuccess( - int32 callbacks_id, +void PushMessagingDispatcher::OnRegisterFromDocumentSuccess( + int32 request_id, const GURL& endpoint, const std::string& registration_id) { blink::WebPushRegistrationCallbacks* callbacks = - registration_callbacks_.Lookup(callbacks_id); + registration_callbacks_.Lookup(request_id); DCHECK(callbacks); scoped_ptr<blink::WebPushRegistration> registration( @@ -102,20 +104,21 @@ WebString::fromUTF8(endpoint.spec()), WebString::fromUTF8(registration_id))); callbacks->onSuccess(registration.release()); - registration_callbacks_.Remove(callbacks_id); + registration_callbacks_.Remove(request_id); } -void PushMessagingDispatcher::OnRegisterError(int32 callbacks_id, - PushRegistrationStatus status) { +void PushMessagingDispatcher::OnRegisterFromDocumentError( + int32 request_id, + PushRegistrationStatus status) { blink::WebPushRegistrationCallbacks* callbacks = - registration_callbacks_.Lookup(callbacks_id); + registration_callbacks_.Lookup(request_id); DCHECK(callbacks); scoped_ptr<blink::WebPushError> error(new blink::WebPushError( blink::WebPushError::ErrorTypeAbort, WebString::fromUTF8(PushRegistrationStatusToString(status)))); callbacks->onError(error.release()); - registration_callbacks_.Remove(callbacks_id); + registration_callbacks_.Remove(request_id); } void PushMessagingDispatcher::OnPermissionStatus(
diff --git a/content/renderer/push_messaging_dispatcher.h b/content/renderer/push_messaging_dispatcher.h index 6c472dd..c81d04684 100644 --- a/content/renderer/push_messaging_dispatcher.h +++ b/content/renderer/push_messaging_dispatcher.h
@@ -41,6 +41,8 @@ virtual void registerPushMessaging( blink::WebPushRegistrationCallbacks* callbacks, blink::WebServiceWorkerProvider* service_worker_provider); // override + // TODO(mvanouwerkerk): Delete once the Push API flows through platform. + // https://crbug.com/389194 virtual void getPermissionStatus( blink::WebPushPermissionStatusCallback* callback, blink::WebServiceWorkerProvider* service_worker_provider); // override @@ -49,18 +51,25 @@ blink::WebServiceWorkerProvider* service_worker_provider, const Manifest& manifest); - void OnRegisterSuccess(int32 callbacks_id, - const GURL& endpoint, - const std::string& registration_id); + void OnRegisterFromDocumentSuccess(int32 request_id, + const GURL& endpoint, + const std::string& registration_id); - void OnRegisterError(int32 callbacks_id, PushRegistrationStatus status); + void OnRegisterFromDocumentError(int32 request_id, + PushRegistrationStatus status); + // TODO(mvanouwerkerk): Delete once the Push API flows through platform. + // https://crbug.com/389194 void OnPermissionStatus(int32 callback_id, blink::WebPushPermissionStatus status); + // TODO(mvanouwerkerk): Delete once the Push API flows through platform. + // https://crbug.com/389194 void OnPermissionStatusFailure(int32 callback_id); IDMap<blink::WebPushRegistrationCallbacks, IDMapOwnPointer> registration_callbacks_; + // TODO(mvanouwerkerk): Delete once the Push API flows through platform. + // https://crbug.com/389194 IDMap<blink::WebPushPermissionStatusCallback, IDMapOwnPointer> permission_check_callbacks_;
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index 9ec55c9..a7a8d13 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc
@@ -136,7 +136,6 @@ #include "content/renderer/pepper/pepper_plugin_instance_impl.h" #include "content/renderer/pepper/pepper_webplugin_impl.h" #include "content/renderer/pepper/plugin_module.h" -#include "content/renderer/pepper/plugin_power_saver_helper.h" #endif #if defined(ENABLE_WEBRTC) @@ -604,7 +603,7 @@ #endif #if defined(ENABLE_PLUGINS) - plugin_power_saver_helper_ = new PluginPowerSaverHelper(this); + plugin_power_saver_helper_ = new PluginPowerSaverHelperImpl(this); #endif manifest_manager_ = new ManifestManager(this); @@ -835,11 +834,6 @@ } pepper_composition_text_.clear(); } - -PluginPowerSaverHelper* RenderFrameImpl::plugin_power_saver_helper() { - DCHECK(plugin_power_saver_helper_); - return plugin_power_saver_helper_; -} #endif // defined(ENABLE_PLUGINS) MediaStreamDispatcher* RenderFrameImpl::GetMediaStreamDispatcher() { @@ -1632,6 +1626,13 @@ return &service_registry_; } +#if defined(ENABLE_PLUGINS) +PluginPowerSaverHelperImpl* RenderFrameImpl::GetPluginPowerSaverHelper() { + DCHECK(plugin_power_saver_helper_); + return plugin_power_saver_helper_; +} +#endif + bool RenderFrameImpl::IsFTPDirectoryListing() { WebURLResponseExtraDataImpl* extra_data = GetExtraDataFromResponse(frame_->dataSource()->response());
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h index 3b828da..14528ab 100644 --- a/content/renderer/render_frame_impl.h +++ b/content/renderer/render_frame_impl.h
@@ -31,6 +31,10 @@ #include "third_party/WebKit/public/web/WebTransitionElementData.h" #include "ui/gfx/range/range.h" +#if defined(ENABLE_PLUGINS) +#include "content/renderer/pepper/plugin_power_saver_helper_impl.h" +#endif + #if defined(OS_ANDROID) #include "content/renderer/media/android/renderer_media_player_manager.h" #endif @@ -72,7 +76,6 @@ class NotificationPermissionDispatcher; class PageState; class PepperPluginInstanceImpl; -class PluginPowerSaverHelper; class PushMessagingDispatcher; class RendererAccessibility; class RendererCdmManager; @@ -243,8 +246,6 @@ void OnImeConfirmComposition(const base::string16& text, const gfx::Range& replacement_range, bool keep_selection); - - PluginPowerSaverHelper* plugin_power_saver_helper(); #endif // defined(ENABLE_PLUGINS) // May return NULL in some cases, especially if userMediaClient() returns @@ -280,6 +281,9 @@ void ExecuteJavaScript(const base::string16& javascript) override; bool IsHidden() override; ServiceRegistry* GetServiceRegistry() override; +#if defined(ENABLE_PLUGINS) + PluginPowerSaverHelperImpl* GetPluginPowerSaverHelper() override; +#endif bool IsFTPDirectoryListing() override; void AttachGuest(int element_instance_id) override; void SetSelectedText(const base::string16& selection_text, @@ -704,7 +708,7 @@ // progress. base::string16 pepper_composition_text_; - PluginPowerSaverHelper* plugin_power_saver_helper_; + PluginPowerSaverHelperImpl* plugin_power_saver_helper_; #endif RendererWebCookieJarImpl cookie_jar_;
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc index 465ec70..650c8e492 100644 --- a/content/renderer/render_thread_impl.cc +++ b/content/renderer/render_thread_impl.cc
@@ -80,6 +80,7 @@ #include "content/renderer/gpu/compositor_output_surface.h" #include "content/renderer/input/input_event_filter.h" #include "content/renderer/input/input_handler_manager.h" +#include "content/renderer/input/main_thread_input_event_filter.h" #include "content/renderer/media/aec_dump_message_filter.h" #include "content/renderer/media/audio_input_message_filter.h" #include "content/renderer/media/audio_message_filter.h" @@ -670,6 +671,8 @@ audio_message_filter_ = NULL; compositor_thread_.reset(); + + main_input_callback_.Cancel(); input_handler_manager_.reset(); if (input_event_filter_.get()) { RemoveFilter(input_event_filter_.get()); @@ -896,6 +899,10 @@ main_thread_compositor_task_runner_ = renderer_scheduler()->CompositorTaskRunner(); + main_input_callback_.Reset( + base::Bind(base::IgnoreResult(&RenderThreadImpl::OnMessageReceived), + base::Unretained(this))); + bool enable = !command_line.HasSwitch(switches::kDisableThreadedCompositing); if (enable) { #if defined(OS_ANDROID) @@ -926,18 +933,28 @@ } #endif if (!input_handler_manager_client) { - input_event_filter_ = - new InputEventFilter(this, + scoped_refptr<InputEventFilter> compositor_input_event_filter( + new InputEventFilter(main_input_callback_.callback(), main_thread_compositor_task_runner_, - compositor_message_loop_proxy_); - AddFilter(input_event_filter_.get()); - input_handler_manager_client = input_event_filter_.get(); + compositor_message_loop_proxy_)); + input_handler_manager_client = compositor_input_event_filter.get(); + input_event_filter_ = compositor_input_event_filter; } input_handler_manager_.reset(new InputHandlerManager( compositor_message_loop_proxy_, input_handler_manager_client, renderer_scheduler())); } + if (!input_event_filter_.get()) { + // Always provide an input event filter implementation to ensure consistent + // input event scheduling and prioritization. + // TODO(jdduke): Merge InputEventFilter, InputHandlerManager and + // MainThreadInputEventFilter, crbug.com/436057. + input_event_filter_ = new MainThreadInputEventFilter( + main_input_callback_.callback(), main_thread_compositor_task_runner_); + } + AddFilter(input_event_filter_.get()); + scoped_refptr<base::MessageLoopProxy> compositor_impl_side_loop; if (enable) compositor_impl_side_loop = compositor_message_loop_proxy_; @@ -1010,27 +1027,7 @@ scoped_ptr<base::SharedMemory> RenderThreadImpl::HostAllocateSharedMemoryBuffer(size_t size) { - if (size > static_cast<size_t>(std::numeric_limits<int>::max())) - return scoped_ptr<base::SharedMemory>(); - - base::SharedMemoryHandle handle; - bool success; - IPC::Message* message = - new ChildProcessHostMsg_SyncAllocateSharedMemory(size, &handle); - - // Allow calling this from the compositor thread. - if (base::MessageLoop::current() == message_loop()) - success = ChildThread::Send(message); - else - success = sync_message_filter()->Send(message); - - if (!success) - return scoped_ptr<base::SharedMemory>(); - - if (!base::SharedMemory::IsHandleValid(handle)) - return scoped_ptr<base::SharedMemory>(); - - return scoped_ptr<base::SharedMemory>(new base::SharedMemory(handle, false)); + return ChildThread::AllocateSharedMemory(size, thread_safe_sender()); } void RenderThreadImpl::RegisterExtension(v8::Extension* extension) {
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h index ef93741..8dd52978 100644 --- a/content/renderer/render_thread_impl.h +++ b/content/renderer/render_thread_impl.h
@@ -9,6 +9,7 @@ #include <string> #include <vector> +#include "base/cancelable_callback.h" #include "base/memory/memory_pressure_listener.h" #include "base/metrics/user_metrics_action.h" #include "base/observer_list.h" @@ -86,7 +87,6 @@ class EmbeddedWorkerDispatcher; class GpuChannelHost; class IndexedDBDispatcher; -class InputEventFilter; class InputHandlerManager; class MediaStreamCenter; class MemoryObserver; @@ -547,8 +547,8 @@ // regardless of whether |compositor_thread_| is overriden. scoped_refptr<base::MessageLoopProxy> compositor_message_loop_proxy_; - // May be null if unused by the |input_handler_manager_|. - scoped_refptr<InputEventFilter> input_event_filter_; + base::CancelableCallback<void(const IPC::Message&)> main_input_callback_; + scoped_refptr<IPC::MessageFilter> input_event_filter_; scoped_ptr<InputHandlerManager> input_handler_manager_; scoped_refptr<CompositorForwardingMessageFilter> compositor_message_filter_;
diff --git a/content/renderer/renderer_clipboard_delegate.cc b/content/renderer/renderer_clipboard_delegate.cc index 5033220..4a184bed 100644 --- a/content/renderer/renderer_clipboard_delegate.cc +++ b/content/renderer/renderer_clipboard_delegate.cc
@@ -143,9 +143,11 @@ // Allocate a shared memory buffer to hold the bitmap bits. uint32 buf_size = checked_buf_size.ValueOrDie(); - shared_buf.reset(ChildThread::current()->AllocateSharedMemory(buf_size)); + shared_buf = ChildThread::current()->AllocateSharedMemory(buf_size); if (!shared_buf) return false; + if (!shared_buf->Map(buf_size)) + return false; // Copy the bits into shared memory DCHECK(shared_buf->memory()); memcpy(shared_buf->memory(), pixels, buf_size);
diff --git a/content/renderer/renderer_main_platform_delegate_android.cc b/content/renderer/renderer_main_platform_delegate_android.cc index b4eef97b..8ef13037 100644 --- a/content/renderer/renderer_main_platform_delegate_android.cc +++ b/content/renderer/renderer_main_platform_delegate_android.cc
@@ -35,6 +35,12 @@ switches::kEnableSeccompFilterSandbox)) { return true; } + if (!sandbox::SandboxBPF::SupportsSeccompSandbox( + sandbox::SandboxBPF::SeccompLevel::MULTI_THREADED)) { + LOG(WARNING) << "Seccomp-BPF sandbox enabled without kernel support. " + << "Ignoring flag and proceeding without seccomp sandbox."; + return true; + } sandbox::SandboxBPF sandbox(new SandboxBPFBasePolicyAndroid()); CHECK(
diff --git a/content/renderer/scheduler/renderer_scheduler_impl_unittest.cc b/content/renderer/scheduler/renderer_scheduler_impl_unittest.cc index 092440cf..869a742 100644 --- a/content/renderer/scheduler/renderer_scheduler_impl_unittest.cc +++ b/content/renderer/scheduler/renderer_scheduler_impl_unittest.cc
@@ -42,7 +42,7 @@ void EnableIdleTasks() { scheduler_->WillBeginFrame(cc::BeginFrameArgs::Create( - clock_->Now(), base::TimeTicks(), + BEGINFRAME_FROM_HERE, clock_->Now(), base::TimeTicks(), base::TimeDelta::FromMilliseconds(1000), cc::BeginFrameArgs::NORMAL)); scheduler_->DidCommitFrameToCompositor(); } @@ -192,8 +192,8 @@ EXPECT_FALSE(task_run); // Shouldn't run yet as no WillBeginFrame. scheduler_->WillBeginFrame(cc::BeginFrameArgs::Create( - clock_->Now(), base::TimeTicks(), base::TimeDelta::FromMilliseconds(1000), - cc::BeginFrameArgs::NORMAL)); + BEGINFRAME_FROM_HERE, clock_->Now(), base::TimeTicks(), + base::TimeDelta::FromMilliseconds(1000), cc::BeginFrameArgs::NORMAL)); RunUntilIdle(); EXPECT_FALSE(task_run); // Shouldn't run as no DidCommitFrameToCompositor. @@ -203,8 +203,8 @@ EXPECT_FALSE(task_run); // We missed the deadline. scheduler_->WillBeginFrame(cc::BeginFrameArgs::Create( - clock_->Now(), base::TimeTicks(), base::TimeDelta::FromMilliseconds(1000), - cc::BeginFrameArgs::NORMAL)); + BEGINFRAME_FROM_HERE, clock_->Now(), base::TimeTicks(), + base::TimeDelta::FromMilliseconds(1000), cc::BeginFrameArgs::NORMAL)); clock_->AdvanceNow(base::TimeDelta::FromMilliseconds(800)); scheduler_->DidCommitFrameToCompositor(); RunUntilIdle();
diff --git a/content/shell/android/shell_apk/AndroidManifest.xml b/content/shell/android/shell_apk/AndroidManifest.xml index e1529f4..4df60274 100644 --- a/content/shell/android/shell_apk/AndroidManifest.xml +++ b/content/shell/android/shell_apk/AndroidManifest.xml
@@ -137,6 +137,7 @@ <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> + <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
diff --git a/content/shell/browser/shell_devtools_frontend.cc b/content/shell/browser/shell_devtools_frontend.cc index 489db60d..e7fe05cc 100644 --- a/content/shell/browser/shell_devtools_frontend.cc +++ b/content/shell/browser/shell_devtools_frontend.cc
@@ -43,7 +43,7 @@ DevToolsHttpHandler* http_handler = ShellContentBrowserClient::Get() ->shell_browser_main_parts() ->devtools_http_handler(); - shell->LoadURL(http_handler->GetFrontendURL()); + shell->LoadURL(http_handler->GetFrontendURL("/devtools/devtools.html")); return devtools_frontend; }
diff --git a/content/shell/browser/shell_devtools_manager_delegate.cc b/content/shell/browser/shell_devtools_manager_delegate.cc index ef188e3c..04e97f4 100644 --- a/content/shell/browser/shell_devtools_manager_delegate.cc +++ b/content/shell/browser/shell_devtools_manager_delegate.cc
@@ -232,8 +232,6 @@ std::string frontend_url; #if defined(OS_ANDROID) frontend_url = base::StringPrintf(kFrontEndURL, GetWebKitRevision().c_str()); -#else - frontend_url = "/devtools/devtools.html"; #endif return DevToolsHttpHandler::Start(CreateSocketFactory(), frontend_url,
diff --git a/content/shell/renderer/test_runner/web_ax_object_proxy.cc b/content/shell/renderer/test_runner/web_ax_object_proxy.cc index 3d7f17d..2ffc21f0 100644 --- a/content/shell/renderer/test_runner/web_ax_object_proxy.cc +++ b/content/shell/renderer/test_runner/web_ax_object_proxy.cc
@@ -80,8 +80,6 @@ return result.append("Div"); case blink::WebAXRoleDocument: return result.append("Document"); - case blink::WebAXRoleEditableText: - return result.append("EditableText"); case blink::WebAXRoleEmbeddedObject: return result.append("EmbeddedObject"); case blink::WebAXRoleFigcaption: @@ -96,8 +94,6 @@ return result.append("Grid"); case blink::WebAXRoleGroup: return result.append("Group"); - case blink::WebAXRoleGrowArea: - return result.append("GrowArea"); case blink::WebAXRoleHeading: return result.append("Heading"); case blink::WebAXRoleIgnored: @@ -204,8 +200,6 @@ return result.append("SpinButtonPart"); case blink::WebAXRoleSpinButton: return result.append("SpinButton"); - case blink::WebAXRoleSplitGroup: - return result.append("SplitGroup"); case blink::WebAXRoleSplitter: return result.append("Splitter"); case blink::WebAXRoleStaticText: @@ -297,13 +291,6 @@ return title.insert(0, "AXTitle: "); } -std::string GetOrientation(const blink::WebAXObject& object) { - if (object.isVertical()) - return "AXOrientation: AXVerticalOrientation"; - - return "AXOrientation: AXHorizontalOrientation"; -} - std::string GetValueDescription(const blink::WebAXObject& object) { std::string value_description = object.valueDescription().utf8(); return value_description.insert(0, "AXValueDescription: "); @@ -776,7 +763,13 @@ std::string WebAXObjectProxy::Orientation() { accessibility_object_.updateLayoutAndCheckValidity(); - return GetOrientation(accessibility_object_); + if (accessibility_object_.orientation() == blink::WebAXOrientationVertical) + return "AXOrientation: AXVerticalOrientation"; + else if (accessibility_object_.orientation() + == blink::WebAXOrientationHorizontal) + return "AXOrientation: AXHorizontalOrientation"; + + return std::string(); } int WebAXObjectProxy::ClickPointX() {
diff --git a/content/test/browser_side_navigation_test_utils.h b/content/test/browser_side_navigation_test_utils.h index 77c9ef3..a2daa6e1 100644 --- a/content/test/browser_side_navigation_test_utils.h +++ b/content/test/browser_side_navigation_test_utils.h
@@ -26,6 +26,10 @@ // from the IO thread with a TestNavigationURLLoader. scoped_ptr<StreamHandle> MakeEmptyStream(); +// If a test needs to run with browser side navigation enabled, call this +// function before doing any setup. In particular, for tests inheriting from +// RenderViewHostTestHarness, call this function before calling +// RenderViewHostTestHarness::SetUp. void EnableBrowserSideNavigation(); } // namespace content
diff --git a/content/test/data/accessibility/aria-directory-expected-android.txt b/content/test/data/accessibility/aria-directory-expected-android.txt new file mode 100644 index 0000000..1282ba2 --- /dev/null +++ b/content/test/data/accessibility/aria-directory-expected-android.txt
@@ -0,0 +1,2 @@ +android.webkit.WebView focusable focused scrollable + android.widget.ListView collection hierarchical
diff --git a/content/test/data/accessibility/aria-directory-expected-mac.txt b/content/test/data/accessibility/aria-directory-expected-mac.txt new file mode 100644 index 0000000..6fc9a911 --- /dev/null +++ b/content/test/data/accessibility/aria-directory-expected-mac.txt
@@ -0,0 +1,2 @@ +AXWebArea AXRoleDescription='HTML content' + AXList AXSubrole=AXContentList AXRoleDescription='list'
diff --git a/content/test/data/accessibility/aria-directory-expected-win.txt b/content/test/data/accessibility/aria-directory-expected-win.txt new file mode 100644 index 0000000..4ba996a --- /dev/null +++ b/content/test/data/accessibility/aria-directory-expected-win.txt
@@ -0,0 +1,2 @@ +ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE + ROLE_SYSTEM_LIST READONLY xml-roles:directory
diff --git a/content/test/data/accessibility/aria-directory.html b/content/test/data/accessibility/aria-directory.html new file mode 100644 index 0000000..236f8e3 --- /dev/null +++ b/content/test/data/accessibility/aria-directory.html
@@ -0,0 +1,13 @@ +<!-- +@MAC-ALLOW:AXRole* +@MAC-ALLOW:AXSubrole* +@WIN-ALLOW:xml-roles:* +@WIN-DENY:name* +--> +<!DOCTYPE html> +<html> +<body> + <div role="directory"> + </div> +</body> +</html>
diff --git a/content/test/data/accessibility/aria-list-expected-mac.txt b/content/test/data/accessibility/aria-list-expected-mac.txt index d1715c2..2504eab 100644 --- a/content/test/data/accessibility/aria-list-expected-mac.txt +++ b/content/test/data/accessibility/aria-list-expected-mac.txt
@@ -1,5 +1,5 @@ AXWebArea - AXList AXSubrole=AXContentList AXOrientation='AXVerticalOrientation' AXSelectedChildren=[] AXVisibleChildren=["AXGroup group 1","AXGroup group 2","AXGroup group 3"] + AXList AXSubrole=AXContentList AXSelectedChildren=[] AXVisibleChildren=["AXGroup group 1","AXGroup group 2","AXGroup group 3"] AXGroup AXTitle='Item 1' AXStaticText AXValue='Item 1' AXGroup AXTitle='Item 2'
diff --git a/content/test/data/accessibility/aria-list.html b/content/test/data/accessibility/aria-list.html index 1aa4cd1..2dad514 100644 --- a/content/test/data/accessibility/aria-list.html +++ b/content/test/data/accessibility/aria-list.html
@@ -1,6 +1,5 @@ <!-- @MAC-ALLOW:AXSubrole* -@MAC-ALLOW:AXOrientation* @MAC-ALLOW:AXSelectedChildren* @MAC-ALLOW:AXVisibleChildren* -->
diff --git a/content/test/data/accessibility/aria-multiline-expected-android.txt b/content/test/data/accessibility/aria-multiline-expected-android.txt new file mode 100644 index 0000000..15c00cd9 --- /dev/null +++ b/content/test/data/accessibility/aria-multiline-expected-android.txt
@@ -0,0 +1,4 @@ +android.webkit.WebView focusable focused scrollable + android.widget.EditText editable_text + android.widget.EditText editable_text multiline +
diff --git a/content/test/data/accessibility/aria-multiline-expected-mac.txt b/content/test/data/accessibility/aria-multiline-expected-mac.txt new file mode 100644 index 0000000..954da6d --- /dev/null +++ b/content/test/data/accessibility/aria-multiline-expected-mac.txt
@@ -0,0 +1,3 @@ +AXWebArea AXRoleDescription='HTML content' + AXTextField AXRoleDescription='text field' + AXTextArea AXRoleDescription='text entry area'
diff --git a/content/test/data/accessibility/aria-multiline-expected-win.txt b/content/test/data/accessibility/aria-multiline-expected-win.txt new file mode 100644 index 0000000..83c2aab0 --- /dev/null +++ b/content/test/data/accessibility/aria-multiline-expected-win.txt
@@ -0,0 +1,3 @@ +ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE + ROLE_SYSTEM_TEXT IA2_STATE_SINGLE_LINE xml-roles:textbox + ROLE_SYSTEM_TEXT IA2_STATE_MULTI_LINE xml-roles:textbox
diff --git a/content/test/data/accessibility/aria-multiline.html b/content/test/data/accessibility/aria-multiline.html new file mode 100644 index 0000000..e8186a9 --- /dev/null +++ b/content/test/data/accessibility/aria-multiline.html
@@ -0,0 +1,13 @@ +<!-- +@MAC-ALLOW:AXRole* +@WIN-ALLOW:IA2_STATE_SINGLE_LINE +@WIN-ALLOW:IA2_STATE_MULTI_LINE +@WIN-ALLOW:xml-roles* +--> +<!DOCTYPE html> +<html> +<body> + <div role="textbox" aria-multiline="false"></div> + <div role="textbox" aria-multiline="true"></div> +</body> +</html>
diff --git a/content/test/data/accessibility/aria-orientation-expected-android.txt b/content/test/data/accessibility/aria-orientation-expected-android.txt index 4a64843..975ee10 100644 --- a/content/test/data/accessibility/aria-orientation-expected-android.txt +++ b/content/test/data/accessibility/aria-orientation-expected-android.txt
@@ -1,3 +1,40 @@ android.webkit.WebView focusable focused scrollable - android.view.View range range_max=17 range_current_value=14 - android.view.View range range_max=17 range_current_value=14 + android.widget.Spinner + android.widget.Spinner + android.widget.Spinner + android.widget.ListView collection + android.widget.ListView collection + android.widget.ListView collection + android.view.View + android.view.View + android.view.View + android.view.View + android.view.View + android.view.View + android.view.View + android.view.View + android.view.View + android.view.View range + android.view.View range + android.view.View range + android.widget.SeekBar range item_count=100 + android.widget.SeekBar range item_count=100 + android.widget.SeekBar range item_count=100 + android.view.View + android.view.View + android.view.View + android.widget.TabWidget + android.widget.TabWidget + android.widget.TabWidget + android.view.View + android.view.View + android.view.View + android.view.View collection hierarchical + android.view.View collection hierarchical + android.view.View collection hierarchical + android.widget.GridView collection + android.view.View + android.widget.GridView collection + android.view.View + android.widget.GridView collection + android.view.View
diff --git a/content/test/data/accessibility/aria-orientation-expected-mac.txt b/content/test/data/accessibility/aria-orientation-expected-mac.txt index c66bcc19..fb1288f 100644 --- a/content/test/data/accessibility/aria-orientation-expected-mac.txt +++ b/content/test/data/accessibility/aria-orientation-expected-mac.txt
@@ -1,3 +1,40 @@ AXWebArea - AXScrollBar AXValue='14' AXOrientation='AXHorizontalOrientation' - AXScrollBar AXValue='14' AXOrientation='AXVerticalOrientation' + AXComboBox AXOrientation='AXVerticalOrientation' + AXComboBox AXOrientation='AXHorizontalOrientation' + AXComboBox AXOrientation='AXVerticalOrientation' + AXList AXOrientation='AXVerticalOrientation' + AXList AXOrientation='AXHorizontalOrientation' + AXList AXOrientation='AXVerticalOrientation' + AXMenu AXOrientation='AXVerticalOrientation' + AXMenu AXOrientation='AXHorizontalOrientation' + AXMenu AXOrientation='AXVerticalOrientation' + AXMenuBar AXOrientation='AXHorizontalOrientation' + AXMenuBar AXOrientation='AXHorizontalOrientation' + AXMenuBar AXOrientation='AXVerticalOrientation' + AXRadioGroup + AXRadioGroup AXOrientation='AXHorizontalOrientation' + AXRadioGroup AXOrientation='AXVerticalOrientation' + AXScrollBar AXValue='0' AXOrientation='AXVerticalOrientation' + AXScrollBar AXValue='0' AXOrientation='AXHorizontalOrientation' + AXScrollBar AXValue='0' AXOrientation='AXVerticalOrientation' + AXSlider AXValue='0' AXOrientation='AXHorizontalOrientation' + AXSlider AXValue='0' AXOrientation='AXHorizontalOrientation' + AXSlider AXValue='0' AXOrientation='AXVerticalOrientation' + AXSplitter AXOrientation='AXHorizontalOrientation' + AXSplitter AXOrientation='AXHorizontalOrientation' + AXSplitter AXOrientation='AXVerticalOrientation' + AXTabGroup AXOrientation='AXHorizontalOrientation' + AXTabGroup AXOrientation='AXHorizontalOrientation' + AXTabGroup AXOrientation='AXVerticalOrientation' + AXToolbar AXOrientation='AXHorizontalOrientation' + AXToolbar AXOrientation='AXHorizontalOrientation' + AXToolbar AXOrientation='AXVerticalOrientation' + AXOutline AXOrientation='AXVerticalOrientation' + AXOutline AXOrientation='AXHorizontalOrientation' + AXOutline AXOrientation='AXVerticalOrientation' + AXTable + AXGroup + AXTable AXOrientation='AXHorizontalOrientation' + AXGroup + AXTable AXOrientation='AXVerticalOrientation' + AXGroup
diff --git a/content/test/data/accessibility/aria-orientation-expected-win.txt b/content/test/data/accessibility/aria-orientation-expected-win.txt index ff23a20..afcaede 100644 --- a/content/test/data/accessibility/aria-orientation-expected-win.txt +++ b/content/test/data/accessibility/aria-orientation-expected-win.txt
@@ -1,4 +1,40 @@ -#<skip -- need to generate correct expectations> ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE - ROLE_SYSTEM_SCROLLBAR - ROLE_SYSTEM_SCROLLBAR + ROLE_SYSTEM_COMBOBOX IA2_STATE_VERTICAL + ROLE_SYSTEM_COMBOBOX IA2_STATE_HORIZONTAL + ROLE_SYSTEM_COMBOBOX IA2_STATE_VERTICAL + ROLE_SYSTEM_LIST IA2_STATE_VERTICAL + ROLE_SYSTEM_LIST IA2_STATE_HORIZONTAL + ROLE_SYSTEM_LIST IA2_STATE_VERTICAL + ROLE_SYSTEM_MENUPOPUP IA2_STATE_VERTICAL + ROLE_SYSTEM_MENUPOPUP IA2_STATE_HORIZONTAL + ROLE_SYSTEM_MENUPOPUP IA2_STATE_VERTICAL + ROLE_SYSTEM_MENUBAR IA2_STATE_HORIZONTAL + ROLE_SYSTEM_MENUBAR IA2_STATE_HORIZONTAL + ROLE_SYSTEM_MENUBAR IA2_STATE_VERTICAL + ROLE_SYSTEM_GROUPING + ROLE_SYSTEM_GROUPING IA2_STATE_HORIZONTAL + ROLE_SYSTEM_GROUPING IA2_STATE_VERTICAL + ROLE_SYSTEM_SCROLLBAR IA2_STATE_VERTICAL + ROLE_SYSTEM_SCROLLBAR IA2_STATE_HORIZONTAL + ROLE_SYSTEM_SCROLLBAR IA2_STATE_VERTICAL + ROLE_SYSTEM_SLIDER IA2_STATE_HORIZONTAL + ROLE_SYSTEM_SLIDER IA2_STATE_HORIZONTAL + ROLE_SYSTEM_SLIDER IA2_STATE_VERTICAL + ROLE_SYSTEM_SEPARATOR IA2_STATE_HORIZONTAL + ROLE_SYSTEM_SEPARATOR IA2_STATE_HORIZONTAL + ROLE_SYSTEM_SEPARATOR IA2_STATE_VERTICAL + ROLE_SYSTEM_PAGETABLIST IA2_STATE_HORIZONTAL + ROLE_SYSTEM_PAGETABLIST IA2_STATE_HORIZONTAL + ROLE_SYSTEM_PAGETABLIST IA2_STATE_VERTICAL + ROLE_SYSTEM_TOOLBAR READONLY IA2_STATE_HORIZONTAL + ROLE_SYSTEM_TOOLBAR READONLY IA2_STATE_HORIZONTAL + ROLE_SYSTEM_TOOLBAR READONLY IA2_STATE_VERTICAL + ROLE_SYSTEM_OUTLINE IA2_STATE_VERTICAL + ROLE_SYSTEM_OUTLINE IA2_STATE_HORIZONTAL + ROLE_SYSTEM_OUTLINE IA2_STATE_VERTICAL + ROLE_SYSTEM_OUTLINE + IA2_ROLE_SECTION + ROLE_SYSTEM_OUTLINE IA2_STATE_HORIZONTAL + IA2_ROLE_SECTION + ROLE_SYSTEM_OUTLINE IA2_STATE_VERTICAL + IA2_ROLE_SECTION
diff --git a/content/test/data/accessibility/aria-orientation.html b/content/test/data/accessibility/aria-orientation.html index 1a23f5e9..88187b20 100644 --- a/content/test/data/accessibility/aria-orientation.html +++ b/content/test/data/accessibility/aria-orientation.html
@@ -1,11 +1,47 @@ <!-- @MAC-ALLOW:AXOrientation=* +@WIN-ALLOW:IA2_STATE_VERTICAL +@WIN-ALLOW:IA2_STATE_HORIZONTAL --> +<!DOCTYPE html> <html> <body> - <div id="horizontal" role="scrollbar" aria-orientation="horizontal" - aria-valuemin="0" aria-valuemax="17" aria-valuenow="14" > </div> - <div id="vertical" role="scrollbar" aria-orientation="vertical" - aria-valuemin="0" aria-valuemax="17" aria-valuenow="14" ></div> + <div role="combobox"></div> + <div role="combobox" aria-orientation="horizontal"> </div> + <div role="combobox" aria-orientation="vertical"></div> + <div role="listbox"></div> + <div role="listbox" aria-orientation="horizontal"> </div> + <div role="listbox" aria-orientation="vertical"></div> + <div role="menu"></div> + <div role="menu" aria-orientation="horizontal"> </div> + <div role="menu" aria-orientation="vertical"></div> + <div role="menubar"></div> + <div role="menubar" aria-orientation="horizontal"> </div> + <div role="menubar" aria-orientation="vertical"></div> + <div role="radiogroup"></div> + <div role="radiogroup" aria-orientation="horizontal"> </div> + <div role="radiogroup" aria-orientation="vertical"></div> + <div role="scrollbar"></div> + <div role="scrollbar" aria-orientation="horizontal"> </div> + <div role="scrollbar" aria-orientation="vertical"></div> + <div role="slider"></div> + <div role="slider" aria-orientation="horizontal"> </div> + <div role="slider" aria-orientation="vertical"></div> + <div role="separator"></div> + <div role="separator" aria-orientation="horizontal"> </div> + <div role="separator" aria-orientation="vertical"></div> + <div role="tablist"></div> + <div role="tablist" aria-orientation="horizontal"> </div> + <div role="tablist" aria-orientation="vertical"></div> + <div role="toolbar"></div> + <div role="toolbar" aria-orientation="horizontal"> </div> + <div role="toolbar" aria-orientation="vertical"></div> + <div role="tree"></div> + <div role="tree" aria-orientation="horizontal"> </div> + <div role="tree" aria-orientation="vertical"></div> + <div role="treegrid"></div> + <div role="treegrid" aria-orientation="horizontal"> </div> + <div role="treegrid" aria-orientation="vertical"></div> + </body> </html>
diff --git a/content/test/data/accessibility/aria-slider-expected-android.txt b/content/test/data/accessibility/aria-slider-expected-android.txt new file mode 100644 index 0000000..016d6d0 --- /dev/null +++ b/content/test/data/accessibility/aria-slider-expected-android.txt
@@ -0,0 +1,3 @@ +android.webkit.WebView focusable focused scrollable + android.widget.SeekBar range item_index=44 item_count=100 range_min=1 range_max=10 range_current_value=5 +
diff --git a/content/test/data/accessibility/aria-slider-expected-mac.txt b/content/test/data/accessibility/aria-slider-expected-mac.txt new file mode 100644 index 0000000..39d3a16 --- /dev/null +++ b/content/test/data/accessibility/aria-slider-expected-mac.txt
@@ -0,0 +1,2 @@ +AXWebArea AXRoleDescription='HTML content' + AXSlider AXRoleDescription='slider' AXValue='5'
diff --git a/content/test/data/accessibility/aria-slider-expected-win.txt b/content/test/data/accessibility/aria-slider-expected-win.txt new file mode 100644 index 0000000..af18ae3 --- /dev/null +++ b/content/test/data/accessibility/aria-slider-expected-win.txt
@@ -0,0 +1,2 @@ +ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE + ROLE_SYSTEM_SLIDER xml-roles:slider currentValue=5.00 minimumValue=1.00 maximumValue=10.00
diff --git a/content/test/data/accessibility/aria-slider.html b/content/test/data/accessibility/aria-slider.html new file mode 100644 index 0000000..0bed2405 --- /dev/null +++ b/content/test/data/accessibility/aria-slider.html
@@ -0,0 +1,14 @@ +<!-- +@MAC-ALLOW:AXRole* +@WIN-ALLOW:xml-roles:* +@WIN-ALLOW:currentValue* +@WIN-ALLOW:minimumValue* +@WIN-ALLOW:maximumValue* +@WIN-DENY:name* +--> +<!DOCTYPE html> +<html> +<body> + <div role="slider" aria-valuenow="5" aria-valuemin="1" aria-valuemax="10">Slider</div> +</body> +</html>
diff --git a/content/test/data/accessibility/aria-tooltip-expected-android.txt b/content/test/data/accessibility/aria-tooltip-expected-android.txt new file mode 100644 index 0000000..4094ee3 --- /dev/null +++ b/content/test/data/accessibility/aria-tooltip-expected-android.txt
@@ -0,0 +1,4 @@ +android.webkit.WebView focusable focused scrollable + android.view.View + android.widget.EditText clickable editable_text focusable name='Your username should be your email id' input_type=1 + android.view.View clickable name='Your username should be your email id'
diff --git a/content/test/data/accessibility/aria-tooltip-expected-mac.txt b/content/test/data/accessibility/aria-tooltip-expected-mac.txt new file mode 100644 index 0000000..023229d4 --- /dev/null +++ b/content/test/data/accessibility/aria-tooltip-expected-mac.txt
@@ -0,0 +1,5 @@ +AXWebArea AXRoleDescription='HTML content' + AXGroup AXRoleDescription='group' + AXTextField AXRoleDescription='text field' + AXGroup AXSubrole=AXUserInterfaceTooltip AXRoleDescription='tooltip' + AXStaticText AXRoleDescription='text' AXValue='Your username should be your email id'
diff --git a/content/test/data/accessibility/aria-tooltip-expected-win.txt b/content/test/data/accessibility/aria-tooltip-expected-win.txt new file mode 100644 index 0000000..3b9f36c --- /dev/null +++ b/content/test/data/accessibility/aria-tooltip-expected-win.txt
@@ -0,0 +1,5 @@ +ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE + IA2_ROLE_SECTION + ROLE_SYSTEM_TEXT FOCUSABLE + ROLE_SYSTEM_TOOLTIP READONLY xml-roles:tooltip + ROLE_SYSTEM_STATICTEXT
diff --git a/content/test/data/accessibility/aria-tooltip.html b/content/test/data/accessibility/aria-tooltip.html new file mode 100644 index 0000000..6032e13c --- /dev/null +++ b/content/test/data/accessibility/aria-tooltip.html
@@ -0,0 +1,13 @@ +<!-- +@MAC-ALLOW:AXRole* +@MAC-ALLOW:AXSubrole* +@WIN-ALLOW:xml-roles:* +@WIN-DENY:name* +--> +<!DOCTYPE html> +<html> +<body> + <input type="text" id="username" aria-describedby="username-tip" /> + <div role="tooltip" id="username-tip">Your username should be your email id</div> +</body> +</html>
diff --git a/content/test/data/accessibility/aria-treegrid-expected-android.txt b/content/test/data/accessibility/aria-treegrid-expected-android.txt new file mode 100644 index 0000000..c3802dd --- /dev/null +++ b/content/test/data/accessibility/aria-treegrid-expected-android.txt
@@ -0,0 +1,8 @@ +android.webkit.WebView focusable focused scrollable + android.widget.GridView collection row_count=2 column_count=1 + android.view.View + android.view.View clickable collection_item name='Cell at level 1' row_span=1 column_span=1 + android.view.View + android.view.View clickable collection_item name='Cell at level 2' row_index=1 row_span=1 column_span=1 + android.view.View + android.view.View
diff --git a/content/test/data/accessibility/aria-treegrid-expected-mac.txt b/content/test/data/accessibility/aria-treegrid-expected-mac.txt new file mode 100644 index 0000000..17f312d --- /dev/null +++ b/content/test/data/accessibility/aria-treegrid-expected-mac.txt
@@ -0,0 +1,10 @@ +AXWebArea + AXTable + AXRow AXDisclosureLevel='0' + AXCell + AXStaticText AXValue='Cell at level 1' + AXRow AXDisclosureLevel='1' + AXCell + AXStaticText AXValue='Cell at level 2' + AXColumn + AXGroup
diff --git a/content/test/data/accessibility/aria-treegrid-expected-win.txt b/content/test/data/accessibility/aria-treegrid-expected-win.txt new file mode 100644 index 0000000..ff767f12 --- /dev/null +++ b/content/test/data/accessibility/aria-treegrid-expected-win.txt
@@ -0,0 +1,10 @@ +ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE + ROLE_SYSTEM_OUTLINE xml-roles:treegrid + ROLE_SYSTEM_ROW xml-roles:row level:1 + ROLE_SYSTEM_CELL xml-roles:gridcell + ROLE_SYSTEM_STATICTEXT name='Cell at level 1' + ROLE_SYSTEM_ROW xml-roles:row level:2 + ROLE_SYSTEM_CELL xml-roles:gridcell + ROLE_SYSTEM_STATICTEXT name='Cell at level 2' + ROLE_SYSTEM_COLUMN + IA2_ROLE_SECTION
diff --git a/content/test/data/accessibility/aria-treegrid.html b/content/test/data/accessibility/aria-treegrid.html new file mode 100644 index 0000000..b5923c5f --- /dev/null +++ b/content/test/data/accessibility/aria-treegrid.html
@@ -0,0 +1,19 @@ +<!-- +@MAC-ALLOW:AXRole=* +@MAC-ALLOW:AXDisclosureLevel* +@WIN-ALLOW:xml-roles:* +@WIN-ALLOW:level* +--> +<!DOCTYPE html> +<html> +<body> + <table role="treegrid"> + <tr role="row" aria-level="1"> + <td role="gridcell">Cell at level 1</td> + </tr> + <tr role="row" aria-level="2"> + <td role="gridcell">Cell at level 2</td> + </tr> +</table> +</body> +</html>
diff --git a/content/test/data/file_input.html b/content/test/data/file_input.html new file mode 100644 index 0000000..64957b1 --- /dev/null +++ b/content/test/data/file_input.html
@@ -0,0 +1 @@ +<input type="file" id="fileinput" />
diff --git a/content/test/run_all_unittests.cc b/content/test/run_all_unittests.cc index ed61a5c0..58e3304 100644 --- a/content/test/run_all_unittests.cc +++ b/content/test/run_all_unittests.cc
@@ -11,12 +11,17 @@ #if defined(OS_ANDROID) #include "base/android/jni_android.h" #include "base/test/test_file_util.h" +#include "content/browser/gpu/browser_gpu_channel_host_factory.h" #endif int main(int argc, char** argv) { #if defined(OS_ANDROID) // Register JNI bindings for android. base::RegisterContentUriTestUtils(base::android::AttachCurrentThread()); + + // Android wants to call GetChannelId() (even though GPU channels + // are not getting created in content_unittests). + content::BrowserGpuChannelHostFactory::Initialize(false); #endif #if !defined(OS_IOS) content::InitializeMojo();
diff --git a/device/udev_linux/udev_loader.cc b/device/udev_linux/udev_loader.cc index 88b64e10..22f709e 100644 --- a/device/udev_linux/udev_loader.cc +++ b/device/udev_linux/udev_loader.cc
@@ -22,11 +22,19 @@ return g_udev_loader; scoped_ptr<UdevLoader> udev_loader; + // This is an ugly hack to get around the fact that a MSAN build on Precise + // will only build an instrumented copy of libudev0 and not libudev1. If one + // runs the binary on Trusty, it will end up loading an uninstrumented + // libudev1 at run time. http://crbug.com/437464 + // TODO(thestig): Remove this after upgrading our MSAN LKGR builders to + // Trusty. +#if !defined(MEMORY_SANITIZER) udev_loader.reset(new Udev1Loader); if (udev_loader->Init()) { g_udev_loader = udev_loader.release(); return g_udev_loader; } +#endif udev_loader.reset(new Udev0Loader); if (udev_loader->Init()) {
diff --git a/device/usb/usb_device_handle_impl.cc b/device/usb/usb_device_handle_impl.cc index 6f0e2868..eb125421 100644 --- a/device/usb/usb_device_handle_impl.cc +++ b/device/usb/usb_device_handle_impl.cc
@@ -151,37 +151,326 @@ return rv == LIBUSB_SUCCESS; } -struct UsbDeviceHandleImpl::Transfer { - Transfer(); +// This inner class owns the underlying libusb_transfer and may outlast +// the UsbDeviceHandle that created it. +class UsbDeviceHandleImpl::Transfer { + public: + static scoped_ptr<Transfer> CreateControlTransfer( + uint8 type, + uint8 request, + uint8 value, + uint8 index, + uint16 length, + scoped_refptr<net::IOBuffer> buffer, + unsigned int timeout, + const UsbTransferCallback& callback); + static scoped_ptr<Transfer> CreateBulkTransfer( + uint8 endpoint, + scoped_refptr<net::IOBuffer> buffer, + int length, + unsigned int timeout, + const UsbTransferCallback& callback); + static scoped_ptr<Transfer> CreateInterruptTransfer( + uint8 endpoint, + scoped_refptr<net::IOBuffer> buffer, + int length, + unsigned int timeout, + const UsbTransferCallback& callback); + static scoped_ptr<Transfer> CreateIsochronousTransfer( + uint8 endpoint, + scoped_refptr<net::IOBuffer> buffer, + size_t length, + unsigned int packets, + unsigned int packet_length, + unsigned int timeout, + const UsbTransferCallback& callback); + ~Transfer(); + bool Submit(base::WeakPtr<UsbDeviceHandleImpl> device_handle); + void Cancel(); + void ProcessCompletion(); void Complete(UsbTransferStatus status, size_t bytes_transferred); - UsbTransferType transfer_type; - scoped_refptr<net::IOBuffer> buffer; - scoped_refptr<UsbDeviceHandleImpl::InterfaceClaimer> claimed_interface; - scoped_refptr<base::SingleThreadTaskRunner> task_runner; - size_t length; - UsbTransferCallback callback; + const UsbDeviceHandleImpl::InterfaceClaimer* claimed_interface() const { + return claimed_interface_.get(); + } + + private: + Transfer(UsbTransferType transfer_type, + scoped_refptr<net::IOBuffer> buffer, + size_t length, + const UsbTransferCallback& callback); + + static void LIBUSB_CALL PlatformCallback(PlatformUsbTransferHandle handle); + + UsbTransferType transfer_type_; + base::WeakPtr<UsbDeviceHandleImpl> device_handle_; + PlatformUsbTransferHandle platform_transfer_; + scoped_refptr<net::IOBuffer> buffer_; + scoped_refptr<UsbDeviceHandleImpl::InterfaceClaimer> claimed_interface_; + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + size_t length_; + UsbTransferCallback callback_; + scoped_refptr<base::SingleThreadTaskRunner> callback_task_runner_; }; -UsbDeviceHandleImpl::Transfer::Transfer() - : transfer_type(USB_TRANSFER_CONTROL), length(0) { +// static +scoped_ptr<UsbDeviceHandleImpl::Transfer> +UsbDeviceHandleImpl::Transfer::CreateControlTransfer( + uint8 type, + uint8 request, + uint8 value, + uint8 index, + uint16 length, + scoped_refptr<net::IOBuffer> buffer, + unsigned int timeout, + const UsbTransferCallback& callback) { + scoped_ptr<Transfer> transfer(new Transfer(USB_TRANSFER_CONTROL, buffer, + length + LIBUSB_CONTROL_SETUP_SIZE, + callback)); + + transfer->platform_transfer_ = libusb_alloc_transfer(0); + if (!transfer->platform_transfer_) { + return nullptr; + } + + libusb_fill_control_setup(reinterpret_cast<uint8*>(buffer->data()), type, + request, value, index, length); + libusb_fill_control_transfer(transfer->platform_transfer_, + nullptr, /* filled in by Submit() */ + reinterpret_cast<uint8*>(buffer->data()), + &UsbDeviceHandleImpl::Transfer::PlatformCallback, + transfer.get(), timeout); + + return transfer.Pass(); +} + +// static +scoped_ptr<UsbDeviceHandleImpl::Transfer> +UsbDeviceHandleImpl::Transfer::CreateBulkTransfer( + uint8 endpoint, + scoped_refptr<net::IOBuffer> buffer, + int length, + unsigned int timeout, + const UsbTransferCallback& callback) { + scoped_ptr<Transfer> transfer( + new Transfer(USB_TRANSFER_BULK, buffer, length, callback)); + + transfer->platform_transfer_ = libusb_alloc_transfer(0); + if (!transfer->platform_transfer_) { + return nullptr; + } + + libusb_fill_bulk_transfer(transfer->platform_transfer_, + nullptr, /* filled in by Submit() */ + endpoint, reinterpret_cast<uint8*>(buffer->data()), + static_cast<int>(length), + &UsbDeviceHandleImpl::Transfer::PlatformCallback, + transfer.get(), timeout); + + return transfer.Pass(); +} + +// static +scoped_ptr<UsbDeviceHandleImpl::Transfer> +UsbDeviceHandleImpl::Transfer::CreateInterruptTransfer( + uint8 endpoint, + scoped_refptr<net::IOBuffer> buffer, + int length, + unsigned int timeout, + const UsbTransferCallback& callback) { + scoped_ptr<Transfer> transfer( + new Transfer(USB_TRANSFER_INTERRUPT, buffer, length, callback)); + + transfer->platform_transfer_ = libusb_alloc_transfer(0); + if (!transfer->platform_transfer_) { + return nullptr; + } + + libusb_fill_interrupt_transfer( + transfer->platform_transfer_, nullptr, /* filled in by Submit() */ + endpoint, reinterpret_cast<uint8*>(buffer->data()), + static_cast<int>(length), + &UsbDeviceHandleImpl::Transfer::PlatformCallback, transfer.get(), + timeout); + + return transfer.Pass(); +} + +// static +scoped_ptr<UsbDeviceHandleImpl::Transfer> +UsbDeviceHandleImpl::Transfer::CreateIsochronousTransfer( + uint8 endpoint, + scoped_refptr<net::IOBuffer> buffer, + size_t length, + unsigned int packets, + unsigned int packet_length, + unsigned int timeout, + const UsbTransferCallback& callback) { + DCHECK(packets <= length && (packets * packet_length) <= length) + << "transfer length is too small"; + + scoped_ptr<Transfer> transfer( + new Transfer(USB_TRANSFER_ISOCHRONOUS, buffer, length, callback)); + + transfer->platform_transfer_ = libusb_alloc_transfer(0); + if (!transfer->platform_transfer_) { + return nullptr; + } + + libusb_fill_iso_transfer( + transfer->platform_transfer_, nullptr, /* filled in by Submit() */ + endpoint, reinterpret_cast<uint8*>(buffer->data()), + static_cast<int>(length), packets, &Transfer::PlatformCallback, + transfer.get(), timeout); + libusb_set_iso_packet_lengths(transfer->platform_transfer_, packet_length); + + return transfer.Pass(); +} + +UsbDeviceHandleImpl::Transfer::Transfer(UsbTransferType transfer_type, + scoped_refptr<net::IOBuffer> buffer, + size_t length, + const UsbTransferCallback& callback) + : transfer_type_(transfer_type), + buffer_(buffer), + length_(length), + callback_(callback) { + // Remember the thread from which this transfer was created so that |callback| + // can be dispatched there. + callback_task_runner_ = base::ThreadTaskRunnerHandle::Get(); } UsbDeviceHandleImpl::Transfer::~Transfer() { + if (platform_transfer_) { + libusb_free_transfer(platform_transfer_); + } +} + +bool UsbDeviceHandleImpl::Transfer::Submit( + base::WeakPtr<UsbDeviceHandleImpl> device_handle) { + device_handle_ = device_handle; + // Remember the thread from which this transfer was submitted so that it can + // be marked complete there. + task_runner_ = base::ThreadTaskRunnerHandle::Get(); + // GetClaimedInterfaceForEndpoint may return nullptr. libusb_submit_transfer + // will fail if it requires an interface we didn't claim. + claimed_interface_ = device_handle->GetClaimedInterfaceForEndpoint( + platform_transfer_->endpoint); + platform_transfer_->dev_handle = device_handle_->handle_; + + const int rv = libusb_submit_transfer(platform_transfer_); + if (rv == LIBUSB_SUCCESS) { + return true; + } else { + VLOG(1) << "Failed to submit transfer: " + << ConvertPlatformUsbErrorToString(rv); + Complete(USB_TRANSFER_ERROR, 0); + return false; + } +} + +void UsbDeviceHandleImpl::Transfer::Cancel() { + libusb_cancel_transfer(platform_transfer_); +} + +void UsbDeviceHandleImpl::Transfer::ProcessCompletion() { + DCHECK_GE(platform_transfer_->actual_length, 0) + << "Negative actual length received"; + size_t actual_length = + static_cast<size_t>(std::max(platform_transfer_->actual_length, 0)); + + DCHECK(length_ >= actual_length) + << "data too big for our buffer (libusb failure?)"; + + switch (transfer_type_) { + case USB_TRANSFER_CONTROL: + // If the transfer is a control transfer we do not expose the control + // setup header to the caller. This logic strips off the header if + // present before invoking the callback provided with the transfer. + if (actual_length > 0) { + CHECK(length_ >= LIBUSB_CONTROL_SETUP_SIZE) + << "buffer was not correctly set: too small for the control header"; + + if (length_ >= (LIBUSB_CONTROL_SETUP_SIZE + actual_length)) { + // If the payload is zero bytes long, pad out the allocated buffer + // size to one byte so that an IOBuffer of that size can be allocated. + scoped_refptr<net::IOBuffer> resized_buffer = + new net::IOBuffer(static_cast<int>( + std::max(actual_length, static_cast<size_t>(1)))); + memcpy(resized_buffer->data(), + buffer_->data() + LIBUSB_CONTROL_SETUP_SIZE, actual_length); + buffer_ = resized_buffer; + } + } + break; + + case USB_TRANSFER_ISOCHRONOUS: + // Isochronous replies might carry data in the different isoc packets even + // if the transfer actual_data value is zero. Furthermore, not all of the + // received packets might contain data, so we need to calculate how many + // data bytes we are effectively providing and pack the results. + if (actual_length == 0) { + size_t packet_buffer_start = 0; + for (int i = 0; i < platform_transfer_->num_iso_packets; ++i) { + PlatformUsbIsoPacketDescriptor packet = + &platform_transfer_->iso_packet_desc[i]; + if (packet->actual_length > 0) { + // We don't need to copy as long as all packets until now provide + // all the data the packet can hold. + if (actual_length < packet_buffer_start) { + CHECK(packet_buffer_start + packet->actual_length <= length_); + memmove(buffer_->data() + actual_length, + buffer_->data() + packet_buffer_start, + packet->actual_length); + } + actual_length += packet->actual_length; + } + + packet_buffer_start += packet->length; + } + } + break; + + case USB_TRANSFER_BULK: + case USB_TRANSFER_INTERRUPT: + break; + + default: + NOTREACHED() << "Invalid usb transfer type"; + break; + } + + Complete(ConvertTransferStatus(platform_transfer_->status), actual_length); } void UsbDeviceHandleImpl::Transfer::Complete(UsbTransferStatus status, size_t bytes_transferred) { - if (task_runner->RunsTasksOnCurrentThread()) { - callback.Run(status, buffer, bytes_transferred); + if (callback_task_runner_->RunsTasksOnCurrentThread()) { + callback_.Run(status, buffer_, bytes_transferred); } else { - task_runner->PostTask( - FROM_HERE, base::Bind(callback, status, buffer, bytes_transferred)); + callback_task_runner_->PostTask( + FROM_HERE, base::Bind(callback_, status, buffer_, bytes_transferred)); } } +/* static */ +void LIBUSB_CALL UsbDeviceHandleImpl::Transfer::PlatformCallback( + PlatformUsbTransferHandle platform_transfer) { + scoped_ptr<Transfer> transfer( + reinterpret_cast<Transfer*>(platform_transfer->user_data)); + DCHECK(transfer->platform_transfer_ == platform_transfer); + + // Because device_handle_ is a weak pointer it is guaranteed that the callback + // will be discarded if the handle has been freed. + Transfer* tmp_transfer = transfer.get(); // base::Passed invalidates transfer + tmp_transfer->task_runner_->PostTask( + FROM_HERE, base::Bind(&UsbDeviceHandleImpl::CompleteTransfer, + tmp_transfer->device_handle_, + base::Passed(&transfer))); +} + UsbDeviceHandleImpl::UsbDeviceHandleImpl(scoped_refptr<UsbContext> context, UsbDeviceImpl* device, PlatformUsbDeviceHandle handle, @@ -190,6 +479,7 @@ handle_(handle), config_(config), context_(context), + weak_factory_(this), task_runner_(base::ThreadTaskRunnerHandle::Get()) { DCHECK(handle) << "Cannot create device with NULL handle."; } @@ -239,10 +529,10 @@ // Cancel all the transfers on that interface. InterfaceClaimer* interface_claimer = claimed_interfaces_[interface_number].get(); - for (TransferMap::iterator it = transfers_.begin(); it != transfers_.end(); - ++it) { - if (it->second.claimed_interface.get() == interface_claimer) - libusb_cancel_transfer(it->first); + for (Transfer* transfer : transfers_) { + if (transfer->claimed_interface() == interface_claimer) { + transfer->Cancel(); + } } claimed_interfaces_.erase(interface_number); @@ -335,19 +625,19 @@ return false; } -void UsbDeviceHandleImpl::ControlTransfer( - const UsbEndpointDirection direction, - const TransferRequestType request_type, - const TransferRecipient recipient, - const uint8 request, - const uint16 value, - const uint16 index, - net::IOBuffer* buffer, - const size_t length, - const unsigned int timeout, - const UsbTransferCallback& callback) { - if (!device_) { - callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0); +void UsbDeviceHandleImpl::ControlTransfer(UsbEndpointDirection direction, + TransferRequestType request_type, + TransferRecipient recipient, + uint8 request, + uint16 value, + uint16 index, + net::IOBuffer* buffer, + size_t length, + unsigned int timeout, + const UsbTransferCallback& callback) { + if (length > UINT16_MAX) { + LOG(ERROR) << "Transfer too long."; + callback.Run(USB_TRANSFER_ERROR, buffer, 0); return; } @@ -358,31 +648,18 @@ callback.Run(USB_TRANSFER_ERROR, buffer, 0); return; } - memcpy(resized_buffer->data() + LIBUSB_CONTROL_SETUP_SIZE, - buffer->data(), - static_cast<int>(length)); + memcpy(resized_buffer->data() + LIBUSB_CONTROL_SETUP_SIZE, buffer->data(), + length); - PlatformUsbTransferHandle const transfer = libusb_alloc_transfer(0); - const uint8 converted_type = - CreateRequestType(direction, request_type, recipient); - libusb_fill_control_setup(reinterpret_cast<uint8*>(resized_buffer->data()), - converted_type, - request, - value, - index, - static_cast<int16>(length)); - libusb_fill_control_transfer(transfer, - handle_, - reinterpret_cast<uint8*>(resized_buffer->data()), - &UsbDeviceHandleImpl::PlatformTransferCallback, - this, - timeout); + scoped_ptr<Transfer> transfer = Transfer::CreateControlTransfer( + CreateRequestType(direction, request_type, recipient), request, value, + index, static_cast<uint16>(length), resized_buffer, timeout, callback); + if (!transfer) { + callback.Run(USB_TRANSFER_ERROR, buffer, 0); + return; + } - PostOrSubmitTransfer(transfer, - USB_TRANSFER_CONTROL, - resized_buffer.get(), - resized_length, - callback); + PostOrSubmitTransfer(transfer.Pass()); } void UsbDeviceHandleImpl::BulkTransfer(const UsbEndpointDirection direction, @@ -391,50 +668,37 @@ const size_t length, const unsigned int timeout, const UsbTransferCallback& callback) { - if (!device_) { - callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0); + if (length > INT_MAX) { + LOG(ERROR) << "Transfer too long."; + callback.Run(USB_TRANSFER_ERROR, buffer, 0); return; } - PlatformUsbTransferHandle const transfer = libusb_alloc_transfer(0); - const uint8 new_endpoint = ConvertTransferDirection(direction) | endpoint; - libusb_fill_bulk_transfer(transfer, - handle_, - new_endpoint, - reinterpret_cast<uint8*>(buffer->data()), - static_cast<int>(length), - &UsbDeviceHandleImpl::PlatformTransferCallback, - this, - timeout); + scoped_ptr<Transfer> transfer = Transfer::CreateBulkTransfer( + ConvertTransferDirection(direction) | endpoint, buffer, + static_cast<int>(length), timeout, callback); - PostOrSubmitTransfer(transfer, USB_TRANSFER_BULK, buffer, length, callback); + PostOrSubmitTransfer(transfer.Pass()); } void UsbDeviceHandleImpl::InterruptTransfer( - const UsbEndpointDirection direction, - const uint8 endpoint, + UsbEndpointDirection direction, + uint8 endpoint, net::IOBuffer* buffer, - const size_t length, - const unsigned int timeout, + size_t length, + unsigned int timeout, const UsbTransferCallback& callback) { - if (!device_) { - callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0); + if (length > INT_MAX) { + LOG(ERROR) << "Transfer too long."; + callback.Run(USB_TRANSFER_ERROR, buffer, 0); return; } - PlatformUsbTransferHandle const transfer = libusb_alloc_transfer(0); - const uint8 new_endpoint = ConvertTransferDirection(direction) | endpoint; - libusb_fill_interrupt_transfer(transfer, - handle_, - new_endpoint, - reinterpret_cast<uint8*>(buffer->data()), - static_cast<int>(length), - &UsbDeviceHandleImpl::PlatformTransferCallback, - this, - timeout); + scoped_ptr<Transfer> transfer = Transfer::CreateInterruptTransfer( + ConvertTransferDirection(direction) | endpoint, buffer, + static_cast<int>(length), timeout, callback); - PostOrSubmitTransfer( - transfer, USB_TRANSFER_INTERRUPT, buffer, length, callback); + PostOrSubmitTransfer(transfer.Pass()); } void UsbDeviceHandleImpl::IsochronousTransfer( @@ -446,30 +710,17 @@ const unsigned int packet_length, const unsigned int timeout, const UsbTransferCallback& callback) { - if (!device_) { - callback.Run(USB_TRANSFER_DISCONNECT, buffer, 0); + if (length > INT_MAX) { + LOG(ERROR) << "Transfer too long."; + callback.Run(USB_TRANSFER_ERROR, buffer, 0); return; } - const uint64 total_length = packets * packet_length; - CHECK(packets <= length && total_length <= length) - << "transfer length is too small"; + scoped_ptr<Transfer> transfer = Transfer::CreateIsochronousTransfer( + ConvertTransferDirection(direction) | endpoint, buffer, + static_cast<int>(length), packets, packet_length, timeout, callback); - PlatformUsbTransferHandle const transfer = libusb_alloc_transfer(packets); - const uint8 new_endpoint = ConvertTransferDirection(direction) | endpoint; - libusb_fill_iso_transfer(transfer, - handle_, - new_endpoint, - reinterpret_cast<uint8*>(buffer->data()), - static_cast<int>(length), - packets, - &UsbDeviceHandleImpl::PlatformTransferCallback, - this, - timeout); - libusb_set_iso_packet_lengths(transfer, packet_length); - - PostOrSubmitTransfer( - transfer, USB_TRANSFER_ISOCHRONOUS, buffer, length, callback); + PostOrSubmitTransfer(transfer.Pass()); } void UsbDeviceHandleImpl::RefreshEndpointMap() { @@ -503,155 +754,35 @@ return NULL; } -void UsbDeviceHandleImpl::PostOrSubmitTransfer( - PlatformUsbTransferHandle transfer, - UsbTransferType transfer_type, - net::IOBuffer* buffer, - size_t length, - const UsbTransferCallback& callback) { +void UsbDeviceHandleImpl::PostOrSubmitTransfer(scoped_ptr<Transfer> transfer) { if (task_runner_->RunsTasksOnCurrentThread()) { - SubmitTransfer(transfer, - transfer_type, - buffer, - length, - base::ThreadTaskRunnerHandle::Get(), - callback); + SubmitTransfer(transfer.Pass()); } else { - task_runner_->PostTask(FROM_HERE, - base::Bind(&UsbDeviceHandleImpl::SubmitTransfer, - this, - transfer, - transfer_type, - make_scoped_refptr(buffer), - length, - base::ThreadTaskRunnerHandle::Get(), - callback)); + task_runner_->PostTask( + FROM_HERE, base::Bind(&UsbDeviceHandleImpl::SubmitTransfer, this, + base::Passed(&transfer))); } } -void UsbDeviceHandleImpl::SubmitTransfer( - PlatformUsbTransferHandle handle, - UsbTransferType transfer_type, - net::IOBuffer* buffer, - const size_t length, - scoped_refptr<base::SingleThreadTaskRunner> task_runner, - const UsbTransferCallback& callback) { +void UsbDeviceHandleImpl::SubmitTransfer(scoped_ptr<Transfer> transfer) { DCHECK(thread_checker_.CalledOnValidThread()); - Transfer transfer; - transfer.transfer_type = transfer_type; - transfer.buffer = buffer; - transfer.length = length; - transfer.callback = callback; - transfer.task_runner = task_runner; - - if (!device_) { - transfer.Complete(USB_TRANSFER_DISCONNECT, 0); - return; - } - - // It's OK for this method to return NULL. libusb_submit_transfer will fail if - // it requires an interface we didn't claim. - transfer.claimed_interface = GetClaimedInterfaceForEndpoint(handle->endpoint); - - const int rv = libusb_submit_transfer(handle); - if (rv == LIBUSB_SUCCESS) { - transfers_[handle] = transfer; + if (device_) { + if (transfer->Submit(weak_factory_.GetWeakPtr())) { + // Transfer is now owned by libusb until its completion callback is run. + // This object holds a weak reference. + transfers_.insert(transfer.release()); + } } else { - VLOG(1) << "Failed to submit transfer: " - << ConvertPlatformUsbErrorToString(rv); - transfer.Complete(USB_TRANSFER_ERROR, 0); + transfer->Complete(USB_TRANSFER_DISCONNECT, 0); } } -/* static */ -void LIBUSB_CALL UsbDeviceHandleImpl::PlatformTransferCallback( - PlatformUsbTransferHandle transfer) { - UsbDeviceHandleImpl* device_handle = - reinterpret_cast<UsbDeviceHandleImpl*>(transfer->user_data); - device_handle->task_runner_->PostTask( - FROM_HERE, - base::Bind( - &UsbDeviceHandleImpl::CompleteTransfer, device_handle, transfer)); -} - -void UsbDeviceHandleImpl::CompleteTransfer(PlatformUsbTransferHandle handle) { - DCHECK(ContainsKey(transfers_, handle)) << "Missing transfer completed"; - - Transfer transfer = transfers_[handle]; - transfers_.erase(handle); - - DCHECK_GE(handle->actual_length, 0) << "Negative actual length received"; - size_t actual_length = - static_cast<size_t>(std::max(handle->actual_length, 0)); - - DCHECK(transfer.length >= actual_length) - << "data too big for our buffer (libusb failure?)"; - - switch (transfer.transfer_type) { - case USB_TRANSFER_CONTROL: - // If the transfer is a control transfer we do not expose the control - // setup header to the caller. This logic strips off the header if - // present before invoking the callback provided with the transfer. - if (actual_length > 0) { - CHECK(transfer.length >= LIBUSB_CONTROL_SETUP_SIZE) - << "buffer was not correctly set: too small for the control header"; - - if (transfer.length >= (LIBUSB_CONTROL_SETUP_SIZE + actual_length)) { - // If the payload is zero bytes long, pad out the allocated buffer - // size to one byte so that an IOBuffer of that size can be allocated. - scoped_refptr<net::IOBuffer> resized_buffer = - new net::IOBuffer(static_cast<int>( - std::max(actual_length, static_cast<size_t>(1)))); - memcpy(resized_buffer->data(), - transfer.buffer->data() + LIBUSB_CONTROL_SETUP_SIZE, - actual_length); - transfer.buffer = resized_buffer; - } - } - break; - - case USB_TRANSFER_ISOCHRONOUS: - // Isochronous replies might carry data in the different isoc packets even - // if the transfer actual_data value is zero. Furthermore, not all of the - // received packets might contain data, so we need to calculate how many - // data bytes we are effectively providing and pack the results. - if (actual_length == 0) { - size_t packet_buffer_start = 0; - for (int i = 0; i < handle->num_iso_packets; ++i) { - PlatformUsbIsoPacketDescriptor packet = &handle->iso_packet_desc[i]; - if (packet->actual_length > 0) { - // We don't need to copy as long as all packets until now provide - // all the data the packet can hold. - if (actual_length < packet_buffer_start) { - CHECK(packet_buffer_start + packet->actual_length <= - transfer.length); - memmove(transfer.buffer->data() + actual_length, - transfer.buffer->data() + packet_buffer_start, - packet->actual_length); - } - actual_length += packet->actual_length; - } - - packet_buffer_start += packet->length; - } - } - break; - - case USB_TRANSFER_BULK: - case USB_TRANSFER_INTERRUPT: - break; - - default: - NOTREACHED() << "Invalid usb transfer type"; - break; - } - - transfer.Complete(ConvertTransferStatus(handle->status), actual_length); - libusb_free_transfer(handle); - - // Must release interface first before actually delete this. - transfer.claimed_interface = NULL; +void UsbDeviceHandleImpl::CompleteTransfer(scoped_ptr<Transfer> transfer) { + DCHECK(ContainsKey(transfers_, transfer.get())) + << "Missing transfer completed"; + transfers_.erase(transfer.get()); + transfer->ProcessCompletion(); } bool UsbDeviceHandleImpl::GetSupportedLanguages() { @@ -694,10 +825,9 @@ return; // Cancel all the transfers. - for (TransferMap::iterator it = transfers_.begin(); it != transfers_.end(); - ++it) { + for (Transfer* transfer : transfers_) { // The callback will be called some time later. - libusb_cancel_transfer(it->first); + transfer->Cancel(); } // Attempt-release all the interfaces.
diff --git a/device/usb/usb_device_handle_impl.h b/device/usb/usb_device_handle_impl.h index 4488ec9..682cefd 100644 --- a/device/usb/usb_device_handle_impl.h +++ b/device/usb/usb_device_handle_impl.h
@@ -6,10 +6,12 @@ #define DEVICE_USB_USB_DEVICE_HANDLE_IMPL_H_ #include <map> +#include <set> #include <vector> #include "base/callback.h" #include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" #include "base/strings/string16.h" #include "base/threading/thread_checker.h" #include "device/usb/usb_device_handle.h" @@ -90,8 +92,10 @@ ~UsbDeviceHandleImpl() override; private: + friend class Transfer; + class InterfaceClaimer; - struct Transfer; + class Transfer; // Refresh endpoint_map_ after ClaimInterface, ReleaseInterface and // SetInterfaceAlternateSetting. @@ -106,28 +110,16 @@ // be submitted directly, otherwise a task to do so it posted. The callback // will be called on the current message loop of the thread where this // function was called. - void PostOrSubmitTransfer(PlatformUsbTransferHandle handle, - UsbTransferType transfer_type, - net::IOBuffer* buffer, - size_t length, - const UsbTransferCallback& callback); + void PostOrSubmitTransfer(scoped_ptr<Transfer> transfer); // Submits a transfer and starts tracking it. Retains the buffer and copies // the completion callback until the transfer finishes, whereupon it invokes // the callback then releases the buffer. - void SubmitTransfer(PlatformUsbTransferHandle handle, - UsbTransferType transfer_type, - net::IOBuffer* buffer, - const size_t length, - scoped_refptr<base::SingleThreadTaskRunner> task_runner, - const UsbTransferCallback& callback); - - static void LIBUSB_CALL - PlatformTransferCallback(PlatformUsbTransferHandle handle); + void SubmitTransfer(scoped_ptr<Transfer> transfer); // Invokes the callbacks associated with a given transfer, and removes it from // the in-flight transfer set. - void CompleteTransfer(PlatformUsbTransferHandle transfer); + void CompleteTransfer(scoped_ptr<Transfer> transfer); bool GetSupportedLanguages(); @@ -143,11 +135,11 @@ std::vector<uint16> languages_; std::map<uint8, base::string16> strings_; - typedef std::map<int, scoped_refptr<InterfaceClaimer> > ClaimedInterfaceMap; + typedef std::map<int, scoped_refptr<InterfaceClaimer>> ClaimedInterfaceMap; ClaimedInterfaceMap claimed_interfaces_; - typedef std::map<PlatformUsbTransferHandle, Transfer> TransferMap; - TransferMap transfers_; + // This set holds weak pointers to pending transfers. + std::set<Transfer*> transfers_; // A map from endpoints to interfaces typedef std::map<int, int> EndpointMap; @@ -157,6 +149,7 @@ // before this handle. scoped_refptr<UsbContext> context_; + base::WeakPtrFactory<UsbDeviceHandleImpl> weak_factory_; scoped_refptr<base::SingleThreadTaskRunner> task_runner_; base::ThreadChecker thread_checker_;
diff --git a/device/usb/usb_device_impl.cc b/device/usb/usb_device_impl.cc index 58150aab..407862c 100644 --- a/device/usb/usb_device_impl.cc +++ b/device/usb/usb_device_impl.cc
@@ -157,6 +157,12 @@ continue; } +#if defined(OS_CHROMEOS) + value = udev_device_get_devnode(device.get()); + if (value) { + devnode_ = value; + } +#endif value = udev_device_get_sysattr_value(device.get(), "manufacturer"); if (value) { manufacturer_ = base::UTF8ToUTF16(value); @@ -207,10 +213,9 @@ ui_task_runner_->PostTask( FROM_HERE, - base::Bind(&chromeos::PermissionBrokerClient::RequestUsbAccess, + base::Bind(&chromeos::PermissionBrokerClient::RequestPathAccess, base::Unretained(client), - vendor_id(), - product_id(), + devnode_, interface_id, base::Bind(&OnRequestUsbAccessReplied, base::ThreadTaskRunnerHandle::Get(),
diff --git a/device/usb/usb_device_impl.h b/device/usb/usb_device_impl.h index e962c6da..379d4019 100644 --- a/device/usb/usb_device_impl.h +++ b/device/usb/usb_device_impl.h
@@ -76,6 +76,11 @@ void CacheStrings(); bool strings_cached_; #endif +#if defined(OS_CHROMEOS) + // On Chrome OS save the devnode string for requesting path access from + // permission broker. + std::string devnode_; +#endif // The active configuration descriptor is not read immediately but cached for // later use.
diff --git a/extensions/browser/BUILD.gn b/extensions/browser/BUILD.gn index c270fcc..cb99369 100644 --- a/extensions/browser/BUILD.gn +++ b/extensions/browser/BUILD.gn
@@ -524,7 +524,6 @@ "api/vpn_provider/vpn_provider_api.h", "api/vpn_provider/vpn_service.cc", "api/vpn_provider/vpn_service.h", - "api/vpn_provider/vpn_service_factory.cc", "api/vpn_provider/vpn_service_factory.h", ] }
diff --git a/extensions/browser/api/app_current_window_internal/app_current_window_internal_api.cc b/extensions/browser/api/app_current_window_internal/app_current_window_internal_api.cc index 29cf618a1..3e3de5d 100644 --- a/extensions/browser/api/app_current_window_internal/app_current_window_internal_api.cc +++ b/extensions/browser/api/app_current_window_internal/app_current_window_internal_api.cc
@@ -28,7 +28,8 @@ namespace SetAlwaysOnTop = app_current_window_internal::SetAlwaysOnTop; namespace SetVisibleOnAllWorkspaces = app_current_window_internal::SetVisibleOnAllWorkspaces; - +namespace SetInterceptAllKeys = + app_current_window_internal::SetInterceptAllKeys; using app_current_window_internal::Bounds; using app_current_window_internal::Region; using app_current_window_internal::RegionRect; @@ -51,6 +52,11 @@ const char kAlwaysOnTopPermission[] = "The \"app.window.alwaysOnTop\" permission is required."; +const char kInterceptAllKeysPermission[] = "app.window.interceptAllKeys"; + +const char kInterceptAllKeysPermissionError[] = + "The \"app.window.interceptAllKeys\" permission is required."; + const char kInvalidParameters[] = "Invalid parameters."; const int kUnboundedSize = SizeConstraints::kUnboundedSize; @@ -412,4 +418,19 @@ return true; } +bool AppCurrentWindowInternalSetInterceptAllKeysFunction::RunWithWindow( + AppWindow* window) { + if (!extension()->permissions_data()->HasAPIPermission( + kInterceptAllKeysPermission)) { + error_ = kInterceptAllKeysPermissionError; + return false; + } + + scoped_ptr<SetInterceptAllKeys::Params> params( + SetInterceptAllKeys::Params::Create(*args_)); + CHECK(params.get()); + window->SetInterceptAllKeys(params->want_all_keys); + return true; +} + } // namespace extensions
diff --git a/extensions/browser/api/app_current_window_internal/app_current_window_internal_api.h b/extensions/browser/api/app_current_window_internal/app_current_window_internal_api.h index eb59a41..bdde8e4 100644 --- a/extensions/browser/api/app_current_window_internal/app_current_window_internal_api.h +++ b/extensions/browser/api/app_current_window_internal/app_current_window_internal_api.h
@@ -208,6 +208,17 @@ bool RunWithWindow(AppWindow* window) override; }; +class AppCurrentWindowInternalSetInterceptAllKeysFunction + : public AppCurrentWindowInternalExtensionFunction { + public: + DECLARE_EXTENSION_FUNCTION("app.currentWindowInternal.setInterceptAllKeys", + APP_CURRENTWINDOWINTERNAL_SETINTERCEPTALLKEYS) + + protected: + virtual ~AppCurrentWindowInternalSetInterceptAllKeysFunction() {} + virtual bool RunWithWindow(AppWindow* window) override; +}; + } // namespace extensions #endif // EXTENSIONS_BROWSER_API_APP_CURRENT_WINDOW_INTERNAL_APP_CURRENT_WINDOW_INTERNAL_API_H_
diff --git a/extensions/browser/api/app_runtime/app_runtime_api.cc b/extensions/browser/api/app_runtime/app_runtime_api.cc index 13ac1be..6cb7c71 100644 --- a/extensions/browser/api/app_runtime/app_runtime_api.cc +++ b/extensions/browser/api/app_runtime/app_runtime_api.cc
@@ -83,13 +83,24 @@ return app_runtime::LAUNCH_SOURCE_FILE_HANDLER; case extensions::SOURCE_URL_HANDLER: return app_runtime::LAUNCH_SOURCE_URL_HANDLER; - case extensions::SOURCE_SYSTEM_TRAY: return app_runtime::LAUNCH_SOURCE_SYSTEM_TRAY; case extensions::SOURCE_ABOUT_PAGE: return app_runtime::LAUNCH_SOURCE_ABOUT_PAGE; case extensions::SOURCE_KEYBOARD: return app_runtime::LAUNCH_SOURCE_KEYBOARD; + case extensions::SOURCE_EXTENSIONS_PAGE: + return app_runtime::LAUNCH_SOURCE_EXTENSIONS_PAGE; + case extensions::SOURCE_MANAGEMENT_API: + return app_runtime::LAUNCH_SOURCE_MANAGEMENT_API; + case extensions::SOURCE_EPHEMERAL_APP: + return app_runtime::LAUNCH_SOURCE_EPHEMERAL_APP; + case extensions::SOURCE_BACKGROUND: + return app_runtime::LAUNCH_SOURCE_BACKGROUND; + case extensions::SOURCE_KIOSK: + return app_runtime::LAUNCH_SOURCE_KIOSK; + case extensions::SOURCE_CHROME_INTERNAL: + return app_runtime::LAUNCH_SOURCE_CHROME_INTERNAL; default: return app_runtime::LAUNCH_SOURCE_NONE;
diff --git a/extensions/browser/api/declarative/declarative_api.cc b/extensions/browser/api/declarative/declarative_api.cc index 5cd807e..b786fcb0 100644 --- a/extensions/browser/api/declarative/declarative_api.cc +++ b/extensions/browser/api/declarative/declarative_api.cc
@@ -139,23 +139,26 @@ std::string event_name; EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &event_name)); - int webview_instance_id = 0; - EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(1, &webview_instance_id)); + int web_view_instance_id = 0; + EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(1, &web_view_instance_id)); int embedder_process_id = render_view_host()->GetProcess()->GetID(); - bool has_webview = webview_instance_id != 0; - if (has_webview != IsWebViewEvent(event_name)) + bool has_web_view = web_view_instance_id != 0; + if (has_web_view != IsWebViewEvent(event_name)) EXTENSION_FUNCTION_ERROR(kWebViewExpectedError); event_name = GetWebRequestEventName(event_name); - // If we are not operating on a particular <webview>, then the key is (0, 0). - RulesRegistry::WebViewKey key( - webview_instance_id ? embedder_process_id : 0, webview_instance_id); + // If we are not operating on a particular <webview>, then the key is 0. + int rules_registry_id = RulesRegistryService::kDefaultRulesRegistryID; + if (has_web_view) { + rules_registry_id = WebViewGuest::GetOrGenerateRulesRegistryID( + embedder_process_id, web_view_instance_id, browser_context()); + } // The following call will return a NULL pointer for apps_shell, but should // never be called there anyways. rules_registry_ = RulesRegistryService::Get(browser_context())-> - GetRulesRegistry(key, event_name); + GetRulesRegistry(rules_registry_id, event_name); DCHECK(rules_registry_.get()); // Raw access to this function is not available to extensions, therefore // there should never be a request for a nonexisting rules registry.
diff --git a/extensions/browser/api/declarative/rules_registry.cc b/extensions/browser/api/declarative/rules_registry.cc index 68aa4346..dfd9c35 100644 --- a/extensions/browser/api/declarative/rules_registry.cc +++ b/extensions/browser/api/declarative/rules_registry.cc
@@ -73,11 +73,11 @@ const std::string& event_name, content::BrowserThread::ID owner_thread, RulesCacheDelegate* cache_delegate, - const WebViewKey& webview_key) + int id) : browser_context_(browser_context), owner_thread_(owner_thread), event_name_(event_name), - webview_key_(webview_key), + id_(id), ready_(/*signaled=*/!cache_delegate), // Immediately ready if no cache // delegate to wait for. last_generated_rule_identifier_id_(0), @@ -200,7 +200,6 @@ void RulesRegistry::GetAllRules(const std::string& extension_id, std::vector<linked_ptr<Rule> >* out) { DCHECK_CURRENTLY_ON(owner_thread()); - for (RulesDictionary::const_iterator i = rules_.begin(); i != rules_.end(); ++i) { const RulesDictionaryKey& key = i->first;
diff --git a/extensions/browser/api/declarative/rules_registry.h b/extensions/browser/api/declarative/rules_registry.h index 4772823..4fc3178 100644 --- a/extensions/browser/api/declarative/rules_registry.h +++ b/extensions/browser/api/declarative/rules_registry.h
@@ -40,18 +40,6 @@ class RulesRegistry : public base::RefCountedThreadSafe<RulesRegistry> { public: typedef extensions::core_api::events::Rule Rule; - struct WebViewKey { - int embedder_process_id; - int webview_instance_id; - WebViewKey(int embedder_process_id, int webview_instance_id) - : embedder_process_id(embedder_process_id), - webview_instance_id(webview_instance_id) {} - bool operator<(const WebViewKey& other) const { - return embedder_process_id < other.embedder_process_id || - ((embedder_process_id == other.embedder_process_id) && - (webview_instance_id < other.webview_instance_id)); - } - }; enum Defaults { DEFAULT_PRIORITY = 100 }; // After the RulesCacheDelegate object (the part of the registry which runs on @@ -63,7 +51,7 @@ const std::string& event_name, content::BrowserThread::ID owner_thread, RulesCacheDelegate* cache_delegate, - const WebViewKey& webview_key); + int id); const OneShotEvent& ready() const { return ready_; @@ -145,11 +133,8 @@ // The name of the event with which rules are registered. const std::string& event_name() const { return event_name_; } - // The key that identifies the webview (or tabs) in which these rules apply. - // If the rules apply to the main browser, then this returns the tuple (0, 0). - const WebViewKey& webview_key() const { - return webview_key_; - } + // The unique identifier for this RulesRegistry object. + int id() const { return id_; } protected: virtual ~RulesRegistry(); @@ -233,7 +218,7 @@ const std::string event_name_; // The key that identifies the context in which these rules apply. - WebViewKey webview_key_; + int id_; RulesDictionary rules_;
diff --git a/extensions/browser/api/declarative/rules_registry_service.cc b/extensions/browser/api/declarative/rules_registry_service.cc index 9ddc450..a1e02d8 100644 --- a/extensions/browser/api/declarative/rules_registry_service.cc +++ b/extensions/browser/api/declarative/rules_registry_service.cc
@@ -9,10 +9,6 @@ #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "content/public/browser/browser_thread.h" -#include "content/public/browser/notification_details.h" -#include "content/public/browser/notification_service.h" -#include "content/public/browser/notification_source.h" -#include "content/public/browser/notification_types.h" #include "content/public/browser/render_process_host.h" #include "extensions/browser/api/declarative/rules_cache_delegate.h" #include "extensions/browser/api/declarative_content/content_rules_registry.h" @@ -30,65 +26,66 @@ // Registers |web_request_rules_registry| on the IO thread. void RegisterToExtensionWebRequestEventRouterOnIO( content::BrowserContext* browser_context, - const RulesRegistryService::WebViewKey& webview_key, + int rules_registry_id, scoped_refptr<WebRequestRulesRegistry> web_request_rules_registry) { ExtensionWebRequestEventRouter::GetInstance()->RegisterRulesRegistry( - browser_context, webview_key, web_request_rules_registry); -} - -bool IsWebView(const RulesRegistryService::WebViewKey& webview_key) { - return webview_key.embedder_process_id && webview_key.webview_instance_id; + browser_context, rules_registry_id, web_request_rules_registry); } } // namespace +const int RulesRegistryService::kDefaultRulesRegistryID = 0; +const int RulesRegistryService::kInvalidRulesRegistryID = -1; + RulesRegistryService::RulesRegistryService(content::BrowserContext* context) - : content_rules_registry_(NULL), + : current_rules_registry_id_(kDefaultRulesRegistryID), + content_rules_registry_(NULL), extension_registry_observer_(this), browser_context_(context) { if (browser_context_) { extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_)); - registrar_.Add( - this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, - content::NotificationService::AllBrowserContextsAndSources()); - EnsureDefaultRulesRegistriesRegistered(WebViewKey(0, 0)); + EnsureDefaultRulesRegistriesRegistered(kDefaultRulesRegistryID); } } RulesRegistryService::~RulesRegistryService() {} +int RulesRegistryService::GetNextRulesRegistryID() { + return ++current_rules_registry_id_; +} + void RulesRegistryService::EnsureDefaultRulesRegistriesRegistered( - const WebViewKey& webview_key) { + int rules_registry_id) { if (!browser_context_) return; - RulesRegistryKey key(declarative_webrequest_constants::kOnRequest, - webview_key); + rules_registry_id); // If we can find the key in the |rule_registries_| then we have already // installed the default registries. if (ContainsKey(rule_registries_, key)) return; - + // Only cache rules for regular pages. RulesCacheDelegate* web_request_cache_delegate = NULL; - if (!IsWebView(webview_key)) { + if (rules_registry_id == kDefaultRulesRegistryID) { + // Create a RulesCacheDelegate. web_request_cache_delegate = new RulesCacheDelegate(true /*log_storage_init_delay*/); cache_delegates_.push_back(web_request_cache_delegate); } scoped_refptr<WebRequestRulesRegistry> web_request_rules_registry( - new WebRequestRulesRegistry(browser_context_, - web_request_cache_delegate, - webview_key)); + new WebRequestRulesRegistry(browser_context_, web_request_cache_delegate, + rules_registry_id)); RegisterRulesRegistry(web_request_rules_registry); content::BrowserThread::PostTask( content::BrowserThread::IO, FROM_HERE, base::Bind(&RegisterToExtensionWebRequestEventRouterOnIO, - browser_context_, webview_key, web_request_rules_registry)); + browser_context_, rules_registry_id, + web_request_rules_registry)); - // Only create a ContentRulesRegistry for regular pages and not webviews. - if (!IsWebView(webview_key)) { + // Only create a ContentRulesRegistry for regular pages. + if (rules_registry_id == kDefaultRulesRegistryID) { RulesCacheDelegate* content_rules_cache_delegate = new RulesCacheDelegate(false /*log_storage_init_delay*/); cache_delegates_.push_back(content_rules_cache_delegate); @@ -113,8 +110,9 @@ content::BrowserThread::PostTask( content::BrowserThread::IO, FROM_HERE, base::Bind(&RegisterToExtensionWebRequestEventRouterOnIO, - browser_context_, WebViewKey(0, 0), - scoped_refptr<WebRequestRulesRegistry>(NULL))); + browser_context_, + RulesRegistryService::kDefaultRulesRegistryID, + scoped_refptr<WebRequestRulesRegistry>(NULL))); } static base::LazyInstance<BrowserContextKeyedAPIFactory<RulesRegistryService> > @@ -135,44 +133,35 @@ void RulesRegistryService::RegisterRulesRegistry( scoped_refptr<RulesRegistry> rule_registry) { const std::string event_name(rule_registry->event_name()); - RulesRegistryKey key(event_name, rule_registry->webview_key()); + RulesRegistryKey key(event_name, rule_registry->id()); DCHECK(rule_registries_.find(key) == rule_registries_.end()); rule_registries_[key] = rule_registry; } scoped_refptr<RulesRegistry> RulesRegistryService::GetRulesRegistry( - const WebViewKey& webview_key, + int rules_registry_id, const std::string& event_name) { - EnsureDefaultRulesRegistriesRegistered(webview_key); + EnsureDefaultRulesRegistriesRegistered(rules_registry_id); - RulesRegistryKey key(event_name, webview_key); + RulesRegistryKey key(event_name, rules_registry_id); RulesRegistryMap::const_iterator i = rule_registries_.find(key); if (i == rule_registries_.end()) return scoped_refptr<RulesRegistry>(); return i->second; } -void RulesRegistryService::RemoveWebViewRulesRegistries(int process_id) { - DCHECK_NE(0, process_id); - +void RulesRegistryService::RemoveRulesRegistriesByID(int rules_registry_id) { std::set<RulesRegistryKey> registries_to_delete; for (RulesRegistryMap::iterator it = rule_registries_.begin(); it != rule_registries_.end(); ++it) { const RulesRegistryKey& key = it->first; - const WebViewKey& webview_key = key.webview_key; - int embedder_process_id = webview_key.embedder_process_id; - // |process_id| will always be non-zero. - // |embedder_process_id| will only be non-zero if the key corresponds to a - // webview registry. - // Thus, |embedder_process_id| == |process_id| ==> the process ID is a - // webview embedder. - if (embedder_process_id != process_id) + if (key.rules_registry_id != rules_registry_id) continue; - - // Modifying the container while iterating is bad so we'll save the keys we - // wish to delete in another container, and delete them in another loop. + // Modifying a container while iterating over it can lead to badness. So we + // save the keys in another container and delete them in another loop. registries_to_delete.insert(key); } + for (std::set<RulesRegistryKey>::iterator it = registries_to_delete.begin(); it != registries_to_delete.end(); ++it) { rule_registries_.erase(*it); @@ -222,15 +211,4 @@ extension->id()); } -void RulesRegistryService::Observe( - int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) { - DCHECK_EQ(content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, type); - - content::RenderProcessHost* process = - content::Source<content::RenderProcessHost>(source).ptr(); - RemoveWebViewRulesRegistries(process->GetID()); -} - } // namespace extensions
diff --git a/extensions/browser/api/declarative/rules_registry_service.h b/extensions/browser/api/declarative/rules_registry_service.h index 693d5e73..5cb534b 100644 --- a/extensions/browser/api/declarative/rules_registry_service.h +++ b/extensions/browser/api/declarative/rules_registry_service.h
@@ -13,15 +13,12 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_vector.h" #include "base/scoped_observer.h" -#include "content/public/browser/notification_observer.h" -#include "content/public/browser/notification_registrar.h" #include "extensions/browser/api/declarative/rules_registry.h" #include "extensions/browser/browser_context_keyed_api_factory.h" #include "extensions/browser/extension_registry_observer.h" namespace content { class BrowserContext; -class NotificationSource; } namespace extensions { @@ -35,21 +32,21 @@ // This class owns all RulesRegistries implementations of an ExtensionService. // This class lives on the UI thread. class RulesRegistryService : public BrowserContextKeyedAPI, - public content::NotificationObserver, public ExtensionRegistryObserver { public: - typedef RulesRegistry::WebViewKey WebViewKey; + static const int kDefaultRulesRegistryID; + static const int kInvalidRulesRegistryID; + struct RulesRegistryKey { std::string event_name; - WebViewKey webview_key; - RulesRegistryKey(const std::string event_name, - const WebViewKey& webview_key) + int rules_registry_id; + RulesRegistryKey(const std::string event_name, int rules_registry_id) : event_name(event_name), - webview_key(webview_key) {} + rules_registry_id(rules_registry_id) {} bool operator<(const RulesRegistryKey& other) const { return (event_name < other.event_name) || - ((event_name == other.event_name) && - (webview_key < other.webview_key)); + ((event_name == other.event_name) && + (rules_registry_id < other.rules_registry_id)); } }; @@ -67,43 +64,40 @@ // Convenience method to get the RulesRegistryService for a context. static RulesRegistryService* Get(content::BrowserContext* context); + int GetNextRulesRegistryID(); + // Registers the default RulesRegistries used in Chromium. - void EnsureDefaultRulesRegistriesRegistered(const WebViewKey& webview_key); + void EnsureDefaultRulesRegistriesRegistered(int rules_registry_id); // Registers a RulesRegistry and wraps it in an InitializingRulesRegistry. void RegisterRulesRegistry(scoped_refptr<RulesRegistry> rule_registry); - // Returns the RulesRegistry for |event_name| and |webview_key| or NULL if no - // such registry has been registered. Default rules registries (such as the - // WebRequest rules registry) will be created on first access. - scoped_refptr<RulesRegistry> GetRulesRegistry(const WebViewKey& webview_key, + // Returns the RulesRegistry for |event_name| and |rules_registry_id| or + // NULL if no such registry has been registered. Default rules registries + // (such as the WebRequest rules registry) will be created on first access. + scoped_refptr<RulesRegistry> GetRulesRegistry(int rules_registry_id, const std::string& event_name); + // Remove all rules registries of the given rules_registry_id. + void RemoveRulesRegistriesByID(int rules_registry_id); + // Accessors for each type of rules registry. ContentRulesRegistry* content_rules_registry() const { CHECK(content_rules_registry_); return content_rules_registry_; } - // Removes all rules registries of a given webview embedder process ID. - void RemoveWebViewRulesRegistries(int process_id); - // For testing. void SimulateExtensionUninstalled(const std::string& extension_id); private: friend class BrowserContextKeyedAPIFactory<RulesRegistryService>; - // Maps <event name, webview key> to RuleRegistries that handle these + // Maps <event name, rules registry ID> to RuleRegistries that handle these // events. typedef std::map<RulesRegistryKey, scoped_refptr<RulesRegistry> > RulesRegistryMap; - // Implementation of content::NotificationObserver. - void Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) override; - // ExtensionRegistryObserver implementation. void OnExtensionLoaded(content::BrowserContext* browser_context, const Extension* extension) override; @@ -129,6 +123,8 @@ static const bool kServiceHasOwnInstanceInIncognito = true; static const bool kServiceIsNULLWhileTesting = true; + int current_rules_registry_id_; + RulesRegistryMap rule_registries_; // We own the parts of the registries which need to run on the UI thread. @@ -138,8 +134,6 @@ // conditions. ContentRulesRegistry* content_rules_registry_; - content::NotificationRegistrar registrar_; - // Listen to extension load, unloaded notification. ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver> extension_registry_observer_;
diff --git a/extensions/browser/api/declarative/rules_registry_unittest.cc b/extensions/browser/api/declarative/rules_registry_unittest.cc index 5e4616b..33da872a 100644 --- a/extensions/browser/api/declarative/rules_registry_unittest.cc +++ b/extensions/browser/api/declarative/rules_registry_unittest.cc
@@ -8,12 +8,14 @@ #include "base/message_loop/message_loop.h" #include "content/public/test/test_browser_thread.h" +#include "extensions/browser/api/declarative/rules_registry_service.h" #include "extensions/browser/api/declarative/test_rules_registry.h" #include "testing/gtest/include/gtest/gtest.h" namespace { const char kExtensionId[] = "foobar"; const char kRuleId[] = "foo"; +const int key = extensions::RulesRegistryService::kDefaultRulesRegistryID; } // namespace namespace extensions { @@ -22,7 +24,6 @@ base::MessageLoopForUI message_loop; content::TestBrowserThread thread(content::BrowserThread::UI, &message_loop); - const RulesRegistry::WebViewKey key(0, 0); std::string error; scoped_refptr<RulesRegistry> registry = new TestRulesRegistry(content::BrowserThread::UI, "" /*event_name*/, key); @@ -132,7 +133,6 @@ base::MessageLoopForUI message_loop; content::TestBrowserThread thread(content::BrowserThread::UI, &message_loop); - const RulesRegistry::WebViewKey key(0, 0); std::string error; scoped_refptr<RulesRegistry> registry = new TestRulesRegistry(content::BrowserThread::UI, "" /*event_name*/, key);
diff --git a/extensions/browser/api/declarative/test_rules_registry.cc b/extensions/browser/api/declarative/test_rules_registry.cc index 030a22a8..ad1db304 100644 --- a/extensions/browser/api/declarative/test_rules_registry.cc +++ b/extensions/browser/api/declarative/test_rules_registry.cc
@@ -10,24 +10,25 @@ TestRulesRegistry::TestRulesRegistry(content::BrowserThread::ID owner_thread, const std::string& event_name, - const WebViewKey& webview_key) + int rules_registry_id) : RulesRegistry(NULL /*profile*/, event_name, owner_thread, NULL, - webview_key) {} + rules_registry_id) { +} -TestRulesRegistry::TestRulesRegistry( - content::BrowserContext* browser_context, - const std::string& event_name, - content::BrowserThread::ID owner_thread, - RulesCacheDelegate* cache_delegate, - const WebViewKey& webview_key) +TestRulesRegistry::TestRulesRegistry(content::BrowserContext* browser_context, + const std::string& event_name, + content::BrowserThread::ID owner_thread, + RulesCacheDelegate* cache_delegate, + int rules_registry_id) : RulesRegistry(browser_context, event_name, owner_thread, cache_delegate, - webview_key) {} + rules_registry_id) { +} std::string TestRulesRegistry::AddRulesImpl( const std::string& extension_id,
diff --git a/extensions/browser/api/declarative/test_rules_registry.h b/extensions/browser/api/declarative/test_rules_registry.h index d42877f1..04460d42 100644 --- a/extensions/browser/api/declarative/test_rules_registry.h +++ b/extensions/browser/api/declarative/test_rules_registry.h
@@ -14,13 +14,12 @@ public: TestRulesRegistry(content::BrowserThread::ID owner_thread, const std::string& event_name, - const WebViewKey& webview_key); - TestRulesRegistry( - content::BrowserContext* browser_context, - const std::string& event_name, - content::BrowserThread::ID owner_thread, - RulesCacheDelegate* cache_delegate, - const WebViewKey& webview_key); + int rules_registry_id); + TestRulesRegistry(content::BrowserContext* browser_context, + const std::string& event_name, + content::BrowserThread::ID owner_thread, + RulesCacheDelegate* cache_delegate, + int rules_registry_id); // RulesRegistry implementation: std::string AddRulesImpl(
diff --git a/extensions/browser/api/declarative_content/content_rules_registry.h b/extensions/browser/api/declarative_content/content_rules_registry.h index a5f3c43..161b7ba 100644 --- a/extensions/browser/api/declarative_content/content_rules_registry.h +++ b/extensions/browser/api/declarative_content/content_rules_registry.h
@@ -29,12 +29,12 @@ const std::string& event_name, content::BrowserThread::ID owner_thread, RulesCacheDelegate* cache_delegate, - const WebViewKey& webview_key) + int rules_registry_id) : RulesRegistry(browser_context, event_name, owner_thread, cache_delegate, - webview_key) {} + rules_registry_id) {} // Applies all content rules given an update (CSS match change or // page navigation, for now) from the renderer.
diff --git a/extensions/browser/api/declarative_webrequest/webrequest_rules_registry.cc b/extensions/browser/api/declarative_webrequest/webrequest_rules_registry.cc index 21f7a0a0..ae6f531 100644 --- a/extensions/browser/api/declarative_webrequest/webrequest_rules_registry.cc +++ b/extensions/browser/api/declarative_webrequest/webrequest_rules_registry.cc
@@ -39,12 +39,12 @@ WebRequestRulesRegistry::WebRequestRulesRegistry( content::BrowserContext* browser_context, RulesCacheDelegate* cache_delegate, - const WebViewKey& webview_key) + int rules_registry_id) : RulesRegistry(browser_context, declarative_webrequest_constants::kOnRequest, content::BrowserThread::IO, cache_delegate, - webview_key), + rules_registry_id), browser_context_(browser_context) { if (browser_context_) extension_info_map_ = ExtensionSystem::Get(browser_context_)->info_map(); @@ -180,10 +180,9 @@ DCHECK(registered_rules.find(rule_id) == registered_rules.end()); scoped_ptr<WebRequestRule> webrequest_rule(WebRequestRule::Create( - url_matcher_.condition_factory(), - browser_context(), extension, extension_installation_time, *rule, - base::Bind(&Checker, base::Unretained(extension)), - &error)); + url_matcher_.condition_factory(), browser_context(), extension, + extension_installation_time, *rule, + base::Bind(&Checker, base::Unretained(extension)), &error)); if (!error.empty()) { // We don't return here, because we want to clear temporary // condition sets in the url_matcher_.
diff --git a/extensions/browser/api/declarative_webrequest/webrequest_rules_registry.h b/extensions/browser/api/declarative_webrequest/webrequest_rules_registry.h index 5b14e21..0ac5a2c 100644 --- a/extensions/browser/api/declarative_webrequest/webrequest_rules_registry.h +++ b/extensions/browser/api/declarative_webrequest/webrequest_rules_registry.h
@@ -80,7 +80,7 @@ // storage functionality suspended. WebRequestRulesRegistry(content::BrowserContext* browser_context, RulesCacheDelegate* cache_delegate, - const WebViewKey& webview_key); + int rules_registry_id); // TODO(battre): This will become an implementation detail, because we need // a way to also execute the actions of the rules.
diff --git a/extensions/browser/api/dns/dns_api.cc b/extensions/browser/api/dns/dns_api.cc index ae61123..17bfdd7a 100644 --- a/extensions/browser/api/dns/dns_api.cc +++ b/extensions/browser/api/dns/dns_api.cc
@@ -5,6 +5,7 @@ #include "extensions/browser/api/dns/dns_api.h" #include "base/bind.h" +#include "base/profiler/scoped_tracker.h" #include "base/values.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" @@ -80,6 +81,11 @@ } void DnsResolveFunction::OnLookupFinished(int resolve_result) { + // TODO(vadimt): Remove ScopedTracker below once crbug.com/436634 is fixed. + tracked_objects::ScopedTracker tracking_profile( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "436634 DnsResolveFunction::OnLookupFinished")); + scoped_ptr<ResolveCallbackResolveInfo> resolve_info( new ResolveCallbackResolveInfo()); resolve_info->result_code = resolve_result;
diff --git a/extensions/browser/api/socket/socket_api.cc b/extensions/browser/api/socket/socket_api.cc index c8364fa1..9c63dac8 100644 --- a/extensions/browser/api/socket/socket_api.cc +++ b/extensions/browser/api/socket/socket_api.cc
@@ -8,6 +8,7 @@ #include "base/bind.h" #include "base/containers/hash_tables.h" +#include "base/profiler/scoped_tracker.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/resource_context.h" #include "extensions/browser/api/dns/host_resolver_wrapper.h" @@ -129,6 +130,11 @@ } void SocketExtensionWithDnsLookupFunction::OnDnsLookup(int resolve_result) { + // TODO(vadimt): Remove ScopedTracker below once crbug.com/436634 is fixed. + tracked_objects::ScopedTracker tracking_profile( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "436634 SocketExtensionWithDnsLookupFunction::OnDnsLookup")); + if (resolve_result == net::OK) { DCHECK(!addresses_->empty()); resolved_address_ = addresses_->front().ToStringWithoutPort();
diff --git a/extensions/browser/api/vpn_provider/vpn_service.cc b/extensions/browser/api/vpn_provider/vpn_service.cc index 1a618d6..b1f6199 100644 --- a/extensions/browser/api/vpn_provider/vpn_service.cc +++ b/extensions/browser/api/vpn_provider/vpn_service.cc
@@ -134,6 +134,7 @@ VpnService::VpnService( content::BrowserContext* browser_context, + const std::string& userid_hash, extensions::ExtensionRegistry* extension_registry, extensions::EventRouter* event_router, ShillThirdPartyVpnDriverClient* shill_client, @@ -141,6 +142,7 @@ NetworkProfileHandler* network_profile_handler, NetworkStateHandler* network_state_handler) : browser_context_(browser_context), + userid_hash_(userid_hash), extension_registry_(extension_registry), event_router_(event_router), shill_client_(shill_client), @@ -284,10 +286,8 @@ return; } - // TODO(kaliamoorthi): GetDefaultUserProfile is unsafe. Start using - // GetProfileForUserhash after sorting out the dependency issues. const NetworkProfile* profile = - network_profile_handler_->GetDefaultUserProfile(); + network_profile_handler_->GetProfileForUserhash(userid_hash_); if (!profile) { failure.Run( std::string(),
diff --git a/extensions/browser/api/vpn_provider/vpn_service.h b/extensions/browser/api/vpn_provider/vpn_service.h index 726ccb4..25c4355 100644 --- a/extensions/browser/api/vpn_provider/vpn_service.h +++ b/extensions/browser/api/vpn_provider/vpn_service.h
@@ -57,6 +57,7 @@ const std::string& error_message)>; VpnService(content::BrowserContext* browser_context, + const std::string& userid_hash, extensions::ExtensionRegistry* extension_registry, extensions::EventRouter* event_router, ShillThirdPartyVpnDriverClient* shill_client, @@ -189,6 +190,7 @@ void SetActiveConfiguration(VpnConfiguration* configuration); content::BrowserContext* browser_context_; + std::string userid_hash_; extensions::ExtensionRegistry* extension_registry_; extensions::EventRouter* event_router_;
diff --git a/extensions/browser/api/web_request/web_request_api.cc b/extensions/browser/api/web_request/web_request_api.cc index 509dd98..cddd23c 100644 --- a/extensions/browser/api/web_request/web_request_api.cc +++ b/extensions/browser/api/web_request/web_request_api.cc
@@ -23,6 +23,7 @@ #include "content/public/browser/resource_request_info.h" #include "content/public/browser/user_metrics.h" #include "extensions/browser/api/activity_log/web_request_constants.h" +#include "extensions/browser/api/declarative/rules_registry_service.h" #include "extensions/browser/api/declarative_webrequest/request_stage.h" #include "extensions/browser/api/declarative_webrequest/webrequest_constants.h" #include "extensions/browser/api/declarative_webrequest/webrequest_rules_registry.h" @@ -661,9 +662,9 @@ void ExtensionWebRequestEventRouter::RegisterRulesRegistry( void* browser_context, - const extensions::RulesRegistry::WebViewKey& webview_key, + int rules_registry_id, scoped_refptr<extensions::WebRequestRulesRegistry> rules_registry) { - RulesRegistryKey key(browser_context, webview_key); + RulesRegistryKey key(browser_context, rules_registry_id); if (rules_registry.get()) rules_registries_[key] = rules_registry; else @@ -1966,11 +1967,11 @@ const net::HttpResponseHeaders* original_response_headers) { extensions::WebViewRendererState::WebViewInfo web_view_info; bool is_web_view_guest = GetWebViewInfo(request, &web_view_info); + int rules_registry_id = is_web_view_guest + ? web_view_info.rules_registry_id + : RulesRegistryService::kDefaultRulesRegistryID; - extensions::RulesRegistry::WebViewKey webview_key( - is_web_view_guest ? web_view_info.embedder_process_id : 0, - is_web_view_guest ? web_view_info.instance_id : 0); - RulesRegistryKey rules_key(browser_context, webview_key); + RulesRegistryKey rules_key(browser_context, rules_registry_id); // If this check fails, check that the active stages are up-to-date in // extensions/browser/api/declarative_webrequest/request_stage.h . DCHECK(request_stage & extensions::kActiveStages); @@ -1992,8 +1993,8 @@ } void* cross_browser_context = GetCrossBrowserContext(browser_context); - RulesRegistryKey cross_browser_context_rules_key( - cross_browser_context, webview_key); + RulesRegistryKey cross_browser_context_rules_key(cross_browser_context, + rules_registry_id); if (cross_browser_context && rules_registries_.find(cross_browser_context_rules_key) != rules_registries_.end()) { @@ -2252,11 +2253,11 @@ helpers::ClearCacheOnNavigation(); - BrowserThread::PostTask(BrowserThread::UI, - FROM_HERE, - base::Bind(&helpers::NotifyWebRequestAPIUsed, - profile_id(), - extension->id())); + if (!extension_id_safe().empty()) { + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, + base::Bind(&helpers::NotifyWebRequestAPIUsed, + profile_id(), extension_id_safe())); + } return true; }
diff --git a/extensions/browser/api/web_request/web_request_api.h b/extensions/browser/api/web_request/web_request_api.h index f519409..15706f7 100644 --- a/extensions/browser/api/web_request/web_request_api.h +++ b/extensions/browser/api/web_request/web_request_api.h
@@ -173,7 +173,7 @@ // the rule registry for |browser_context|. void RegisterRulesRegistry( void* browser_context, - const extensions::RulesRegistry::WebViewKey& webview_key, + int rules_registry_id, scoped_refptr<extensions::WebRequestRulesRegistry> rules_registry); // Dispatches the OnBeforeRequest event to any extensions whose filters match @@ -476,8 +476,7 @@ CallbacksForPageLoad callbacks_for_page_load_; - typedef std::pair<void*, extensions::RulesRegistry::WebViewKey> - RulesRegistryKey; + typedef std::pair<void*, int> RulesRegistryKey; // Maps each browser_context (and OTRBrowserContext) and a webview key to its // respective rules registry. std::map<RulesRegistryKey,
diff --git a/extensions/browser/api/web_request/web_request_api_helpers.cc b/extensions/browser/api/web_request/web_request_api_helpers.cc index 7dd2739f..a6d392da 100644 --- a/extensions/browser/api/web_request/web_request_api_helpers.cc +++ b/extensions/browser/api/web_request/web_request_api_helpers.cc
@@ -1196,6 +1196,7 @@ void NotifyWebRequestAPIUsed(void* browser_context_id, const std::string& extension_id) { + DCHECK(!extension_id.empty()); DCHECK_CURRENTLY_ON(content::BrowserThread::UI); content::BrowserContext* browser_context = reinterpret_cast<content::BrowserContext*>(browser_context_id);
diff --git a/extensions/browser/app_window/app_window.cc b/extensions/browser/app_window/app_window.cc index 207e34b..285ca2d 100644 --- a/extensions/browser/app_window/app_window.cc +++ b/extensions/browser/app_window/app_window.cc
@@ -711,6 +711,10 @@ bool AppWindow::IsAlwaysOnTop() const { return cached_always_on_top_; } +void AppWindow::SetInterceptAllKeys(bool want_all_keys) { + native_app_window_->SetInterceptAllKeys(want_all_keys); +} + void AppWindow::WindowEventsReady() { can_send_events_ = true; SendOnWindowShownIfShown();
diff --git a/extensions/browser/app_window/app_window.h b/extensions/browser/app_window/app_window.h index ef5c8ee..668eab1 100644 --- a/extensions/browser/app_window/app_window.h +++ b/extensions/browser/app_window/app_window.h
@@ -336,6 +336,10 @@ // may be false if the bit is silently switched off for security reasons. bool IsAlwaysOnTop() const; + // Set whether the window should get even reserved keys (modulo platform + // restrictions). + void SetInterceptAllKeys(bool want_all_keys); + // Retrieve the current state of the app window as a dictionary, to pass to // the renderer. void GetSerializedState(base::DictionaryValue* properties) const;
diff --git a/extensions/browser/app_window/native_app_window.h b/extensions/browser/app_window/native_app_window.h index 2c37fe0..bb7e467 100644 --- a/extensions/browser/app_window/native_app_window.h +++ b/extensions/browser/app_window/native_app_window.h
@@ -54,6 +54,10 @@ // window is restored to the default shape. virtual void UpdateShape(scoped_ptr<SkRegion> region) = 0; + // Set whether the window should receive all keyboard events including task + // switching keys. + virtual void SetInterceptAllKeys(bool want_all_keys) = 0; + // Allows the window to handle unhandled keyboard messages coming back from // the renderer. virtual void HandleKeyboardEvent(
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h index 26f2966..4dd0f936 100644 --- a/extensions/browser/extension_function_histogram_value.h +++ b/extensions/browser/extension_function_histogram_value.h
@@ -985,6 +985,7 @@ HOTWORDPRIVATE_GETLOCALIZEDSTRINGS, HOTWORDPRIVATE_SETAUDIOHISTORYENABLED, HOTWORDPRIVATE_GETAUDIOHISTORYENABLED, + APP_CURRENTWINDOWINTERNAL_SETINTERCEPTALLKEYS, // Last entry: Add new entries above and ensure to update // tools/metrics/histograms/histograms.xml. ENUM_BOUNDARY
diff --git a/extensions/browser/guest_view/app_view/app_view_guest.cc b/extensions/browser/guest_view/app_view/app_view_guest.cc index f504ddf..2309380e 100644 --- a/extensions/browser/guest_view/app_view/app_view_guest.cc +++ b/extensions/browser/guest_view/app_view/app_view_guest.cc
@@ -88,13 +88,19 @@ // static GuestViewBase* AppViewGuest::Create(content::BrowserContext* browser_context, + content::WebContents* owner_web_contents, int guest_instance_id) { - return new AppViewGuest(browser_context, guest_instance_id); + return new AppViewGuest(browser_context, + owner_web_contents, + guest_instance_id); } AppViewGuest::AppViewGuest(content::BrowserContext* browser_context, + content::WebContents* owner_web_contents, int guest_instance_id) - : GuestView<AppViewGuest>(browser_context, guest_instance_id), + : GuestView<AppViewGuest>(browser_context, + owner_web_contents, + guest_instance_id), app_view_guest_delegate_( ExtensionsAPIClient::Get()->CreateAppViewGuestDelegate()), weak_ptr_factory_(this) { @@ -136,8 +142,6 @@ } void AppViewGuest::CreateWebContents( - int owner_render_process_id, - const GURL& embedder_site_url, const base::DictionaryValue& create_params, const WebContentsCreatedCallback& callback) { std::string app_id; @@ -156,7 +160,7 @@ ExtensionRegistry::Get(browser_context())->enabled_extensions(); const Extension* guest_extension = enabled_extensions.GetByID(app_id); const Extension* embedder_extension = - enabled_extensions.GetByID(embedder_site_url.host()); + enabled_extensions.GetByID(GetOwnerSiteURL().host()); if (!guest_extension || !guest_extension->is_platform_app() || !embedder_extension | !embedder_extension->is_platform_app()) { @@ -248,7 +252,7 @@ scoped_ptr<base::DictionaryValue> embed_request(new base::DictionaryValue()); embed_request->SetInteger(appview::kGuestInstanceID, guest_instance_id()); - embed_request->SetString(appview::kEmbedderID, embedder_extension_id()); + embed_request->SetString(appview::kEmbedderID, owner_extension_id()); embed_request->Set(appview::kData, data.release()); AppRuntimeEventRouter::DispatchOnEmbedRequestedEvent( browser_context(), embed_request.Pass(), extension_host->extension());
diff --git a/extensions/browser/guest_view/app_view/app_view_guest.h b/extensions/browser/guest_view/app_view/app_view_guest.h index 06a45ec..abe4e0eb 100644 --- a/extensions/browser/guest_view/app_view/app_view_guest.h +++ b/extensions/browser/guest_view/app_view/app_view_guest.h
@@ -32,6 +32,7 @@ const std::string& guest_extension_id); static GuestViewBase* Create(content::BrowserContext* browser_context, + content::WebContents* owner_web_contents, int guest_instance_id); // ExtensionFunctionDispatcher::Delegate implementation. @@ -47,15 +48,15 @@ // GuestViewBase implementation. const char* GetAPINamespace() const override; int GetTaskPrefix() const override; - void CreateWebContents(int owner_render_process_id, - const GURL& embedder_site_url, - const base::DictionaryValue& create_params, + void CreateWebContents(const base::DictionaryValue& create_params, const WebContentsCreatedCallback& callback) override; void DidAttachToEmbedder() override; void DidInitialize() override; private: - AppViewGuest(content::BrowserContext* browser_context, int guest_instance_id); + AppViewGuest(content::BrowserContext* browser_context, + content::WebContents* owner_web_contents, + int guest_instance_id); ~AppViewGuest() override;
diff --git a/extensions/browser/guest_view/extension_options/extension_options_guest.cc b/extensions/browser/guest_view/extension_options/extension_options_guest.cc index aa8585f..038d8ed4 100644 --- a/extensions/browser/guest_view/extension_options/extension_options_guest.cc +++ b/extensions/browser/guest_view/extension_options/extension_options_guest.cc
@@ -38,8 +38,11 @@ ExtensionOptionsGuest::ExtensionOptionsGuest( content::BrowserContext* browser_context, + content::WebContents* owner_web_contents, int guest_instance_id) - : GuestView<ExtensionOptionsGuest>(browser_context, guest_instance_id), + : GuestView<ExtensionOptionsGuest>(browser_context, + owner_web_contents, + guest_instance_id), extension_options_guest_delegate_( extensions::ExtensionsAPIClient::Get() ->CreateExtensionOptionsGuestDelegate(this)), @@ -52,13 +55,14 @@ // static extensions::GuestViewBase* ExtensionOptionsGuest::Create( content::BrowserContext* browser_context, + content::WebContents* owner_web_contents, int guest_instance_id) { - return new ExtensionOptionsGuest(browser_context, guest_instance_id); + return new ExtensionOptionsGuest(browser_context, + owner_web_contents, + guest_instance_id); } void ExtensionOptionsGuest::CreateWebContents( - int owner_render_process_id, - const GURL& embedder_site_url, const base::DictionaryValue& create_params, const WebContentsCreatedCallback& callback) { // Get the extension's base URL. @@ -70,7 +74,7 @@ return; } - std::string embedder_extension_id = embedder_site_url.host(); + std::string embedder_extension_id = GetOwnerSiteURL().host(); if (crx_file::id_util::IdIsValid(embedder_extension_id) && extension_id != embedder_extension_id) { // Extensions cannot embed other extensions' options pages.
diff --git a/extensions/browser/guest_view/extension_options/extension_options_guest.h b/extensions/browser/guest_view/extension_options/extension_options_guest.h index 5ca1734c..7b3584a 100644 --- a/extensions/browser/guest_view/extension_options/extension_options_guest.h +++ b/extensions/browser/guest_view/extension_options/extension_options_guest.h
@@ -24,12 +24,11 @@ static const char Type[]; static extensions::GuestViewBase* Create( content::BrowserContext* browser_context, + content::WebContents* owner_web_contents, int guest_instance_id); // GuestViewBase implementation. - void CreateWebContents(int owner_render_process_id, - const GURL& embedder_site_url, - const base::DictionaryValue& create_params, + void CreateWebContents(const base::DictionaryValue& create_params, const WebContentsCreatedCallback& callback) override; void DidAttachToEmbedder() override; void DidInitialize() override; @@ -66,6 +65,7 @@ private: ExtensionOptionsGuest(content::BrowserContext* browser_context, + content::WebContents* owner_web_contents, int guest_instance_id); ~ExtensionOptionsGuest() override; void OnRequest(const ExtensionHostMsg_Request_Params& params);
diff --git a/extensions/browser/guest_view/guest_view.h b/extensions/browser/guest_view/guest_view.h index f60ec9d..c26bfc9 100644 --- a/extensions/browser/guest_view/guest_view.h +++ b/extensions/browser/guest_view/guest_view.h
@@ -63,8 +63,9 @@ protected: GuestView(content::BrowserContext* browser_context, + content::WebContents* owner_web_contents, int guest_instance_id) - : GuestViewBase(browser_context, guest_instance_id) {} + : GuestViewBase(browser_context, owner_web_contents, guest_instance_id) {} virtual ~GuestView() {} private:
diff --git a/extensions/browser/guest_view/guest_view_base.cc b/extensions/browser/guest_view/guest_view_base.cc index 971b391..2c1675c 100644 --- a/extensions/browser/guest_view/guest_view_base.cc +++ b/extensions/browser/guest_view/guest_view_base.cc
@@ -134,9 +134,11 @@ }; GuestViewBase::GuestViewBase(content::BrowserContext* browser_context, + content::WebContents* owner_web_contents, int guest_instance_id) - : owner_web_contents_(NULL), - owner_render_process_id_(0), + : owner_web_contents_(owner_web_contents), + owner_render_process_id_( + owner_web_contents_->GetRenderProcessHost()->GetID()), browser_context_(browser_context), guest_instance_id_(guest_instance_id), view_instance_id_(guestview::kInstanceIDNone), @@ -149,8 +151,7 @@ weak_ptr_factory_(this) { } -void GuestViewBase::Init(const std::string& embedder_extension_id, - content::WebContents* embedder_web_contents, +void GuestViewBase::Init(const std::string& owner_extension_id, const base::DictionaryValue& create_params, const WebContentsCreatedCallback& callback) { if (initialized_) @@ -166,19 +167,14 @@ const Extension* embedder_extension = ExtensionRegistry::Get(browser_context_) ->enabled_extensions() - .GetByID(embedder_extension_id); + .GetByID(owner_extension_id); + // Ok for |embedder_extension| to be NULL, the embedder might be WebUI. - - CHECK(embedder_web_contents); - int embedder_process_id = - embedder_web_contents->GetRenderProcessHost()->GetID(); - - const GURL& embedder_site_url = embedder_web_contents->GetLastCommittedURL(); Feature::Availability availability = feature->IsAvailableToContext( embedder_extension, process_map->GetMostLikelyContextType(embedder_extension, - embedder_process_id), - embedder_site_url); + owner_render_process_id()), + GetOwnerSiteURL()); if (!availability.is_available()) { // The derived class did not create a WebContents so this class serves no // purpose. Let's self-destruct. @@ -187,35 +183,25 @@ return; } - CreateWebContents(embedder_process_id, - embedder_site_url, - create_params, + CreateWebContents(create_params, base::Bind(&GuestViewBase::CompleteInit, weak_ptr_factory_.GetWeakPtr(), - embedder_extension_id, - embedder_web_contents, + owner_extension_id, callback)); } void GuestViewBase::InitWithWebContents( - const std::string& embedder_extension_id, - content::WebContents* owner_web_contents, + const std::string& owner_extension_id, content::WebContents* guest_web_contents) { DCHECK(guest_web_contents); - DCHECK(owner_web_contents); - int owner_render_process_id = - owner_web_contents->GetRenderProcessHost()->GetID(); - content::RenderProcessHost* owner_render_process_host = - content::RenderProcessHost::FromID(owner_render_process_id); - embedder_extension_id_ = embedder_extension_id; - owner_render_process_id_ = owner_render_process_host->GetID(); + owner_extension_id_ = owner_extension_id; // At this point, we have just created the guest WebContents, we need to add // an observer to the embedder WebContents. This observer will be responsible // for destroying the guest WebContents if the embedder goes away. owner_lifetime_observer_.reset( - new OwnerLifetimeObserver(this, owner_web_contents)); + new OwnerLifetimeObserver(this, owner_web_contents_)); WebContentsObserver::Observe(guest_web_contents); guest_web_contents->SetDelegate(this); @@ -269,6 +255,7 @@ // static GuestViewBase* GuestViewBase::Create( content::BrowserContext* browser_context, + content::WebContents* owner_web_contents, int guest_instance_id, const std::string& view_type) { if (guest_view_registry.Get().empty()) @@ -280,7 +267,7 @@ NOTREACHED(); return NULL; } - return it->second.Run(browser_context, guest_instance_id); + return it->second.Run(browser_context, owner_web_contents, guest_instance_id); } // static @@ -348,6 +335,10 @@ GuestSizeChangedDueToAutoSize(old_size, new_size); } +const GURL& GuestViewBase::GetOwnerSiteURL() const { + return owner_web_contents()->GetLastCommittedURL(); +} + void GuestViewBase::Destroy() { if (is_being_destroyed_) return; @@ -499,7 +490,7 @@ EventRouter::DispatchEvent( owner_web_contents_, browser_context_, - embedder_extension_id_, + owner_extension_id_, event->name(), args.Pass(), EventRouter::USER_GESTURE_UNKNOWN, @@ -516,8 +507,7 @@ } } -void GuestViewBase::CompleteInit(const std::string& embedder_extension_id, - content::WebContents* embedder_web_contents, +void GuestViewBase::CompleteInit(const std::string& owner_extension_id, const WebContentsCreatedCallback& callback, content::WebContents* guest_web_contents) { if (!guest_web_contents) { @@ -527,8 +517,7 @@ callback.Run(NULL); return; } - InitWithWebContents( - embedder_extension_id, embedder_web_contents, guest_web_contents); + InitWithWebContents(owner_extension_id, guest_web_contents); callback.Run(guest_web_contents); }
diff --git a/extensions/browser/guest_view/guest_view_base.h b/extensions/browser/guest_view/guest_view_base.h index 1c68c8c..764f6aa9 100644 --- a/extensions/browser/guest_view/guest_view_base.h +++ b/extensions/browser/guest_view/guest_view_base.h
@@ -21,11 +21,10 @@ // A GuestViewBase is the base class browser-side API implementation for a // <*view> tag. GuestViewBase maintains an association between a guest -// WebContents and an embedder WebContents. It receives events issued from -// the guest and relays them to the embedder. GuestViewBase tracks the lifetime -// of its embedder render process until it is attached to a particular embedder -// WebContents. At that point, its lifetime is restricted in scope to the -// lifetime of its embedder WebContents. +// WebContents and an owner WebContents. It receives events issued from +// the guest and relays them to the owner. GuestViewBase tracks the lifetime +// of its owner. A GuestViewBase's owner is referred to as an embedder if +// it is attached to a container within the owner's WebContents. class GuestViewBase : public content::BrowserPluginGuestDelegate, public content::WebContentsDelegate, public content::WebContentsObserver { @@ -54,11 +53,14 @@ } typedef base::Callback<GuestViewBase*( - content::BrowserContext*, int)> GuestCreationCallback; + content::BrowserContext*, + content::WebContents*, + int)> GuestCreationCallback; static void RegisterGuestViewType(const std::string& view_type, const GuestCreationCallback& callback); static GuestViewBase* Create(content::BrowserContext* browser_context, + content::WebContents* owner_web_contents, int guest_instance_id, const std::string& view_type); @@ -156,20 +158,16 @@ typedef base::Callback<void(content::WebContents*)> WebContentsCreatedCallback; virtual void CreateWebContents( - int owner_render_process_id, - const GURL& embedder_site_url, const base::DictionaryValue& create_params, const WebContentsCreatedCallback& callback) = 0; // This creates a WebContents and initializes |this| GuestViewBase to use the // newly created WebContents. - void Init(const std::string& embedder_extension_id, - content::WebContents* embedder_web_contents, + void Init(const std::string& owner_extension_id, const base::DictionaryValue& create_params, const WebContentsCreatedCallback& callback); - void InitWithWebContents(const std::string& embedder_extension_id, - content::WebContents* embedder_web_contents, + void InitWithWebContents(const std::string& owner_extension_id, content::WebContents* guest_web_contents); bool IsViewType(const char* const view_type) const { @@ -205,12 +203,12 @@ int guest_instance_id() const { return guest_instance_id_; } // Returns the extension ID of the embedder. - const std::string& embedder_extension_id() const { - return embedder_extension_id_; + const std::string& owner_extension_id() const { + return owner_extension_id_; } // Returns whether this GuestView is embedded in an extension/app. - bool in_extension() const { return !embedder_extension_id_.empty(); } + bool in_extension() const { return !owner_extension_id_.empty(); } // Returns the user browser context of the embedder. content::BrowserContext* browser_context() const { return browser_context_; } @@ -222,6 +220,9 @@ return opener_.get(); } + // Returns the URL of the owner WebContents. + const GURL& GetOwnerSiteURL() const; + // Whether the guest view is inside a plugin document. bool is_full_page_plugin() { return is_full_page_plugin_; } @@ -248,6 +249,7 @@ protected: GuestViewBase(content::BrowserContext* browser_context, + content::WebContents* owner_web_contents, int guest_instance_id); ~GuestViewBase() override; @@ -259,8 +261,7 @@ void SendQueuedEvents(); - void CompleteInit(const std::string& embedder_extension_id, - content::WebContents* embedder_web_contents, + void CompleteInit(const std::string& owner_extension_id, const WebContentsCreatedCallback& callback, content::WebContents* guest_web_contents); @@ -280,8 +281,12 @@ bool PreHandleGestureEvent(content::WebContents* source, const blink::WebGestureEvent& event) final; + + // This guest tracks the lifetime of the WebContents specified by + // |owner_web_contents_|. If |owner_web_contents_| is destroyed then this + // guest will also self-destruct. content::WebContents* owner_web_contents_; - std::string embedder_extension_id_; + std::string owner_extension_id_; int owner_render_process_id_; content::BrowserContext* browser_context_;
diff --git a/extensions/browser/guest_view/guest_view_manager.cc b/extensions/browser/guest_view/guest_view_manager.cc index 3747e7c..7b42f00fb 100644 --- a/extensions/browser/guest_view/guest_view_manager.cc +++ b/extensions/browser/guest_view/guest_view_manager.cc
@@ -84,11 +84,11 @@ // destroyed immediately after the guest is created). if (!rvh) return; - content::WebContents* embedder_web_contents = + content::WebContents* owner_web_contents = content::WebContents::FromRenderViewHost(rvh); - if (!embedder_web_contents) + if (!owner_web_contents) return; - ElementInstanceKey key(embedder_web_contents, element_instance_id); + ElementInstanceKey key(owner_web_contents, element_instance_id); GuestInstanceIDMap::iterator it = instance_id_map_.find(key); if (it != instance_id_map_.end()) { @@ -118,44 +118,48 @@ } void GuestViewManager::CreateGuest(const std::string& view_type, - const std::string& embedder_extension_id, + const std::string& owner_extension_id, content::WebContents* owner_web_contents, const base::DictionaryValue& create_params, const WebContentsCreatedCallback& callback) { int guest_instance_id = GetNextInstanceID(); GuestViewBase* guest = - GuestViewBase::Create(context_, guest_instance_id, view_type); + GuestViewBase::Create(context_, + owner_web_contents, + guest_instance_id, + view_type); if (!guest) { callback.Run(NULL); return; } - guest->Init( - embedder_extension_id, owner_web_contents, create_params, callback); + guest->Init(owner_extension_id, create_params, callback); } content::WebContents* GuestViewManager::CreateGuestWithWebContentsParams( const std::string& view_type, - const std::string& embedder_extension_id, - content::WebContents* embedder_web_contents, + const std::string& owner_extension_id, + content::WebContents* owner_web_contents, const content::WebContents::CreateParams& create_params) { int guest_instance_id = GetNextInstanceID(); GuestViewBase* guest = - GuestViewBase::Create(context_, guest_instance_id, view_type); + GuestViewBase::Create(context_, + owner_web_contents, + guest_instance_id, + view_type); if (!guest) return NULL; content::WebContents::CreateParams guest_create_params(create_params); guest_create_params.guest_delegate = guest; content::WebContents* guest_web_contents = WebContents::Create(guest_create_params); - guest->InitWithWebContents( - embedder_extension_id, embedder_web_contents, guest_web_contents); + guest->InitWithWebContents(owner_extension_id, guest_web_contents); return guest_web_contents; } content::WebContents* GuestViewManager::GetGuestByInstanceID( - content::WebContents* embedder_web_contents, + content::WebContents* owner_web_contents, int element_instance_id) { - int guest_instance_id = GetGuestInstanceIDForElementID(embedder_web_contents, + int guest_instance_id = GetGuestInstanceIDForElementID(owner_web_contents, element_instance_id); if (guest_instance_id == guestview::kInstanceIDNone) return NULL; @@ -164,10 +168,10 @@ } int GuestViewManager::GetGuestInstanceIDForElementID( - content::WebContents* embedder_web_contents, + content::WebContents* owner_web_contents, int element_instance_id) { GuestInstanceIDMap::iterator iter = instance_id_map_.find( - ElementInstanceKey(embedder_web_contents, element_instance_id)); + ElementInstanceKey(owner_web_contents, element_instance_id)); if (iter == instance_id_map_.end()) return guestview::kInstanceIDNone; return iter->second; @@ -184,14 +188,14 @@ return NULL; } -bool GuestViewManager::ForEachGuest(WebContents* embedder_web_contents, +bool GuestViewManager::ForEachGuest(WebContents* owner_web_contents, const GuestCallback& callback) { for (GuestInstanceMap::iterator it = guest_web_contents_by_instance_id_.begin(); it != guest_web_contents_by_instance_id_.end(); ++it) { WebContents* guest = it->second; GuestViewBase* guest_view = GuestViewBase::FromWebContents(guest); - if (embedder_web_contents != guest_view->embedder_web_contents()) + if (owner_web_contents != guest_view->owner_web_contents()) continue; if (callback.Run(guest))
diff --git a/extensions/browser/guest_view/guest_view_manager.h b/extensions/browser/guest_view/guest_view_manager.h index 722b9841..84a3815 100644 --- a/extensions/browser/guest_view/guest_view_manager.h +++ b/extensions/browser/guest_view/guest_view_manager.h
@@ -58,21 +58,21 @@ int GetNextInstanceID(); int GetGuestInstanceIDForElementID( - content::WebContents* embedder_web_contents, + content::WebContents* owner_web_contents, int element_instance_id); typedef base::Callback<void(content::WebContents*)> WebContentsCreatedCallback; void CreateGuest(const std::string& view_type, - const std::string& embedder_extension_id, - content::WebContents* embedder_web_contents, + const std::string& owner_extension_id, + content::WebContents* owner_web_contents, const base::DictionaryValue& create_params, const WebContentsCreatedCallback& callback); content::WebContents* CreateGuestWithWebContentsParams( const std::string& view_type, - const std::string& embedder_extension_id, - content::WebContents* embedder_web_contents, + const std::string& owner_extension_id, + content::WebContents* owner_web_contents, const content::WebContents::CreateParams& create_params); content::SiteInstance* GetGuestSiteInstance( @@ -80,9 +80,9 @@ // BrowserPluginGuestManager implementation. content::WebContents* GetGuestByInstanceID( - content::WebContents* embedder_web_contents, + content::WebContents* owner_web_contents, int element_instance_id) override; - bool ForEachGuest(content::WebContents* embedder_web_contents, + bool ForEachGuest(content::WebContents* owner_web_contents, const GuestCallback& callback) override; protected: @@ -119,15 +119,15 @@ GuestInstanceMap guest_web_contents_by_instance_id_; struct ElementInstanceKey { - content::WebContents* embedder_web_contents; + content::WebContents* owner_web_contents; int element_instance_id; - ElementInstanceKey(content::WebContents* embedder_web_contents, + ElementInstanceKey(content::WebContents* owner_web_contents, int element_instance_id) - : embedder_web_contents(embedder_web_contents), + : owner_web_contents(owner_web_contents), element_instance_id(element_instance_id) {} bool operator<(const ElementInstanceKey& other) const { - if (embedder_web_contents != other.embedder_web_contents) - return embedder_web_contents < other.embedder_web_contents; + if (owner_web_contents != other.owner_web_contents) + return owner_web_contents < other.owner_web_contents; return element_instance_id < other.element_instance_id; } };
diff --git a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc index b6aca54..2aecb64 100644 --- a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc +++ b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc
@@ -29,14 +29,20 @@ // static GuestViewBase* MimeHandlerViewGuest::Create( content::BrowserContext* browser_context, + content::WebContents* owner_web_contents, int guest_instance_id) { - return new MimeHandlerViewGuest(browser_context, guest_instance_id); + return new MimeHandlerViewGuest(browser_context, + owner_web_contents, + guest_instance_id); } MimeHandlerViewGuest::MimeHandlerViewGuest( content::BrowserContext* browser_context, + content::WebContents* owner_web_contents, int guest_instance_id) - : GuestView<MimeHandlerViewGuest>(browser_context, guest_instance_id), + : GuestView<MimeHandlerViewGuest>(browser_context, + owner_web_contents, + guest_instance_id), delegate_(ExtensionsAPIClient::Get()->CreateMimeHandlerViewGuestDelegate( this)) { } @@ -60,10 +66,7 @@ return IDS_EXTENSION_TASK_MANAGER_MIMEHANDLERVIEW_TAG_PREFIX; } -// |embedder_extension_id| is empty for mime handler view. void MimeHandlerViewGuest::CreateWebContents( - int owner_render_process_id, - const GURL& embedder_site_url, const base::DictionaryValue& create_params, const WebContentsCreatedCallback& callback) { std::string orig_mime_type; @@ -105,7 +108,7 @@ ProcessManager* process_manager = ProcessManager::Get(browser_context()); content::SiteInstance* guest_site_instance = process_manager->GetSiteInstanceForURL( - Extension::GetBaseURLFromExtensionId(embedder_site_url.host())); + Extension::GetBaseURLFromExtensionId(GetOwnerSiteURL().host())); WebContents::CreateParams params(browser_context(), guest_site_instance); params.guest_delegate = this;
diff --git a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h index c4419f0..c14ace52 100644 --- a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h +++ b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h
@@ -21,6 +21,7 @@ public ExtensionFunctionDispatcher::Delegate { public: static GuestViewBase* Create(content::BrowserContext* browser_context, + content::WebContents* owner_web_contents, int guest_instance_id); static const char Type[]; @@ -32,9 +33,7 @@ // GuestViewBase implementation. const char* GetAPINamespace() const override; int GetTaskPrefix() const override; - void CreateWebContents(int owner_render_process_id, - const GURL& embedder_site_url, - const base::DictionaryValue& create_params, + void CreateWebContents(const base::DictionaryValue& create_params, const WebContentsCreatedCallback& callback) override; void DidAttachToEmbedder() override; void DidInitialize() override; @@ -63,6 +62,7 @@ private: MimeHandlerViewGuest(content::BrowserContext* browser_context, + content::WebContents* owner_web_contents, int guest_instance_id); ~MimeHandlerViewGuest() override;
diff --git a/extensions/browser/guest_view/web_view/web_view_guest.cc b/extensions/browser/guest_view/web_view/web_view_guest.cc index 2e13ab63..12967605 100644 --- a/extensions/browser/guest_view/web_view/web_view_guest.cc +++ b/extensions/browser/guest_view/web_view/web_view_guest.cc
@@ -30,6 +30,7 @@ #include "content/public/common/result_codes.h" #include "content/public/common/stop_find_action.h" #include "content/public/common/url_constants.h" +#include "extensions/browser/api/declarative/rules_registry_service.h" #include "extensions/browser/api/extensions_api_client.h" #include "extensions/browser/api/web_request/web_request_api.h" #include "extensions/browser/api/web_view/web_view_internal_api.h" @@ -150,8 +151,11 @@ // static GuestViewBase* WebViewGuest::Create(content::BrowserContext* browser_context, + content::WebContents* owner_web_contents, int guest_instance_id) { - return new WebViewGuest(browser_context, guest_instance_id); + return new WebViewGuest(browser_context, + owner_web_contents, + guest_instance_id); } // static @@ -180,6 +184,31 @@ // static const char WebViewGuest::Type[] = "webview"; +typedef std::pair<int, int> WebViewKey; +typedef std::map<WebViewKey, int> WebViewKeyToIDMap; +static base::LazyInstance<WebViewKeyToIDMap> web_view_key_to_id_map = + LAZY_INSTANCE_INITIALIZER; + +// static +int WebViewGuest::GetOrGenerateRulesRegistryID( + int embedder_process_id, + int webview_instance_id, + content::BrowserContext* browser_context) { + bool is_web_view = embedder_process_id && webview_instance_id; + if (!is_web_view) + return RulesRegistryService::kDefaultRulesRegistryID; + + WebViewKey key = std::make_pair(embedder_process_id, webview_instance_id); + auto it = web_view_key_to_id_map.Get().find(key); + if (it != web_view_key_to_id_map.Get().end()) + return it->second; + + int rules_registry_id = + RulesRegistryService::Get(browser_context)->GetNextRulesRegistryID(); + web_view_key_to_id_map.Get()[key] = rules_registry_id; + return rules_registry_id; +} + // static int WebViewGuest::GetViewInstanceId(WebContents* contents) { WebViewGuest* guest = FromWebContents(contents); @@ -198,12 +227,10 @@ } void WebViewGuest::CreateWebContents( - int owner_render_process_id, - const GURL& embedder_site_url, const base::DictionaryValue& create_params, const WebContentsCreatedCallback& callback) { content::RenderProcessHost* owner_render_process_host = - content::RenderProcessHost::FromID(owner_render_process_id); + content::RenderProcessHost::FromID(owner_render_process_id()); std::string storage_partition_id; bool persist_storage = false; std::string storage_partition_string; @@ -223,7 +250,7 @@ } std::string url_encoded_partition = net::EscapeQueryParamValue( storage_partition_id, false); - std::string partition_domain = embedder_site_url.host(); + std::string partition_domain = GetOwnerSiteURL().host(); GURL guest_site(base::StringPrintf("%s://%s/%s?%s", content::kGuestScheme, partition_domain.c_str(), @@ -347,13 +374,19 @@ if (web_view_guest_delegate_) web_view_guest_delegate_->OnEmbedderWillBeDestroyed(); + // Clean up rules registries for the webview. + RulesRegistryService::Get(browser_context()) + ->RemoveRulesRegistriesByID(rules_registry_id_); + WebViewKey key(owner_render_process_id(), view_instance_id()); + web_view_key_to_id_map.Get().erase(key); + content::BrowserThread::PostTask( content::BrowserThread::IO, FROM_HERE, base::Bind( &RemoveWebViewEventListenersOnIOThread, browser_context(), - embedder_extension_id(), + owner_extension_id(), owner_render_process_id(), view_instance_id())); } @@ -515,7 +548,7 @@ create_params.SetString(webview::kStoragePartitionId, storage_partition_id); guest_manager->CreateGuest(WebViewGuest::Type, - embedder_extension_id(), + owner_extension_id(), embedder_web_contents(), create_params, base::Bind(&WebViewGuest::NewGuestWebViewCallback, @@ -666,8 +699,12 @@ } WebViewGuest::WebViewGuest(content::BrowserContext* browser_context, + content::WebContents* owner_web_contents, int guest_instance_id) - : GuestView<WebViewGuest>(browser_context, guest_instance_id), + : GuestView<WebViewGuest>(browser_context, + owner_web_contents, + guest_instance_id), + rules_registry_id_(RulesRegistryService::kInvalidRulesRegistryID), find_helper_(this), is_overriding_user_agent_(false), guest_opaque_(true), @@ -811,7 +848,8 @@ web_view_info.embedder_process_id = owner_render_process_id(); web_view_info.instance_id = view_instance_id(); web_view_info.partition_id = partition_id; - web_view_info.embedder_extension_id = embedder_extension_id(); + web_view_info.owner_extension_id = owner_extension_id(); + web_view_info.rules_registry_id = rules_registry_id_; content::BrowserThread::PostTask( content::BrowserThread::IO, @@ -841,7 +879,7 @@ GuestViewManager::FromBrowserContext(browser_context()); return guest_manager->CreateGuestWithWebContentsParams( WebViewGuest::Type, - embedder_extension_id(), + owner_extension_id(), embedder_web_contents(), create_params); } @@ -884,6 +922,9 @@ } void WebViewGuest::WillAttachToEmbedder() { + rules_registry_id_ = GetOrGenerateRulesRegistryID( + owner_render_process_id(), view_instance_id(), browser_context()); + // We must install the mapping from guests to WebViews prior to resuming // suspended resource loads so that the WebRequest API will catch resource // requests. @@ -1208,7 +1249,7 @@ GURL default_url(base::StringPrintf("%s://%s/", kExtensionScheme, - embedder_extension_id().c_str())); + owner_extension_id().c_str())); return default_url.Resolve(src); }
diff --git a/extensions/browser/guest_view/web_view/web_view_guest.h b/extensions/browser/guest_view/web_view/web_view_guest.h index 31ca93e..be665ab 100644 --- a/extensions/browser/guest_view/web_view/web_view_guest.h +++ b/extensions/browser/guest_view/web_view/web_view_guest.h
@@ -37,6 +37,7 @@ public content::NotificationObserver { public: static GuestViewBase* Create(content::BrowserContext* browser_context, + content::WebContents* owner_web_contents, int guest_instance_id); // For WebViewGuest, we create special guest processes, which host the @@ -57,6 +58,13 @@ static const char Type[]; + // Return the stored rules registry ID of the given webview. Will generate + // an ID for the first query. + static int GetOrGenerateRulesRegistryID( + int embedder_process_id, + int web_view_instance_id, + content::BrowserContext* browser_context); + // Request navigating the guest to the provided |src| URL. void NavigateGuest(const std::string& src, bool force_navigation); @@ -86,9 +94,7 @@ // GuestViewBase implementation. const char* GetAPINamespace() const override; int GetTaskPrefix() const override; - void CreateWebContents(int embedder_render_process_id, - const GURL& embedder_site_url, - const base::DictionaryValue& create_params, + void CreateWebContents(const base::DictionaryValue& create_params, const WebContentsCreatedCallback& callback) override; void DidAttachToEmbedder() override; void DidInitialize() override; @@ -236,7 +242,9 @@ private: friend class WebViewPermissionHelper; + WebViewGuest(content::BrowserContext* browser_context, + content::WebContents* owner_web_contents, int guest_instance_id); ~WebViewGuest() override; @@ -315,6 +323,9 @@ void SetUpAutoSize(); + // Identifies the set of rules registries belonging to this guest. + int rules_registry_id_; + // Handles find requests and replies for the webview find API. WebViewFindHelper find_helper_;
diff --git a/extensions/browser/guest_view/web_view/web_view_renderer_state.h b/extensions/browser/guest_view/web_view/web_view_renderer_state.h index a6e5f438..273356f2 100644 --- a/extensions/browser/guest_view/web_view/web_view_renderer_state.h +++ b/extensions/browser/guest_view/web_view/web_view_renderer_state.h
@@ -22,8 +22,9 @@ struct WebViewInfo { int embedder_process_id; int instance_id; + int rules_registry_id; std::string partition_id; - std::string embedder_extension_id; + std::string owner_extension_id; }; static WebViewRendererState* GetInstance();
diff --git a/extensions/common/api/_api_features.json b/extensions/common/api/_api_features.json index 7500dfca..85b2f045 100644 --- a/extensions/common/api/_api_features.json +++ b/extensions/common/api/_api_features.json
@@ -77,9 +77,12 @@ "contexts": ["blessed_extension"], "dependencies": ["permission:appview"] }, + // Note that exposing this doesn't necessarily expose AppView, + // appViewEmbedderInternal is required for that. + // See http://crbug.com/437891. "appViewGuestInternal": { "internal": true, - "channel": "dev", + "channel": "stable", "contexts": ["blessed_extension"] }, "bluetooth": {
diff --git a/extensions/common/api/_permission_features.json b/extensions/common/api/_permission_features.json index 90af503..7ded226 100644 --- a/extensions/common/api/_permission_features.json +++ b/extensions/common/api/_permission_features.json
@@ -63,6 +63,10 @@ ] } ], + "app.window.interceptAllKeys": { + "channel": "dev", + "extension_types": ["platform_app"] + }, "app.window.shape": { "channel": "stable", "extension_types": ["platform_app"]
diff --git a/extensions/common/api/app_current_window_internal.idl b/extensions/common/api/app_current_window_internal.idl index f6bd26f..4a58d15 100644 --- a/extensions/common/api/app_current_window_internal.idl +++ b/extensions/common/api/app_current_window_internal.idl
@@ -53,6 +53,7 @@ static void setShape(Region region); static void setAlwaysOnTop(boolean always_on_top); static void setVisibleOnAllWorkspaces(boolean always_visible); + static void setInterceptAllKeys(boolean want_all_keys); }; interface Events {
diff --git a/extensions/common/api/app_runtime.idl b/extensions/common/api/app_runtime.idl index 163db41..f7293479 100644 --- a/extensions/common/api/app_runtime.idl +++ b/extensions/common/api/app_runtime.idl
@@ -25,10 +25,15 @@ command_line, file_handler, url_handler, - system_tray, about_page, - keyboard + keyboard, + extensions_page, + management_api, + ephemeral_app, + background, + kiosk, + chrome_internal }; // Optional data for the launch. Either <code>items</code>, or
diff --git a/extensions/common/api/app_window.idl b/extensions/common/api/app_window.idl index 06cf464b..b8f94fc 100644 --- a/extensions/common/api/app_window.idl +++ b/extensions/common/api/app_window.idl
@@ -394,6 +394,12 @@ // This is only available on dev channel. static void setVisibleOnAllWorkspaces(boolean alwaysVisible); + // Set whether the window should get all keyboard events including system + // keys that are usually not sent. This is best-effort subject to platform + // specific constraints. Requires the <code>"app.window.allKeys"</code> + // permission. This is currently available only in dev channel on Windows. + static void setInterceptAllKeys(boolean wantAllKeys); + // The JavaScript 'window' object for the created child. [instanceOf=Window] object contentWindow;
diff --git a/extensions/common/constants.h b/extensions/common/constants.h index 25d0be2..34f52c1 100644 --- a/extensions/common/constants.h +++ b/extensions/common/constants.h
@@ -112,7 +112,7 @@ // Note the enumeration is used in UMA histogram so entries // should not be re-ordered or removed. enum AppLaunchSource { - SOURCE_UNTRACKED = 0, + SOURCE_UNTRACKED = 0, // Should be used in test. SOURCE_APP_LAUNCHER, SOURCE_NEW_TAB_PAGE, SOURCE_RELOAD, @@ -121,10 +121,15 @@ SOURCE_COMMAND_LINE, SOURCE_FILE_HANDLER, SOURCE_URL_HANDLER, - SOURCE_SYSTEM_TRAY, SOURCE_ABOUT_PAGE, SOURCE_KEYBOARD, + SOURCE_EXTENSIONS_PAGE, + SOURCE_MANAGEMENT_API, + SOURCE_EPHEMERAL_APP, + SOURCE_BACKGROUND, + SOURCE_KIOSK, + SOURCE_CHROME_INTERNAL, NUM_APP_LAUNCH_SOURCES };
diff --git a/extensions/common/permissions/api_permission.h b/extensions/common/permissions/api_permission.h index 70f67eb..207a265c1 100644 --- a/extensions/common/permissions/api_permission.h +++ b/extensions/common/permissions/api_permission.h
@@ -120,6 +120,7 @@ kInfobars, kInput, kInputMethodPrivate, + kInterceptAllKeys, kLocation, kLogPrivate, kManagement,
diff --git a/extensions/common/permissions/permission_message.h b/extensions/common/permissions/permission_message.h index e1212db2..2515de0 100644 --- a/extensions/common/permissions/permission_message.h +++ b/extensions/common/permissions/permission_message.h
@@ -97,6 +97,7 @@ kHosts3ReadOnly, kHosts4OrMoreReadOnly, kHostsAllReadOnly, + kInterceptAllKeys, // Last entry: Add new entries above and ensure to update the // "ExtensionPermission2" enum in tools/metrics/histograms/histograms.xml. kEnumBoundary,
diff --git a/extensions/components/native_app_window/native_app_window_views.cc b/extensions/components/native_app_window/native_app_window_views.cc index 7c1109a..ed415f1c 100644 --- a/extensions/components/native_app_window/native_app_window_views.cc +++ b/extensions/components/native_app_window/native_app_window_views.cc
@@ -374,6 +374,10 @@ // Stub implementation. See also ChromeNativeAppWindowViews. } +void NativeAppWindowViews::SetInterceptAllKeys(bool want_all_keys) { + // Stub implementation. See also ChromeNativeAppWindowViews. +} + void NativeAppWindowViews::HandleKeyboardEvent( const content::NativeWebKeyboardEvent& event) { unhandled_keyboard_event_handler_.HandleKeyboardEvent(event,
diff --git a/extensions/components/native_app_window/native_app_window_views.h b/extensions/components/native_app_window/native_app_window_views.h index c8e84b47ab..ac2a6723 100644 --- a/extensions/components/native_app_window/native_app_window_views.h +++ b/extensions/components/native_app_window/native_app_window_views.h
@@ -141,6 +141,7 @@ const std::vector<extensions::DraggableRegion>& regions) override; SkRegion* GetDraggableRegion() override; void UpdateShape(scoped_ptr<SkRegion> region) override; + void SetInterceptAllKeys(bool want_all_keys) override; void HandleKeyboardEvent( const content::NativeWebKeyboardEvent& event) override; bool IsFrameless() const override;
diff --git a/extensions/extensions.gyp b/extensions/extensions.gyp index bccc46c..2281bd0 100644 --- a/extensions/extensions.gyp +++ b/extensions/extensions.gyp
@@ -791,7 +791,6 @@ 'browser/api/vpn_provider/vpn_provider_api.h', 'browser/api/vpn_provider/vpn_service.cc', 'browser/api/vpn_provider/vpn_service.h', - 'browser/api/vpn_provider/vpn_service_factory.cc', 'browser/api/vpn_provider/vpn_service_factory.h' ] }],
diff --git a/extensions/renderer/guest_view/extensions_guest_view_container.cc b/extensions/renderer/guest_view/extensions_guest_view_container.cc index 82204ec..bc400d9 100644 --- a/extensions/renderer/guest_view/extensions_guest_view_container.cc +++ b/extensions/renderer/guest_view/extensions_guest_view_container.cc
@@ -105,15 +105,31 @@ } ExtensionsGuestViewContainer::ExtensionsGuestViewContainer( - content::RenderFrame* render_frame) + content::RenderFrame* render_frame) : GuestViewContainer(render_frame), - ready_(false) { + ready_(false), + destruction_isolate_(nullptr) { } ExtensionsGuestViewContainer::~ExtensionsGuestViewContainer() { if (element_instance_id() != guestview::kInstanceIDNone) { g_guest_view_container_map.Get().erase(element_instance_id()); } + + // Call the destruction callback, if one is registered. + if (destruction_callback_.IsEmpty()) + return; + v8::HandleScope handle_scope(destruction_isolate_); + v8::Handle<v8::Function> callback = + destruction_callback_.NewHandle(destruction_isolate_); + v8::Handle<v8::Context> context = callback->CreationContext(); + if (context.IsEmpty()) + return; + + v8::Context::Scope context_scope(context); + blink::WebScopedMicrotaskSuppression suppression; + + callback->Call(context->Global(), 0, nullptr); } ExtensionsGuestViewContainer* ExtensionsGuestViewContainer::FromID( @@ -130,6 +146,13 @@ PerformPendingRequest(); } +void ExtensionsGuestViewContainer::RegisterDestructionCallback( + v8::Handle<v8::Function> callback, + v8::Isolate* isolate) { + destruction_callback_.reset(callback); + destruction_isolate_ = isolate; +} + void ExtensionsGuestViewContainer::SetElementInstanceID( int element_instance_id) { GuestViewContainer::SetElementInstanceID(element_instance_id);
diff --git a/extensions/renderer/guest_view/extensions_guest_view_container.h b/extensions/renderer/guest_view/extensions_guest_view_container.h index 0efec26..dee152e 100644 --- a/extensions/renderer/guest_view/extensions_guest_view_container.h +++ b/extensions/renderer/guest_view/extensions_guest_view_container.h
@@ -69,6 +69,8 @@ static ExtensionsGuestViewContainer* FromID(int element_instance_id); void IssueRequest(linked_ptr<Request> request); + void RegisterDestructionCallback(v8::Handle<v8::Function> callback, + v8::Isolate* isolate); // BrowserPluginDelegate implementation. void SetElementInstanceID(int element_instance_id) override; @@ -90,6 +92,9 @@ std::deque<linked_ptr<Request> > pending_requests_; linked_ptr<Request> pending_response_; + ScopedPersistent<v8::Function> destruction_callback_; + v8::Isolate* destruction_isolate_; + DISALLOW_COPY_AND_ASSIGN(ExtensionsGuestViewContainer); };
diff --git a/extensions/renderer/guest_view/guest_view_internal_custom_bindings.cc b/extensions/renderer/guest_view/guest_view_internal_custom_bindings.cc index 86ba4ed9..c96c284 100644 --- a/extensions/renderer/guest_view/guest_view_internal_custom_bindings.cc +++ b/extensions/renderer/guest_view/guest_view_internal_custom_bindings.cc
@@ -25,6 +25,10 @@ RouteFunction("AttachGuest", base::Bind(&GuestViewInternalCustomBindings::AttachGuest, base::Unretained(this))); + RouteFunction( + "RegisterDestructionCallback", + base::Bind(&GuestViewInternalCustomBindings::RegisterDestructionCallback, + base::Unretained(this))); } void GuestViewInternalCustomBindings::AttachGuest( @@ -76,4 +80,27 @@ args.GetReturnValue().Set(v8::Boolean::New(context()->isolate(), true)); } +void GuestViewInternalCustomBindings::RegisterDestructionCallback( + const v8::FunctionCallbackInfo<v8::Value>& args) { + // There are two parameters. + CHECK(args.Length() == 2); + // Element Instance ID. + CHECK(args[0]->IsInt32()); + // Callback function. + CHECK(args[1]->IsFunction()); + + int element_instance_id = args[0]->Int32Value(); + // An element instance ID uniquely identifies a ExtensionsGuestViewContainer + // within a RenderView. + ExtensionsGuestViewContainer* guest_view_container = + ExtensionsGuestViewContainer::FromID(element_instance_id); + if (!guest_view_container) + return; + + guest_view_container->RegisterDestructionCallback(args[1].As<v8::Function>(), + args.GetIsolate()); + + args.GetReturnValue().Set(v8::Boolean::New(context()->isolate(), true)); +} + } // namespace extensions
diff --git a/extensions/renderer/guest_view/guest_view_internal_custom_bindings.h b/extensions/renderer/guest_view/guest_view_internal_custom_bindings.h index 0d7cb75..bc1e2e5 100644 --- a/extensions/renderer/guest_view/guest_view_internal_custom_bindings.h +++ b/extensions/renderer/guest_view/guest_view_internal_custom_bindings.h
@@ -28,6 +28,12 @@ // down to the GuestView. The GuestView may use these parameters to update the // state of the guest hosted in another process. void AttachGuest(const v8::FunctionCallbackInfo<v8::Value>& args); + + // RegisterDestructionCallback registers a JavaScript callback function to be + // called when the guestview's container is destroyed. + // RegisterDestructionCallback takes in a single paramater, |callback|. + void RegisterDestructionCallback( + const v8::FunctionCallbackInfo<v8::Value>& args); }; } // namespace extensions
diff --git a/extensions/renderer/json_schema_unittest.cc b/extensions/renderer/json_schema_unittest.cc index 920616b..41a4b711 100644 --- a/extensions/renderer/json_schema_unittest.cc +++ b/extensions/renderer/json_schema_unittest.cc
@@ -4,6 +4,7 @@ #include "extensions/renderer/module_system_test.h" #include "extensions/renderer/v8_schema_registry.h" +#include "gin/dictionary.h" #include "grit/extensions_renderer_resources.h" namespace extensions { @@ -72,6 +73,18 @@ } TEST_F(JsonSchemaTest, TestType) { + gin::Dictionary array_buffer_container( + env()->isolate(), + env()->CreateGlobal("otherContextArrayBufferContainer")); + { + // Create an ArrayBuffer in another v8 context and pass it to the test + // through a global. + scoped_ptr<ModuleSystemTestEnvironment> other_env(CreateEnvironment()); + v8::Context::Scope scope(other_env->context()->v8_context()); + v8::Handle<v8::ArrayBuffer> array_buffer( + v8::ArrayBuffer::New(env()->isolate(), 1)); + array_buffer_container.Set("value", array_buffer); + } TestFunction("testType"); }
diff --git a/extensions/renderer/resources/extension.css b/extensions/renderer/resources/extension.css index 0d3cb1b4..2010ec9 100644 --- a/extensions/renderer/resources/extension.css +++ b/extensions/renderer/resources/extension.css
@@ -329,11 +329,15 @@ :-webkit-any(.checkbox, .radio) label { /* Don't expand horizontally: <http://crbug.com/112091>. */ - display: -webkit-inline-box; + display: inline-flex; padding-bottom: 7px; padding-top: 7px; } +:-webkit-any(.checkbox, .radio) label input { + flex-shrink: 0; +} + :-webkit-any(.checkbox, .radio) label input ~ span { -webkit-margin-start: 0.6em; /* Make sure long spans wrap at the same horizontal position they start. */
diff --git a/extensions/renderer/resources/guest_view/app_view.js b/extensions/renderer/resources/guest_view/app_view.js index 025b55c0..627887d 100644 --- a/extensions/renderer/resources/guest_view/app_view.js +++ b/extensions/renderer/resources/guest_view/app_view.js
@@ -3,16 +3,14 @@ // found in the LICENSE file. var DocumentNatives = requireNative('document_natives'); +var GuestView = require('guestView').GuestView; var GuestViewContainer = require('guestViewContainer').GuestViewContainer; -var GuestViewInternal = - require('binding').Binding.create('guestViewInternal').generate(); var IdGenerator = requireNative('id_generator'); -var guestViewInternalNatives = requireNative('guest_view_internal'); function AppViewImpl(appviewElement) { GuestViewContainer.call(this, appviewElement) - this.pendingGuestCreation = false; + this.guest = new GuestView('appview'); var shadowRoot = this.element.createShadowRoot(); shadowRoot.appendChild(this.browserPluginElement); @@ -34,10 +32,7 @@ } AppViewImpl.prototype.onElementDetached = function() { - if (this.guestInstanceId) { - GuestViewInternal.destroyGuest(this.guestInstanceId); - this.guestInstanceId = undefined; - } + this.guest.destroy(); }; AppViewImpl.prototype.getErrorNode = function() { @@ -55,7 +50,7 @@ }; AppViewImpl.prototype.connect = function(app, data, callback) { - if (!this.elementAttached || this.pendingGuestCreation) { + if (!this.elementAttached) { if (callback) { callback(false); } @@ -65,47 +60,40 @@ 'appId': app, 'data': data || {} }; - GuestViewInternal.createGuest( - 'appview', - createParams, - function(guestInstanceId) { - this.pendingGuestCreation = false; - if (guestInstanceId && !this.elementAttached) { - GuestViewInternal.destroyGuest(guestInstanceId); - guestInstanceId = 0; - } - if (!guestInstanceId) { - this.browserPluginElement.style.visibility = 'hidden'; - var errorMsg = 'Unable to connect to app "' + app + '".'; - window.console.warn(errorMsg); - this.getErrorNode().innerText = errorMsg; - if (callback) { - callback(false); - } - return; - } - this.attachWindow(guestInstanceId); + + this.guest.create(createParams, function() { + if (!this.guest.getId()) { + this.browserPluginElement.style.visibility = 'hidden'; + var errorMsg = 'Unable to connect to app "' + app + '".'; + window.console.warn(errorMsg); + this.getErrorNode().innerText = errorMsg; if (callback) { - callback(true); + callback(false); } - }.bind(this) - ); - this.pendingGuestCreation = true; + return; + } + this.attachWindow(); + if (callback) { + callback(true); + } + }.bind(this)); }; -AppViewImpl.prototype.attachWindow = function(guestInstanceId) { - this.guestInstanceId = guestInstanceId; - if (!this.internalInstanceId) { - return; - } +AppViewImpl.prototype.buildAttachParams = function() { var params = { 'instanceId': this.viewInstanceId }; + return params; +}; + +AppViewImpl.prototype.attachWindow = function() { + if (!this.internalInstanceId) { + return true; + } + this.browserPluginElement.style.visibility = 'visible'; - return guestViewInternalNatives.AttachGuest( - this.internalInstanceId, - guestInstanceId, - params); + this.guest.attach(this.internalInstanceId, this.buildAttachParams()); + return true; }; AppViewImpl.prototype.handleBrowserPluginAttributeMutation = @@ -114,16 +102,10 @@ this.browserPluginElement.removeAttribute('internalinstanceid'); this.internalInstanceId = parseInt(newValue); - if (!!this.guestInstanceId && this.guestInstanceId != 0) { - var params = { - 'instanceId': this.viewInstanceId - }; - guestViewInternalNatives.AttachGuest( - this.internalInstanceId, - this.guestInstanceId, - params); + if (!this.guest.getId()) { + return; } - return; + this.guest.attach(this.internalInstanceId, this.buildAttachParams()); } };
diff --git a/extensions/renderer/resources/guest_view/guest_view.js b/extensions/renderer/resources/guest_view/guest_view.js index 92d4413..4a5734b 100644 --- a/extensions/renderer/resources/guest_view/guest_view.js +++ b/extensions/renderer/resources/guest_view/guest_view.js
@@ -1,4 +1,4 @@ -// Copyright (c) 2014 The Chromium Authors. All rights reserved. +// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -12,16 +12,17 @@ // Possible states. var GUEST_STATE_ATTACHED = 'attached'; var GUEST_STATE_CREATED = 'created'; -var GUEST_STATE_DESTROYED = 'destroyed'; var GUEST_STATE_START = 'start'; // Error messages. var ERROR_MSG_ATTACH = 'Error calling attach: '; var ERROR_MSG_CREATE = 'Error calling create: '; var ERROR_MSG_DESTROY = 'Error calling destroy: '; +var ERROR_MSG_DETACH = 'Error calling detach: '; +var ERROR_MSG_ALREADY_ATTACHED = 'The guest has already been attached.'; var ERROR_MSG_ALREADY_CREATED = 'The guest has already been created.'; -var ERROR_MSG_DESTROYED = 'The guest is destroyed.'; var ERROR_MSG_INVALID_STATE = 'The guest is in an invalid state.'; +var ERROR_MSG_NOT_ATTACHED = 'The guest is not attached.'; var ERROR_MSG_NOT_CREATED = 'The guest has not been created.'; // Contains and hides the internal implementation details of |GuestView|, @@ -50,7 +51,7 @@ } this.pendingAction = null; this.performNextAction(); -} +}; // Perform the next action in the queue, if one exists. GuestViewImpl.prototype.performNextAction = function() { @@ -70,10 +71,9 @@ case GUEST_STATE_START: window.console.error(ERROR_MSG_ATTACH + ERROR_MSG_NOT_CREATED); return; - case GUEST_STATE_DESTROYED: - window.console.error(ERROR_MSG_ATTACH + ERROR_MSG_DESTROYED); - return; case GUEST_STATE_ATTACHED: + window.console.error(ERROR_MSG_ATTACH + ERROR_MSG_ALREADY_ATTACHED); + return; case GUEST_STATE_CREATED: break; default: @@ -82,16 +82,32 @@ } // Callback wrapper function to store the contentWindow from the attachGuest() - // callback, and advance the queue. - var storeContentWindow = function(callback, contentWindow) { + // callback, handle potential attaching failure, register an automatic detach, + // and advance the queue. + var callbackWrapper = function(callback, contentWindow) { this.contentWindow = contentWindow; + + // Check if attaching failed. + if (this.contentWindow === null) { + this.state = GUEST_STATE_CREATED; + } else { + // Detach automatically when the container is destroyed. + GuestViewInternalNatives.RegisterDestructionCallback(internalInstanceId, + function() { + if (this.state == GUEST_STATE_ATTACHED) { + this.contentWindow = null; + this.state = GUEST_STATE_CREATED; + } + }.bind(this)); + } + this.handleCallback(callback); - } + }; GuestViewInternalNatives.AttachGuest(internalInstanceId, this.id, attachParams, - storeContentWindow.bind(this, callback)); + callbackWrapper.bind(this, callback)); this.state = GUEST_STATE_ATTACHED; }; @@ -100,9 +116,6 @@ GuestViewImpl.prototype.createImpl = function(createParams, callback) { // Check the current state. switch (this.state) { - case GUEST_STATE_DESTROYED: - window.console.error(ERROR_MSG_CREATE + ERROR_MSG_DESTROYED); - return; case GUEST_STATE_ATTACHED: case GUEST_STATE_CREATED: window.console.error(ERROR_MSG_CREATE + ERROR_MSG_ALREADY_CREATED); @@ -115,15 +128,22 @@ } // Callback wrapper function to store the guestInstanceId from the - // createGuest() callback, and advance the queue. - var storeId = function(callback, guestInstanceId) { + // createGuest() callback, handle potential creation failure, and advance the + // queue. + var callbackWrapper = function(callback, guestInstanceId) { this.id = guestInstanceId; + + // Check if creation failed. + if (this.id === 0) { + this.state = GUEST_STATE_START; + } + this.handleCallback(callback); - } + }; GuestViewInternal.createGuest(this.viewType, createParams, - storeId.bind(this, callback)); + callbackWrapper.bind(this, callback)); this.state = GUEST_STATE_CREATED; }; @@ -132,15 +152,11 @@ GuestViewImpl.prototype.destroyImpl = function(callback) { // Check the current state. switch (this.state) { - case GUEST_STATE_DESTROYED: - window.console.error(ERROR_MSG_DESTROY + ERROR_MSG_DESTROYED); - return; - case GUEST_STATE_START: - window.console.error(ERROR_MSG_DESTROY + ERROR_MSG_NOT_CREATED); - return; case GUEST_STATE_ATTACHED: case GUEST_STATE_CREATED: break; + case GUEST_STATE_START: + return; default: window.console.error(ERROR_MSG_DESTROY + ERROR_MSG_INVALID_STATE); return; @@ -148,16 +164,36 @@ GuestViewInternal.destroyGuest(this.id, this.handleCallback.bind(this, callback)); + this.contentWindow = null; this.id = 0; + this.state = GUEST_STATE_START; +}; - this.state = GUEST_STATE_DESTROYED; +// Internal implementation of detach(). +GuestViewImpl.prototype.detachImpl = function(callback) { + // Check the current state. + switch (this.state) { + case GUEST_STATE_ATTACHED: + break; + case GUEST_STATE_CREATED: + case GUEST_STATE_START: + window.console.error(ERROR_MSG_DETACH + ERROR_MSG_NOT_ATTACHED); + return; + default: + window.console.error(ERROR_MSG_DETACH + ERROR_MSG_INVALID_STATE); + return; + } + + // TODO(fsamuel): Implement DetachGuest() in c++. + this.handleCallback(); + this.contentWindow = null; + this.state = GUEST_STATE_CREATED; }; // The exposed interface to a guestview. Exposes in its API the functions // attach(), create(), destroy(), and getId(). All other implementation details // are hidden. - function GuestView(viewType, guestInstanceId) { privates(this).internal = new GuestViewImpl(viewType, guestInstanceId); } @@ -187,6 +223,13 @@ internal.performNextAction(); }; +// Detaches the guestview from its container. +GuestView.prototype.detach = function(callback) { + var internal = privates(this).internal; + internal.actionQueue.push(internal.detachImpl.bind(internal, callback)); + internal.performNextAction(); +}; + // Returns the contentWindow for this guestview. GuestView.prototype.getContentWindow = function() { var internal = privates(this).internal;
diff --git a/extensions/renderer/resources/guest_view/guest_view_container.js b/extensions/renderer/resources/guest_view/guest_view_container.js index 09528eba..c77eba40 100644 --- a/extensions/renderer/resources/guest_view/guest_view_container.js +++ b/extensions/renderer/resources/guest_view/guest_view_container.js
@@ -1,4 +1,4 @@ -// Copyright (c) 2014 The Chromium Authors. All rights reserved. +// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file.
diff --git a/extensions/renderer/resources/guest_view/web_view.js b/extensions/renderer/resources/guest_view/web_view.js index 6ff6fb8..e4a1b09 100644 --- a/extensions/renderer/resources/guest_view/web_view.js +++ b/extensions/renderer/resources/guest_view/web_view.js
@@ -9,9 +9,6 @@ var DocumentNatives = requireNative('document_natives'); var GuestView = require('guestView').GuestView; var GuestViewContainer = require('guestViewContainer').GuestViewContainer; -var GuestViewInternal = - require('binding').Binding.create('guestViewInternal').generate(); -var GuestViewInternalNatives = requireNative('guest_view_internal'); var IdGenerator = requireNative('id_generator'); var WebViewConstants = require('webViewConstants').WebViewConstants; var WebViewEvents = require('webViewEvents').WebViewEvents; @@ -54,7 +51,7 @@ // Create default implementations for undefined API methods. var createDefaultApiMethod = function(m) { return function(var_args) { - if (!this.guest.getId()) {window.console.log(this); + if (!this.guest.getId()) { return false; } var args = $Array.concat([this.guest.getId()], $Array.slice(arguments)); @@ -80,19 +77,10 @@ // Resets some state upon detaching <webview> element from the DOM. WebViewImpl.prototype.onElementDetached = function() { - // If the guest's ID is defined then the <webview> has navigated and has - // already picked up a partition ID. Thus, we need to reset the initialization - // state. However, it may be the case that beforeFirstNavigation is false BUT - // the guest's ID has yet to be initialized. This means that we have not - // heard back from createGuest yet. We will not reset the flag in this case so - // that we don't end up allocating a second guest. - if (this.guest.getId()) { - this.guest.destroy(); - this.guest = new GuestView('webview'); - this.beforeFirstNavigation = true; - this.attributes[WebViewConstants.ATTRIBUTE_PARTITION].validPartitionId = - true; - } + this.guest.destroy(); + this.beforeFirstNavigation = true; + this.attributes[WebViewConstants.ATTRIBUTE_PARTITION].validPartitionId = + true; this.internalInstanceId = 0; }; @@ -232,10 +220,9 @@ WebViewConstants.ATTRIBUTE_PARTITION].getValue() }; - this.guest.create(params, - function() { - this.attachWindow(); - }.bind(this)); + this.guest.create(params, function() { + this.attachWindow(); + }.bind(this)); }; WebViewImpl.prototype.onFrameNameChanged = function(name) { @@ -305,12 +292,15 @@ return params; }; -WebViewImpl.prototype.attachWindow = function(guestInstanceId) { - if (guestInstanceId) { - if (this.guest.getId() && this.guest.getId() != guestInstanceId) { - this.guest.destroy(); +WebViewImpl.prototype.attachWindow = function(opt_guestInstanceId) { + // If |opt_guestInstanceId| was provided, then a different existing guest is + // being attached to this webview, and the current one will get destroyed. + if (opt_guestInstanceId) { + if (this.guest.getId() == opt_guestInstanceId) { + return true; } - this.guest = new GuestView('webview', guestInstanceId); + this.guest.destroy(); + this.guest = new GuestView('webview', opt_guestInstanceId); } if (!this.internalInstanceId) {
diff --git a/extensions/renderer/resources/guest_view/web_view_api_methods.js b/extensions/renderer/resources/guest_view/web_view_api_methods.js index c6701b6..10e316a8 100644 --- a/extensions/renderer/resources/guest_view/web_view_api_methods.js +++ b/extensions/renderer/resources/guest_view/web_view_api_methods.js
@@ -1,4 +1,4 @@ -// Copyright (c) 2014 The Chromium Authors. All rights reserved. +// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file.
diff --git a/extensions/renderer/resources/guest_view/web_view_attributes.js b/extensions/renderer/resources/guest_view/web_view_attributes.js index aa1b7598..d76b61f 100644 --- a/extensions/renderer/resources/guest_view/web_view_attributes.js +++ b/extensions/renderer/resources/guest_view/web_view_attributes.js
@@ -1,4 +1,4 @@ -// Copyright (c) 2014 The Chromium Authors. All rights reserved. +// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file.
diff --git a/extensions/renderer/resources/json_schema.js b/extensions/renderer/resources/json_schema.js index 67c30c9..147dd67 100644 --- a/extensions/renderer/resources/json_schema.js +++ b/extensions/renderer/resources/json_schema.js
@@ -132,8 +132,8 @@ return "null"; } else if (Object.prototype.toString.call(value) == "[object Array]") { return "array"; - } else if (typeof(ArrayBuffer) != "undefined" && - value.constructor == ArrayBuffer) { + } else if (Object.prototype.toString.call(value) == + "[object ArrayBuffer]") { return "binary"; } } else if (s == "number") {
diff --git a/extensions/shell/BUILD.gn b/extensions/shell/BUILD.gn index ccaf688..db2979e 100644 --- a/extensions/shell/BUILD.gn +++ b/extensions/shell/BUILD.gn
@@ -19,15 +19,15 @@ } source_set("app_shell_lib") { - # This library is testonly because it depends on testonly libarries, - # namely //base:prefs_test_support and //content/shell:content_shell_lib - # TODO(jamescook): investigate and get rid of test dependencies. + # TODO(jamescook): investigate and get rid of test dependencies. This library + # is testonly because it depends on testonly libraries, namely + # //content/shell:content_shell_lib. See http://crbug.com/438283 testonly = true deps = [ ":resources", ":version_header", "//base", - "//base:prefs_test_support", + "//base:prefs", "//components/omaha_client", "//components/pref_registry", "//components/user_prefs", @@ -108,6 +108,8 @@ "browser/shell_oauth2_token_service.h", "browser/shell_omaha_query_params_delegate.cc", "browser/shell_omaha_query_params_delegate.h", + "browser/shell_prefs.cc", + "browser/shell_prefs.h", "browser/shell_runtime_api_delegate.cc", "browser/shell_runtime_api_delegate.h", "browser/shell_special_storage_policy.cc", @@ -139,6 +141,7 @@ sources += [ "browser/api/shell_gcd/shell_gcd_api.cc", "browser/api/shell_gcd/shell_gcd_api.h", + "browser/api/vpn_provider/vpn_service_factory.cc", ] } }
diff --git a/extensions/shell/app_shell.gyp b/extensions/shell/app_shell.gyp index ef9b246..f2c7565 100644 --- a/extensions/shell/app_shell.gyp +++ b/extensions/shell/app_shell.gyp
@@ -13,7 +13,7 @@ 'dependencies': [ 'app_shell_version_header', '<(DEPTH)/base/base.gyp:base', - '<(DEPTH)/base/base.gyp:base_prefs_test_support', + '<(DEPTH)/base/base.gyp:base_prefs', '<(DEPTH)/components/components.gyp:omaha_client', '<(DEPTH)/components/components.gyp:pref_registry', '<(DEPTH)/components/components.gyp:user_prefs', @@ -95,6 +95,8 @@ 'browser/shell_oauth2_token_service.h', 'browser/shell_omaha_query_params_delegate.cc', 'browser/shell_omaha_query_params_delegate.h', + 'browser/shell_prefs.cc', + 'browser/shell_prefs.h', 'browser/shell_runtime_api_delegate.cc', 'browser/shell_runtime_api_delegate.h', 'browser/shell_special_storage_policy.cc', @@ -139,6 +141,7 @@ 'sources': [ 'browser/api/shell_gcd/shell_gcd_api.cc', 'browser/api/shell_gcd/shell_gcd_api.h', + 'browser/api/vpn_provider/vpn_service_factory.cc', ], }], ['disable_nacl==0 and OS=="linux"', { @@ -250,6 +253,7 @@ 'dependencies': [ 'app_shell_lib', '<(DEPTH)/base/base.gyp:base', + '<(DEPTH)/base/base.gyp:base_prefs_test_support', '<(DEPTH)/base/base.gyp:test_support_base', '<(DEPTH)/content/content.gyp:content_app_both', '<(DEPTH)/content/content_shell_and_tests.gyp:test_support_content', @@ -264,6 +268,7 @@ 'browser/shell_audio_controller_chromeos_unittest.cc', 'browser/shell_native_app_window_aura_unittest.cc', 'browser/shell_oauth2_token_service_unittest.cc', + 'browser/shell_prefs_unittest.cc', 'common/shell_content_client_unittest.cc' ], 'conditions': [
diff --git a/extensions/shell/browser/api/vpn_provider/OWNERS b/extensions/shell/browser/api/vpn_provider/OWNERS new file mode 100644 index 0000000..9e75e8cd --- /dev/null +++ b/extensions/shell/browser/api/vpn_provider/OWNERS
@@ -0,0 +1,3 @@ +kaliamoorthi@chromium.org +bartfab@chromium.org +pneubeck@chromium.org
diff --git a/extensions/shell/browser/api/vpn_provider/vpn_service_factory.cc b/extensions/shell/browser/api/vpn_provider/vpn_service_factory.cc new file mode 100644 index 0000000..0a6a150 --- /dev/null +++ b/extensions/shell/browser/api/vpn_provider/vpn_service_factory.cc
@@ -0,0 +1,49 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions/browser/api/vpn_provider/vpn_service_factory.h" + +#include "base/memory/singleton.h" +#include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "extensions/browser/api/vpn_provider/vpn_service.h" + +namespace chromeos { + +// This file is a dummy stub for use in appshell. + +// static +VpnService* VpnServiceFactory::GetForBrowserContext( + content::BrowserContext* context) { + return static_cast<VpnService*>( + GetInstance()->GetServiceForBrowserContext(context, true)); +} + +// static +VpnServiceFactory* VpnServiceFactory::GetInstance() { + return Singleton<VpnServiceFactory>::get(); +} + +VpnServiceFactory::VpnServiceFactory() + : BrowserContextKeyedServiceFactory( + "VpnService", + BrowserContextDependencyManager::GetInstance()) { +} + +VpnServiceFactory::~VpnServiceFactory() { +} + +bool VpnServiceFactory::ServiceIsCreatedWithBrowserContext() const { + return true; +} + +bool VpnServiceFactory::ServiceIsNULLWhileTesting() const { + return true; +} + +KeyedService* VpnServiceFactory::BuildServiceInstanceFor( + content::BrowserContext* context) const { + return nullptr; +} + +} // namespace chromeos
diff --git a/extensions/shell/browser/shell_browser_context.h b/extensions/shell/browser/shell_browser_context.h index 1bc4db6..08c72be6 100644 --- a/extensions/shell/browser/shell_browser_context.h +++ b/extensions/shell/browser/shell_browser_context.h
@@ -37,6 +37,7 @@ private: void InitURLRequestContextOnIOThread(); + net::NetLog* net_log_; scoped_refptr<storage::SpecialStoragePolicy> storage_policy_;
diff --git a/extensions/shell/browser/shell_browser_main_parts.cc b/extensions/shell/browser/shell_browser_main_parts.cc index 7af36498..fe60355 100644 --- a/extensions/shell/browser/shell_browser_main_parts.cc +++ b/extensions/shell/browser/shell_browser_main_parts.cc
@@ -4,7 +4,10 @@ #include "extensions/shell/browser/shell_browser_main_parts.h" +#include <string> + #include "base/command_line.h" +#include "base/prefs/pref_service.h" #include "base/run_loop.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" #include "components/omaha_client/omaha_query_params.h" @@ -31,6 +34,7 @@ #include "extensions/shell/browser/shell_extensions_browser_client.h" #include "extensions/shell/browser/shell_oauth2_token_service.h" #include "extensions/shell/browser/shell_omaha_query_params_delegate.h" +#include "extensions/shell/browser/shell_prefs.h" #include "extensions/shell/common/shell_extensions_client.h" #include "extensions/shell/common/switches.h" #include "ui/base/ime/input_method_initializer.h" @@ -128,6 +132,7 @@ void ShellBrowserMainParts::PreMainMessageLoopRun() { // Initialize our "profile" equivalent. browser_context_.reset(new ShellBrowserContext(net_log_.get())); + pref_service_ = ShellPrefs::CreatePrefService(browser_context_.get()); #if defined(USE_AURA) aura::Env::GetInstance()->set_context_factory(content::GetContextFactory()); @@ -146,8 +151,8 @@ extensions_client_.reset(CreateExtensionsClient()); ExtensionsClient::Set(extensions_client_.get()); - extensions_browser_client_.reset( - CreateExtensionsBrowserClient(browser_context_.get())); + extensions_browser_client_.reset(CreateExtensionsBrowserClient( + browser_context_.get(), pref_service_.get())); ExtensionsBrowserClient::Set(extensions_browser_client_.get()); omaha_query_params_delegate_.reset(new ShellOmahaQueryParamsDelegate); @@ -221,6 +226,7 @@ } void ShellBrowserMainParts::PostMainMessageLoopRun() { + // NOTE: Please destroy objects in the reverse order of their creation. browser_main_delegate_->Shutdown(); devtools_http_handler_.reset(); @@ -235,11 +241,14 @@ extension_system_ = NULL; ExtensionsBrowserClient::Set(NULL); extensions_browser_client_.reset(); - browser_context_.reset(); desktop_controller_.reset(); storage_monitor::StorageMonitor::Destroy(); + + pref_service_->CommitPendingWrite(); + pref_service_.reset(); + browser_context_.reset(); } void ShellBrowserMainParts::PostDestroyThreads() { @@ -257,8 +266,9 @@ } ExtensionsBrowserClient* ShellBrowserMainParts::CreateExtensionsBrowserClient( - content::BrowserContext* context) { - return new ShellExtensionsBrowserClient(context); + content::BrowserContext* context, + PrefService* service) { + return new ShellExtensionsBrowserClient(context, service); } void ShellBrowserMainParts::CreateExtensionSystem() {
diff --git a/extensions/shell/browser/shell_browser_main_parts.h b/extensions/shell/browser/shell_browser_main_parts.h index 29032b17..edc88104 100644 --- a/extensions/shell/browser/shell_browser_main_parts.h +++ b/extensions/shell/browser/shell_browser_main_parts.h
@@ -13,6 +13,8 @@ #include "content/public/common/main_function_params.h" #include "ui/aura/window_tree_host_observer.h" +class PrefService; + namespace content { class BrowserContext; class DevToolsHttpHandler; @@ -71,7 +73,8 @@ // This class takes ownership of the returned objects. virtual ExtensionsClient* CreateExtensionsClient(); virtual ExtensionsBrowserClient* CreateExtensionsBrowserClient( - content::BrowserContext* context); + content::BrowserContext* context, + PrefService* service); private: // Creates and initializes the ExtensionSystem. @@ -83,6 +86,7 @@ #endif scoped_ptr<DesktopController> desktop_controller_; scoped_ptr<ShellBrowserContext> browser_context_; + scoped_ptr<PrefService> pref_service_; scoped_ptr<ShellDeviceClient> device_client_; scoped_ptr<AppWindowClient> app_window_client_; scoped_ptr<ExtensionsClient> extensions_client_;
diff --git a/extensions/shell/browser/shell_extensions_browser_client.cc b/extensions/shell/browser/shell_extensions_browser_client.cc index 6cbaa14..e4006f1 100644 --- a/extensions/shell/browser/shell_extensions_browser_client.cc +++ b/extensions/shell/browser/shell_extensions_browser_client.cc
@@ -4,18 +4,12 @@ #include "extensions/shell/browser/shell_extensions_browser_client.h" -#include "base/prefs/pref_service.h" -#include "base/prefs/pref_service_factory.h" -#include "base/prefs/testing_pref_store.h" -#include "components/pref_registry/pref_registry_syncable.h" -#include "components/user_prefs/user_prefs.h" #include "content/public/browser/browser_thread.h" #include "extensions/browser/api/extensions_api_client.h" #include "extensions/browser/api/generated_api_registration.h" #include "extensions/browser/app_sorting.h" #include "extensions/browser/event_router.h" #include "extensions/browser/extension_function_registry.h" -#include "extensions/browser/extension_prefs.h" #include "extensions/browser/null_app_sorting.h" #include "extensions/browser/updater/null_extension_cache.h" #include "extensions/browser/url_request_util.h" @@ -28,33 +22,14 @@ using content::BrowserThread; namespace extensions { -namespace { - -// See chrome::RegisterProfilePrefs() in chrome/browser/prefs/browser_prefs.cc -void RegisterPrefs(user_prefs::PrefRegistrySyncable* registry) { - ExtensionPrefs::RegisterProfilePrefs(registry); -} - -} // namespace ShellExtensionsBrowserClient::ShellExtensionsBrowserClient( - BrowserContext* context) + BrowserContext* context, + PrefService* pref_service) : browser_context_(context), + pref_service_(pref_service), api_client_(new ExtensionsAPIClient), extension_cache_(new NullExtensionCache()) { - // Set up the preferences service. - base::PrefServiceFactory factory; - factory.set_user_prefs(new TestingPrefStore); - factory.set_extension_prefs(new TestingPrefStore); - // app_shell should not require syncable preferences, but for now we need to - // recycle some of the RegisterProfilePrefs() code in Chrome. - // TODO(jamescook): Convert this to PrefRegistrySimple. - user_prefs::PrefRegistrySyncable* pref_registry = - new user_prefs::PrefRegistrySyncable; - // Prefs should be registered before the PrefService is created. - RegisterPrefs(pref_registry); - prefs_ = factory.Create(pref_registry).Pass(); - user_prefs::UserPrefs::Set(browser_context_, prefs_.get()); } ShellExtensionsBrowserClient::~ShellExtensionsBrowserClient() { @@ -139,7 +114,7 @@ PrefService* ShellExtensionsBrowserClient::GetPrefServiceForContext( BrowserContext* context) { - return prefs_.get(); + return pref_service_; } void ShellExtensionsBrowserClient::GetEarlyExtensionPrefsObservers(
diff --git a/extensions/shell/browser/shell_extensions_browser_client.h b/extensions/shell/browser/shell_extensions_browser_client.h index 208e350b..b5f95eb 100644 --- a/extensions/shell/browser/shell_extensions_browser_client.h +++ b/extensions/shell/browser/shell_extensions_browser_client.h
@@ -19,7 +19,9 @@ class ShellExtensionsBrowserClient : public ExtensionsBrowserClient { public: // |context| is the single BrowserContext used for IsValidContext() below. - explicit ShellExtensionsBrowserClient(content::BrowserContext* context); + // |pref_service| is used for GetPrefServiceForContext() below. + ShellExtensionsBrowserClient(content::BrowserContext* context, + PrefService* pref_service); ~ShellExtensionsBrowserClient() override; // ExtensionsBrowserClient overrides: @@ -82,12 +84,12 @@ // The single BrowserContext for app_shell. Not owned. content::BrowserContext* browser_context_; + // The PrefService for |browser_context_|. Not owned. + PrefService* pref_service_; + // Support for extension APIs. scoped_ptr<ExtensionsAPIClient> api_client_; - // The PrefService for |browser_context_|. - scoped_ptr<PrefService> prefs_; - // The extension cache used for download and installation. scoped_ptr<ExtensionCache> extension_cache_;
diff --git a/extensions/shell/browser/shell_native_app_window.cc b/extensions/shell/browser/shell_native_app_window.cc index dd8bfa0ba..a04ce4e 100644 --- a/extensions/shell/browser/shell_native_app_window.cc +++ b/extensions/shell/browser/shell_native_app_window.cc
@@ -140,6 +140,10 @@ NOTIMPLEMENTED(); } +void ShellNativeAppWindow::SetInterceptAllKeys(bool want_all_keys) { + NOTIMPLEMENTED(); +} + void ShellNativeAppWindow::HandleKeyboardEvent( const content::NativeWebKeyboardEvent& event) { // No special handling. The WebContents will handle it.
diff --git a/extensions/shell/browser/shell_native_app_window.h b/extensions/shell/browser/shell_native_app_window.h index d86470a..e7f1325 100644 --- a/extensions/shell/browser/shell_native_app_window.h +++ b/extensions/shell/browser/shell_native_app_window.h
@@ -53,6 +53,7 @@ const std::vector<DraggableRegion>& regions) override; SkRegion* GetDraggableRegion() override; void UpdateShape(scoped_ptr<SkRegion> region) override; + void SetInterceptAllKeys(bool want_all_keys) override; void HandleKeyboardEvent( const content::NativeWebKeyboardEvent& event) override; bool IsFrameless() const override;
diff --git a/extensions/shell/browser/shell_prefs.cc b/extensions/shell/browser/shell_prefs.cc new file mode 100644 index 0000000..68d89ad --- /dev/null +++ b/extensions/shell/browser/shell_prefs.cc
@@ -0,0 +1,51 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions/shell/browser/shell_prefs.h" + +#include "base/prefs/json_pref_store.h" +#include "base/prefs/pref_filter.h" +#include "base/prefs/pref_service.h" +#include "base/prefs/pref_service_factory.h" +#include "components/pref_registry/pref_registry_syncable.h" +#include "components/user_prefs/user_prefs.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/browser_thread.h" +#include "extensions/browser/extension_prefs.h" + +using user_prefs::PrefRegistrySyncable; + +namespace extensions { + +// static +scoped_ptr<PrefService> ShellPrefs::CreatePrefService( + content::BrowserContext* browser_context) { + base::PrefServiceFactory factory; + + base::FilePath filename = + browser_context->GetPath().AppendASCII("user_prefs.json"); + scoped_refptr<base::SequencedTaskRunner> task_runner = + JsonPrefStore::GetTaskRunnerForFile( + filename, content::BrowserThread::GetBlockingPool()); + scoped_refptr<JsonPrefStore> user_prefs = + new JsonPrefStore(filename, task_runner, scoped_ptr<PrefFilter>()); + user_prefs->ReadPrefs(); // Synchronous. + factory.set_user_prefs(user_prefs); + + // TODO(jamescook): If we want to support prefs that are set by extensions + // via ChromeSettings properties (e.g. chrome.accessibilityFeatures or + // chrome.proxy) then this should create an ExtensionPrefStore and attach it + // with PrefServiceFactory::set_extension_prefs(). + // See https://developer.chrome.com/extensions/types#ChromeSetting + + // Prefs should be registered before the PrefService is created. + PrefRegistrySyncable* pref_registry = new PrefRegistrySyncable; + ExtensionPrefs::RegisterProfilePrefs(pref_registry); + + scoped_ptr<PrefService> pref_service = factory.Create(pref_registry); + user_prefs::UserPrefs::Set(browser_context, pref_service.get()); + return pref_service; +} + +} // namespace extensions
diff --git a/extensions/shell/browser/shell_prefs.h b/extensions/shell/browser/shell_prefs.h new file mode 100644 index 0000000..c81a017 --- /dev/null +++ b/extensions/shell/browser/shell_prefs.h
@@ -0,0 +1,32 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef EXTENSIONS_SHELL_BROWSER_SHELL_PREFS_H_ +#define EXTENSIONS_SHELL_BROWSER_SHELL_PREFS_H_ + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" + +class PrefService; + +namespace content { +class BrowserContext; +} + +namespace extensions { + +// Support for PrefService initialization and management. +class ShellPrefs { + public: + // Creates a pref service that loads user prefs. + static scoped_ptr<PrefService> CreatePrefService( + content::BrowserContext* browser_context); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(ShellPrefs); +}; + +} // namespace extensions + +#endif // EXTENSIONS_SHELL_BROWSER_SHELL_PREFS_H_
diff --git a/extensions/shell/browser/shell_prefs_unittest.cc b/extensions/shell/browser/shell_prefs_unittest.cc new file mode 100644 index 0000000..6e5da97 --- /dev/null +++ b/extensions/shell/browser/shell_prefs_unittest.cc
@@ -0,0 +1,59 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions/shell/browser/shell_prefs.h" + +#include "base/path_service.h" +#include "base/prefs/pref_service.h" +#include "components/user_prefs/user_prefs.h" +#include "content/public/test/test_browser_context.h" +#include "content/public/test/test_browser_thread_bundle.h" +#include "extensions/common/extension_paths.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +// A BrowserContext that uses a test data directory as its data path. +class PrefsTestBrowserContext : public content::TestBrowserContext { + public: + PrefsTestBrowserContext() {} + ~PrefsTestBrowserContext() override {} + + // content::BrowserContext: + base::FilePath GetPath() const override { + base::FilePath path; + PathService::Get(extensions::DIR_TEST_DATA, &path); + return path.AppendASCII("shell_prefs"); + } + + private: + DISALLOW_COPY_AND_ASSIGN(PrefsTestBrowserContext); +}; + +} // namespace + +namespace extensions { + +TEST(ShellPrefsTest, CreatePrefService) { + content::TestBrowserThreadBundle thread_bundle; + PrefsTestBrowserContext browser_context; + + // Create the pref service. This loads the test pref file. + scoped_ptr<PrefService> service = + ShellPrefs::CreatePrefService(&browser_context); + + // Some basic extension preferences are registered. + EXPECT_TRUE(service->FindPreference("extensions.settings")); + EXPECT_TRUE(service->FindPreference("extensions.toolbarsize")); + EXPECT_FALSE(service->FindPreference("should.not.exist")); + + // User prefs from the file have been read correctly. + EXPECT_EQ("1.2.3.4", service->GetString("extensions.last_chrome_version")); + EXPECT_EQ(123, service->GetInteger("extensions.toolbarsize")); + + // The user prefs system has been initialized. + EXPECT_EQ(service.get(), user_prefs::UserPrefs::Get(&browser_context)); +} + +} // namespace extensions
diff --git a/extensions/test/data/json_schema_test.js b/extensions/test/data/json_schema_test.js index 645fd9d..03fc057 100644 --- a/extensions/test/data/json_schema_test.js +++ b/extensions/test/data/json_schema_test.js
@@ -443,6 +443,8 @@ assertValid("Type", false, {type:"boolean"}); assertValid("Type", null, {type:"null"}); assertValid("Type", undefined, {type:"undefined"}); + assertValid("Type", new ArrayBuffer(1), {type:"binary"}); + assertValid("Type", otherContextArrayBufferContainer.value, {type:"binary"}); // not valid assertNotValid("Type", [], {type: "object"},
diff --git a/extensions/test/data/shell_prefs/user_prefs.json b/extensions/test/data/shell_prefs/user_prefs.json new file mode 100644 index 0000000..ad177768 --- /dev/null +++ b/extensions/test/data/shell_prefs/user_prefs.json
@@ -0,0 +1,7 @@ +{ + "homepage": "http://www.example.com/", + "extensions": { + "last_chrome_version": "1.2.3.4", + "toolbarsize": 123 + } +}
diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn index d918e9f..dc03b55f 100644 --- a/gpu/BUILD.gn +++ b/gpu/BUILD.gn
@@ -102,6 +102,7 @@ ":gpu", ":test_support", "//base", + "//base/test:test_support", "//base/third_party/dynamic_annotations", "//testing/gmock", "//testing/gtest", @@ -253,6 +254,7 @@ deps = [ "//base", + "//base/test:test_support", "//base/third_party/dynamic_annotations", "//testing/gmock", "//testing/gtest",
diff --git a/gpu/angle_unittest_main.cc b/gpu/angle_unittest_main.cc index 67e91ed..e7667f6 100644 --- a/gpu/angle_unittest_main.cc +++ b/gpu/angle_unittest_main.cc
@@ -3,22 +3,33 @@ // found in the LICENSE file. #include "base/at_exit.h" +#include "base/bind.h" #include "base/command_line.h" +#include "base/message_loop/message_loop.h" +#include "base/test/launcher/unit_test_launcher.h" +#include "base/test/test_suite.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/angle/include/GLSLANG/ShaderLang.h" +namespace { + +int RunHelper(base::TestSuite* test_suite) { + base::MessageLoopForIO message_loop; + return test_suite->Run(); +} + +} // namespace + int main(int argc, char** argv) { - // On Android, AtExitManager is created in - // testing/android/native_test_wrapper.cc before main() is called. - // The same thing is also done in base/test/test_suite.cc -#if !defined(OS_ANDROID) - base::AtExitManager exit_manager; -#endif CommandLine::Init(argc, argv); testing::InitGoogleMock(&argc, argv); ShInitialize(); - int rt = RUN_ALL_TESTS(); + base::TestSuite test_suite(argc, argv); + int rt = base::LaunchUnitTestsSerially( + argc, + argv, + base::Bind(&RunHelper, base::Unretained(&test_suite))); ShFinalize(); return rt; }
diff --git a/gpu/command_buffer/common/capabilities.cc b/gpu/command_buffer/common/capabilities.cc index 9d9e90d2..ab33aeb7 100644 --- a/gpu/command_buffer/common/capabilities.cc +++ b/gpu/command_buffer/common/capabilities.cc
@@ -37,7 +37,8 @@ image(false), future_sync_points(false), blend_equation_advanced(false), - blend_equation_advanced_coherent(false) { + blend_equation_advanced_coherent(false), + texture_rg(false) { } } // namespace gpu
diff --git a/gpu/command_buffer/common/capabilities.h b/gpu/command_buffer/common/capabilities.h index 224829c..a465ca23 100644 --- a/gpu/command_buffer/common/capabilities.h +++ b/gpu/command_buffer/common/capabilities.h
@@ -91,6 +91,7 @@ bool future_sync_points; bool blend_equation_advanced; bool blend_equation_advanced_coherent; + bool texture_rg; }; } // namespace gpu
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc index 4f25017c..ed0ddc95f 100644 --- a/gpu/command_buffer/service/feature_info.cc +++ b/gpu/command_buffer/service/feature_info.cc
@@ -145,7 +145,8 @@ ext_texture_storage(false), chromium_path_rendering(false), blend_equation_advanced(false), - blend_equation_advanced_coherent(false) { + blend_equation_advanced_coherent(false), + ext_texture_rg(false) { } FeatureInfo::Workarounds::Workarounds() : @@ -226,6 +227,39 @@ return true; } +bool IsGL_REDSupportedOnFBOs() { + // Skia uses GL_RED with frame buffers, unfortunately, Mesa claims to support + // GL_EXT_texture_rg, but it doesn't support it on frame buffers. To fix + // this, we try it, and if it fails, we don't expose GL_EXT_texture_rg. + GLint fb_binding = 0; + GLint tex_binding = 0; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fb_binding); + glGetIntegerv(GL_TEXTURE_BINDING_2D, &tex_binding); + + GLuint textureId = 0; + glGenTextures(1, &textureId); + glBindTexture(GL_TEXTURE_2D, textureId); + GLubyte data[1] = {0}; + glTexImage2D(GL_TEXTURE_2D, 0, GL_RED_EXT, 1, 1, 0, GL_RED_EXT, + GL_UNSIGNED_BYTE, data); + GLuint textureFBOID = 0; + glGenFramebuffersEXT(1, &textureFBOID); + glBindFramebufferEXT(GL_FRAMEBUFFER, textureFBOID); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + textureId, 0); + bool result = + glCheckFramebufferStatusEXT(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_UNSUPPORTED; + glDeleteFramebuffersEXT(1, &textureFBOID); + glDeleteTextures(1, &textureId); + + glBindFramebufferEXT(GL_FRAMEBUFFER, static_cast<GLuint>(fb_binding)); + glBindTexture(GL_TEXTURE_2D, static_cast<GLuint>(tex_binding)); + + DCHECK(glGetError() == GL_NO_ERROR); + + return result; +} + void FeatureInfo::InitializeFeatures() { // Figure out what extensions to turn on. StringSet extensions( @@ -939,6 +973,34 @@ validators_.g_l_state.AddValue(GL_PATH_PROJECTION_MATRIX_CHROMIUM); } } + + if ((is_es3 || extensions.Contains("GL_EXT_texture_rg") || + extensions.Contains("GL_ARB_texture_rg")) && + IsGL_REDSupportedOnFBOs()) { + feature_flags_.ext_texture_rg = true; + AddExtensionString("GL_EXT_texture_rg"); + + validators_.texture_format.AddValue(GL_RED_EXT); + validators_.texture_format.AddValue(GL_RG_EXT); + validators_.texture_internal_format.AddValue(GL_RED_EXT); + validators_.texture_internal_format.AddValue(GL_RG_EXT); + validators_.read_pixel_format.AddValue(GL_RED_EXT); + validators_.read_pixel_format.AddValue(GL_RG_EXT); + validators_.render_buffer_format.AddValue(GL_R8_EXT); + validators_.render_buffer_format.AddValue(GL_RG8_EXT); + + texture_format_validators_[GL_RED_EXT].AddValue(GL_UNSIGNED_BYTE); + texture_format_validators_[GL_RG_EXT].AddValue(GL_UNSIGNED_BYTE); + + if (enable_texture_float) { + texture_format_validators_[GL_RED_EXT].AddValue(GL_FLOAT); + texture_format_validators_[GL_RG_EXT].AddValue(GL_FLOAT); + } + if (enable_texture_half_float) { + texture_format_validators_[GL_RED_EXT].AddValue(GL_HALF_FLOAT_OES); + texture_format_validators_[GL_RG_EXT].AddValue(GL_HALF_FLOAT_OES); + } + } } void FeatureInfo::AddExtensionString(const char* s) {
diff --git a/gpu/command_buffer/service/feature_info.h b/gpu/command_buffer/service/feature_info.h index b69f2e4..fc3cd272 100644 --- a/gpu/command_buffer/service/feature_info.h +++ b/gpu/command_buffer/service/feature_info.h
@@ -73,6 +73,7 @@ bool chromium_path_rendering; bool blend_equation_advanced; bool blend_equation_advanced_coherent; + bool ext_texture_rg; }; struct Workarounds {
diff --git a/gpu/command_buffer/service/feature_info_unittest.cc b/gpu/command_buffer/service/feature_info_unittest.cc index e68f872..b314262e 100644 --- a/gpu/command_buffer/service/feature_info_unittest.cc +++ b/gpu/command_buffer/service/feature_info_unittest.cc
@@ -1423,5 +1423,57 @@ EXPECT_TRUE(info_->feature_flags().blend_equation_advanced_coherent); } +TEST_F(FeatureInfoTest, InitializeEXT_texture_rgWithFloat) { + SetupInitExpectations( + "GL_EXT_texture_rg GL_OES_texture_float GL_OES_texture_half_float"); + EXPECT_TRUE(info_->feature_flags().ext_texture_rg); + + EXPECT_TRUE(info_->validators()->texture_format.IsValid(GL_RED_EXT)); + EXPECT_TRUE(info_->validators()->texture_format.IsValid(GL_RG_EXT)); + EXPECT_TRUE(info_->validators()->texture_internal_format.IsValid(GL_RED_EXT)); + EXPECT_TRUE(info_->validators()->texture_internal_format.IsValid(GL_RG_EXT)); + EXPECT_TRUE(info_->validators()->read_pixel_format.IsValid(GL_RED_EXT)); + EXPECT_TRUE(info_->validators()->read_pixel_format.IsValid(GL_RG_EXT)); + EXPECT_TRUE(info_->validators()->render_buffer_format.IsValid(GL_R8_EXT)); + EXPECT_TRUE(info_->validators()->render_buffer_format.IsValid(GL_RG8_EXT)); + + EXPECT_TRUE( + info_->GetTextureFormatValidator(GL_RED_EXT).IsValid(GL_HALF_FLOAT_OES)); + EXPECT_TRUE( + info_->GetTextureFormatValidator(GL_RG_EXT).IsValid(GL_HALF_FLOAT_OES)); + EXPECT_TRUE( + info_->GetTextureFormatValidator(GL_RED_EXT).IsValid(GL_UNSIGNED_BYTE)); + EXPECT_TRUE( + info_->GetTextureFormatValidator(GL_RG_EXT).IsValid(GL_UNSIGNED_BYTE)); + + EXPECT_FALSE(info_->GetTextureFormatValidator(GL_RED_EXT).IsValid(GL_BYTE)); + EXPECT_FALSE(info_->GetTextureFormatValidator(GL_RG_EXT).IsValid(GL_BYTE)); + EXPECT_FALSE(info_->GetTextureFormatValidator(GL_RED_EXT).IsValid(GL_SHORT)); + EXPECT_FALSE(info_->GetTextureFormatValidator(GL_RG_EXT).IsValid(GL_SHORT)); +} + +TEST_F(FeatureInfoTest, InitializeARB_texture_rgNoFloat) { + SetupInitExpectations("GL_ARB_texture_rg"); + EXPECT_TRUE(info_->feature_flags().ext_texture_rg); + + EXPECT_TRUE(info_->validators()->texture_format.IsValid(GL_RED_EXT)); + EXPECT_TRUE(info_->validators()->texture_format.IsValid(GL_RG_EXT)); + EXPECT_TRUE(info_->validators()->texture_internal_format.IsValid(GL_RED_EXT)); + EXPECT_TRUE(info_->validators()->texture_internal_format.IsValid(GL_RG_EXT)); + EXPECT_TRUE(info_->validators()->read_pixel_format.IsValid(GL_RED_EXT)); + EXPECT_TRUE(info_->validators()->read_pixel_format.IsValid(GL_RG_EXT)); + EXPECT_TRUE(info_->validators()->render_buffer_format.IsValid(GL_R8_EXT)); + EXPECT_TRUE(info_->validators()->render_buffer_format.IsValid(GL_RG8_EXT)); + + EXPECT_FALSE( + info_->GetTextureFormatValidator(GL_RED_EXT).IsValid(GL_HALF_FLOAT_OES)); + EXPECT_FALSE( + info_->GetTextureFormatValidator(GL_RG_EXT).IsValid(GL_HALF_FLOAT_OES)); + EXPECT_TRUE( + info_->GetTextureFormatValidator(GL_RED_EXT).IsValid(GL_UNSIGNED_BYTE)); + EXPECT_TRUE( + info_->GetTextureFormatValidator(GL_RG_EXT).IsValid(GL_UNSIGNED_BYTE)); +} + } // namespace gles2 } // namespace gpu
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 363ecf8..9fb4fde 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -2849,6 +2849,7 @@ feature_info_->feature_flags().blend_equation_advanced; caps.blend_equation_advanced_coherent = feature_info_->feature_flags().blend_equation_advanced_coherent; + caps.texture_rg = feature_info_->feature_flags().ext_texture_rg; return caps; }
diff --git a/gpu/command_buffer/service/test_helper.cc b/gpu/command_buffer/service/test_helper.cc index cea7b8a..7d9fb6f1 100644 --- a/gpu/command_buffer/service/test_helper.cc +++ b/gpu/command_buffer/service/test_helper.cc
@@ -344,21 +344,22 @@ if (strstr(extensions, "GL_ARB_texture_float") || (is_es3 && strstr(extensions, "GL_EXT_color_buffer_float"))) { - static const GLuint gl_ids[] = {101, 102}; + static const GLuint tx_ids[] = {101, 102}; + static const GLuint fb_ids[] = {103, 104}; const GLsizei width = 16; EXPECT_CALL(*gl, GetIntegerv(GL_FRAMEBUFFER_BINDING, _)) - .WillOnce(SetArgumentPointee<1>(gl_ids[0])) + .WillOnce(SetArgumentPointee<1>(fb_ids[0])) .RetiresOnSaturation(); EXPECT_CALL(*gl, GetIntegerv(GL_TEXTURE_BINDING_2D, _)) - .WillOnce(SetArgumentPointee<1>(gl_ids[0])) + .WillOnce(SetArgumentPointee<1>(tx_ids[0])) .RetiresOnSaturation(); EXPECT_CALL(*gl, GenTextures(1, _)) - .WillOnce(SetArrayArgument<1>(gl_ids + 1, gl_ids + 2)) + .WillOnce(SetArrayArgument<1>(tx_ids + 1, tx_ids + 2)) .RetiresOnSaturation(); EXPECT_CALL(*gl, GenFramebuffersEXT(1, _)) - .WillOnce(SetArrayArgument<1>(gl_ids + 1, gl_ids + 2)) + .WillOnce(SetArrayArgument<1>(fb_ids + 1, fb_ids + 2)) .RetiresOnSaturation(); - EXPECT_CALL(*gl, BindTexture(GL_TEXTURE_2D, gl_ids[1])) + EXPECT_CALL(*gl, BindTexture(GL_TEXTURE_2D, tx_ids[1])) .Times(1) .RetiresOnSaturation(); EXPECT_CALL(*gl, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, @@ -369,11 +370,11 @@ GL_RGBA, GL_FLOAT, _)) .Times(1) .RetiresOnSaturation(); - EXPECT_CALL(*gl, BindFramebufferEXT(GL_FRAMEBUFFER, gl_ids[1])) + EXPECT_CALL(*gl, BindFramebufferEXT(GL_FRAMEBUFFER, fb_ids[1])) .Times(1) .RetiresOnSaturation(); EXPECT_CALL(*gl, FramebufferTexture2DEXT(GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gl_ids[1], 0)) + GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tx_ids[1], 0)) .Times(1) .RetiresOnSaturation(); EXPECT_CALL(*gl, CheckFramebufferStatusEXT(GL_FRAMEBUFFER)) @@ -398,10 +399,10 @@ EXPECT_CALL(*gl, DeleteTextures(1, _)) .Times(1) .RetiresOnSaturation(); - EXPECT_CALL(*gl, BindFramebufferEXT(GL_FRAMEBUFFER, gl_ids[0])) + EXPECT_CALL(*gl, BindFramebufferEXT(GL_FRAMEBUFFER, fb_ids[0])) .Times(1) .RetiresOnSaturation(); - EXPECT_CALL(*gl, BindTexture(GL_TEXTURE_2D, gl_ids[0])) + EXPECT_CALL(*gl, BindTexture(GL_TEXTURE_2D, tx_ids[0])) .Times(1) .RetiresOnSaturation(); #if DCHECK_IS_ON @@ -421,6 +422,59 @@ .WillOnce(SetArgumentPointee<1>(8)) .RetiresOnSaturation(); } + + if (is_es3 || strstr(extensions, "GL_EXT_texture_rg") || + (strstr(extensions, "GL_ARB_texture_rg"))) { + static const GLuint tx_ids[] = {101, 102}; + static const GLuint fb_ids[] = {103, 104}; + const GLsizei width = 1; + EXPECT_CALL(*gl, GetIntegerv(GL_FRAMEBUFFER_BINDING, _)) + .WillOnce(SetArgumentPointee<1>(fb_ids[0])) + .RetiresOnSaturation(); + EXPECT_CALL(*gl, GetIntegerv(GL_TEXTURE_BINDING_2D, _)) + .WillOnce(SetArgumentPointee<1>(tx_ids[0])) + .RetiresOnSaturation(); + EXPECT_CALL(*gl, GenTextures(1, _)) + .WillOnce(SetArrayArgument<1>(tx_ids + 1, tx_ids + 2)) + .RetiresOnSaturation(); + EXPECT_CALL(*gl, BindTexture(GL_TEXTURE_2D, tx_ids[1])) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl, TexImage2D(GL_TEXTURE_2D, 0, GL_RED_EXT, width, width, 0, + GL_RED_EXT, GL_UNSIGNED_BYTE, _)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl, GenFramebuffersEXT(1, _)) + .WillOnce(SetArrayArgument<1>(fb_ids + 1, fb_ids + 2)) + .RetiresOnSaturation(); + EXPECT_CALL(*gl, BindFramebufferEXT(GL_FRAMEBUFFER, fb_ids[1])) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl, FramebufferTexture2DEXT(GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tx_ids[1], 0)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl, CheckFramebufferStatusEXT(GL_FRAMEBUFFER)) + .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) + .RetiresOnSaturation(); + EXPECT_CALL(*gl, DeleteFramebuffersEXT(1, _)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl, DeleteTextures(1, _)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl, BindFramebufferEXT(GL_FRAMEBUFFER, fb_ids[0])) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl, BindTexture(GL_TEXTURE_2D, tx_ids[0])) + .Times(1) + .RetiresOnSaturation(); +#if DCHECK_IS_ON + EXPECT_CALL(*gl, GetError()) + .WillOnce(Return(GL_NO_ERROR)) + .RetiresOnSaturation(); +#endif + } } void TestHelper::SetupExpectationsForClearingUniforms(
diff --git a/gpu/command_buffer/tests/gl_test_utils.cc b/gpu/command_buffer/tests/gl_test_utils.cc index 0ab71da..d3272ca 100644 --- a/gpu/command_buffer/tests/gl_test_utils.cc +++ b/gpu/command_buffer/tests/gl_test_utils.cc
@@ -7,7 +7,6 @@ #include <stdio.h> #include "base/basictypes.h" #include "base/memory/scoped_ptr.h" -#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" // GCC requires these declarations, but MSVC requires they not be present. @@ -240,8 +239,3 @@ fclose(fp); return true; } - -int GLTestHelper::RunTests(int argc, char** argv) { - testing::InitGoogleMock(&argc, argv); - return RUN_ALL_TESTS(); -}
diff --git a/gpu/command_buffer/tests/gl_test_utils.h b/gpu/command_buffer/tests/gl_test_utils.h index 972ea0a..15a726e 100644 --- a/gpu/command_buffer/tests/gl_test_utils.h +++ b/gpu/command_buffer/tests/gl_test_utils.h
@@ -47,9 +47,6 @@ // Uses ReadPixels to save an area of the current FBO/Backbuffer. static bool SaveBackbufferAsBMP(const char* filename, int width, int height); - - // Run unit tests. - static int RunTests(int argc, char** argv); }; #endif // GPU_COMMAND_BUFFER_TESTS_GL_TEST_UTILS_H_
diff --git a/gpu/command_buffer/tests/gl_tests_main.cc b/gpu/command_buffer/tests/gl_tests_main.cc index 460ecae..8952e44 100644 --- a/gpu/command_buffer/tests/gl_tests_main.cc +++ b/gpu/command_buffer/tests/gl_tests_main.cc
@@ -3,14 +3,17 @@ // found in the LICENSE file. #include "base/at_exit.h" +#include "base/bind.h" #include "base/command_line.h" #include "base/message_loop/message_loop.h" #if defined(OS_MACOSX) #include "base/mac/scoped_nsautorelease_pool.h" #endif +#include "base/test/launcher/unit_test_launcher.h" +#include "base/test/test_suite.h" #include "gpu/command_buffer/client/gles2_lib.h" -#include "gpu/command_buffer/tests/gl_test_utils.h" #include "gpu/config/gpu_util.h" +#include "testing/gmock/include/gmock/gmock.h" #include "ui/gl/gl_surface.h" #if defined(OS_ANDROID) @@ -18,12 +21,20 @@ #include "ui/gl/android/gl_jni_registrar.h" #endif +namespace { + +int RunHelper(base::TestSuite* testSuite) { + base::MessageLoopForIO message_loop; + return testSuite->Run(); +} + +} // namespace + int main(int argc, char** argv) { #if defined(OS_ANDROID) ui::gl::android::RegisterJni(base::android::AttachCurrentThread()); -#else - base::AtExitManager exit_manager; #endif + base::TestSuite test_suite(argc, argv); CommandLine::Init(argc, argv); #if defined(OS_MACOSX) base::mac::ScopedNSAutoreleasePool pool; @@ -31,8 +42,9 @@ gfx::GLSurface::InitializeOneOff(); ::gles2::Initialize(); gpu::ApplyGpuDriverBugWorkarounds(CommandLine::ForCurrentProcess()); - base::MessageLoop main_message_loop; - return GLTestHelper::RunTests(argc, argv); + testing::InitGoogleMock(&argc, argv); + return base::LaunchUnitTestsSerially( + argc, + argv, + base::Bind(&RunHelper, base::Unretained(&test_suite))); } - -
diff --git a/gpu/command_buffer/tests/gl_unittest.cc b/gpu/command_buffer/tests/gl_unittest.cc index 99151900..49eb0025 100644 --- a/gpu/command_buffer/tests/gl_unittest.cc +++ b/gpu/command_buffer/tests/gl_unittest.cc
@@ -5,6 +5,7 @@ #include <GLES2/gl2.h> #include <GLES2/gl2ext.h> +#include "gpu/command_buffer/service/feature_info.h" #include "gpu/command_buffer/tests/gl_manager.h" #include "gpu/command_buffer/tests/gl_test_utils.h" #include "testing/gmock/include/gmock/gmock.h" @@ -88,6 +89,25 @@ EXPECT_TRUE(GLTestHelper::CheckPixels(0, 0, 1, 1, 0, expected_draw)); } +TEST_F(GLTest, FeatureFlagsMatchCapabilities) { + scoped_refptr<gles2::FeatureInfo> features = new gles2::FeatureInfo; + EXPECT_TRUE(features->Initialize()); + const auto& caps = gl_.GetCapabilities(); + const auto& flags = features->feature_flags(); + EXPECT_EQ(caps.egl_image_external, flags.oes_egl_image_external); + EXPECT_EQ(caps.texture_format_bgra8888, flags.ext_texture_format_bgra8888); + EXPECT_EQ(caps.texture_format_etc1, flags.oes_compressed_etc1_rgb8_texture); + EXPECT_EQ(caps.texture_rectangle, flags.arb_texture_rectangle); + EXPECT_EQ(caps.texture_usage, flags.angle_texture_usage); + EXPECT_EQ(caps.texture_storage, flags.ext_texture_storage); + EXPECT_EQ(caps.discard_framebuffer, flags.ext_discard_framebuffer); + EXPECT_EQ(caps.sync_query, flags.chromium_sync_query); + EXPECT_EQ(caps.blend_equation_advanced, flags.blend_equation_advanced); + EXPECT_EQ(caps.blend_equation_advanced_coherent, + flags.blend_equation_advanced_coherent); + EXPECT_EQ(caps.texture_rg, flags.ext_texture_rg); +} + TEST_F(GLTest, GetString) { EXPECT_STREQ( "OpenGL ES 2.0 Chromium",
diff --git a/gpu/gpu.gyp b/gpu/gpu.gyp index 5a9deb1d..40eb5f9 100644 --- a/gpu/gpu.gyp +++ b/gpu/gpu.gyp
@@ -128,6 +128,7 @@ 'type': '<(gtest_target_type)', 'dependencies': [ '../base/base.gyp:base', + '../base/base.gyp:test_support_base', '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', '../testing/gmock.gyp:gmock', '../testing/gtest.gyp:gtest', @@ -293,6 +294,7 @@ 'type': '<(gtest_target_type)', 'dependencies': [ '../base/base.gyp:base', + '../base/base.gyp:test_support_base', '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', '../testing/gmock.gyp:gmock', '../testing/gtest.gyp:gtest',
diff --git a/gpu/ipc/gpu_command_buffer_traits_multi.h b/gpu/ipc/gpu_command_buffer_traits_multi.h index 0978f79..8201f32 100644 --- a/gpu/ipc/gpu_command_buffer_traits_multi.h +++ b/gpu/ipc/gpu_command_buffer_traits_multi.h
@@ -56,4 +56,5 @@ IPC_STRUCT_TRAITS_MEMBER(image) IPC_STRUCT_TRAITS_MEMBER(blend_equation_advanced) IPC_STRUCT_TRAITS_MEMBER(blend_equation_advanced_coherent) + IPC_STRUCT_TRAITS_MEMBER(texture_rg) IPC_STRUCT_TRAITS_END()
diff --git a/ios/OWNERS b/ios/OWNERS index edb8e91..8fe2174 100644 --- a/ios/OWNERS +++ b/ios/OWNERS
@@ -1,3 +1,3 @@ -blundell@chromium.org +droger@chromium.org rohitrao@chromium.org stuartmorgan@chromium.org
diff --git a/ios/ios.gyp b/ios/ios.gyp index 81bda61..23c62c8 100644 --- a/ios/ios.gyp +++ b/ios/ios.gyp
@@ -12,6 +12,7 @@ 'dependencies': [ 'ios_base.gyp:*', 'ios_tests_unit.gyp:*', + 'provider/ios_provider_chrome.gyp:*', 'provider/ios_provider_web.gyp:*', 'web/ios_web.gyp:*', ],
diff --git a/ios/provider/ios_provider_chrome.gyp b/ios/provider/ios_provider_chrome.gyp new file mode 100644 index 0000000..eb8e1f1 --- /dev/null +++ b/ios/provider/ios_provider_chrome.gyp
@@ -0,0 +1,22 @@ +# Copyright 2013 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +{ + 'variables': { + 'chromium_code': 1, + }, + 'targets': [ + { + 'target_name': 'ios_provider_chrome_browser', + 'type': 'static_library', + 'sources': [ + '../public/provider/chrome/browser/browser_state/chrome_browser_state.cc', + '../public/provider/chrome/browser/browser_state/chrome_browser_state.h', + ], + 'dependencies': [ + '../../base/base.gyp:base', + 'ios_provider_web.gyp:ios_provider_web', + ], + }, + ], +}
diff --git a/ios/public/provider/chrome/browser/DEPS b/ios/public/provider/chrome/browser/DEPS new file mode 100644 index 0000000..41a04b1 --- /dev/null +++ b/ios/public/provider/chrome/browser/DEPS
@@ -0,0 +1,3 @@ +include_rules = [ + "+ios/public/provider/web", +]
diff --git a/ios/public/provider/chrome/browser/browser_state/chrome_browser_state.cc b/ios/public/provider/chrome/browser/browser_state/chrome_browser_state.cc new file mode 100644 index 0000000..fc8f705 --- /dev/null +++ b/ios/public/provider/chrome/browser/browser_state/chrome_browser_state.cc
@@ -0,0 +1,18 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ios/public/provider/chrome/browser/browser_state/chrome_browser_state.h" + +#include "ios/public/provider/web/web_state.h" + +namespace ios { + +// static +ChromeBrowserState* ChromeBrowserState::FromBrowserState( + web::BrowserState* browser_state) { + // This is safe; this is the only implementation of BrowserState. + return static_cast<ChromeBrowserState*>(browser_state); +} + +} // namespace ios
diff --git a/ios/public/provider/chrome/browser/browser_state/chrome_browser_state.h b/ios/public/provider/chrome/browser/browser_state/chrome_browser_state.h new file mode 100644 index 0000000..781bb931 --- /dev/null +++ b/ios/public/provider/chrome/browser/browser_state/chrome_browser_state.h
@@ -0,0 +1,50 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_PUBLIC_PROVIDER_CHROME_BROWSER_BROWSER_STATE_CHROME_BROWSER_STATE_H_ +#define IOS_PUBLIC_PROVIDER_CHROME_BROWSER_BROWSER_STATE_CHROME_BROWSER_STATE_H_ + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "ios/web/public/browser_state.h" + +class PrefService; + +namespace ios { + +// This class is a Chrome-specific extension of the BrowserState interface. +class ChromeBrowserState : public web::BrowserState { + public: + ~ChromeBrowserState() override {} + + // Returns the ChromeBrowserState corresponding to the given BrowserState. + static ChromeBrowserState* FromBrowserState(BrowserState* browser_state); + + // Returns the original "recording" ChromeBrowserState. This method returns + // |this| if the ChromeBrowserState is not incognito. + virtual ChromeBrowserState* GetOriginalChromeBrowserState() = 0; + + // Returns the incognito version of this ChromeBrowserState. The returned + // ChromeBrowserState instance is owned by this ChromeBrowserState instance. + // WARNING: This will create the OffTheRecord ChromeBrowserState if it + // doesn't already exist. + virtual ChromeBrowserState* GetOffTheRecordChromeBrowserState() = 0; + + // Destroys the OffTheRecord ChromeBrowserState that is associated with this + // ChromeBrowserState, if one exists. + virtual void DestroyOffTheRecordChromeBrowserState() = 0; + + // Retrieves a pointer to the PrefService that manages the preferences. + virtual PrefService* GetPrefs() = 0; + + protected: + ChromeBrowserState() {} + + private: + DISALLOW_COPY_AND_ASSIGN(ChromeBrowserState); +}; + +} // namespace ios + +#endif // IOS_PUBLIC_PROVIDER_CHROME_BROWSER_BROWSER_STATE_CHROME_BROWSER_STATE_H_
diff --git a/media/audio/agc_audio_stream.h b/media/audio/agc_audio_stream.h index f7b909f..d0ac2bf 100644 --- a/media/audio/agc_audio_stream.h +++ b/media/audio/agc_audio_stream.h
@@ -138,10 +138,11 @@ // be read in each AudioInputCallback::OnData() callback and fed to the // render-side AGC. User must call StartAgc() as well to start measuring // the microphone level. - virtual void SetAutomaticGainControl(bool enabled) override { + virtual bool SetAutomaticGainControl(bool enabled) override { DVLOG(1) << "SetAutomaticGainControl(enabled=" << enabled << ")"; DCHECK(thread_checker_.CalledOnValidThread()); agc_is_enabled_ = enabled; + return true; } // Gets the current automatic gain control state.
diff --git a/media/audio/android/audio_record_input.cc b/media/audio/android/audio_record_input.cc index 1dd6118..92e0a0f4 100644 --- a/media/audio/android/audio_record_input.cc +++ b/media/audio/android/audio_record_input.cc
@@ -125,8 +125,9 @@ return 0.0; } -void AudioRecordInputStream::SetAutomaticGainControl(bool enabled) { +bool AudioRecordInputStream::SetAutomaticGainControl(bool enabled) { NOTIMPLEMENTED(); + return false; } bool AudioRecordInputStream::GetAutomaticGainControl() {
diff --git a/media/audio/android/audio_record_input.h b/media/audio/android/audio_record_input.h index d4c4368..f3ef519 100644 --- a/media/audio/android/audio_record_input.h +++ b/media/audio/android/audio_record_input.h
@@ -38,7 +38,7 @@ virtual double GetMaxVolume() override; virtual void SetVolume(double volume) override; virtual double GetVolume() override; - virtual void SetAutomaticGainControl(bool enabled) override; + virtual bool SetAutomaticGainControl(bool enabled) override; virtual bool GetAutomaticGainControl() override; virtual bool IsMuted() override;
diff --git a/media/audio/android/opensles_input.cc b/media/audio/android/opensles_input.cc index d8e5f63d..a68126c 100644 --- a/media/audio/android/opensles_input.cc +++ b/media/audio/android/opensles_input.cc
@@ -176,8 +176,9 @@ return 0.0; } -void OpenSLESInputStream::SetAutomaticGainControl(bool enabled) { +bool OpenSLESInputStream::SetAutomaticGainControl(bool enabled) { NOTIMPLEMENTED(); + return false; } bool OpenSLESInputStream::GetAutomaticGainControl() {
diff --git a/media/audio/android/opensles_input.h b/media/audio/android/opensles_input.h index ae62639..ff945353 100644 --- a/media/audio/android/opensles_input.h +++ b/media/audio/android/opensles_input.h
@@ -41,7 +41,7 @@ virtual double GetMaxVolume() override; virtual void SetVolume(double volume) override; virtual double GetVolume() override; - virtual void SetAutomaticGainControl(bool enabled) override; + virtual bool SetAutomaticGainControl(bool enabled) override; virtual bool GetAutomaticGainControl() override; virtual bool IsMuted() override;
diff --git a/media/audio/audio_input_controller.cc b/media/audio/audio_input_controller.cc index 44ecb29..6d0f3b0 100644 --- a/media/audio/audio_input_controller.cc +++ b/media/audio/audio_input_controller.cc
@@ -329,7 +329,17 @@ // Set AGC state using mode in |agc_is_enabled_| which can only be enabled in // CreateLowLatency(). +#if defined(AUDIO_POWER_MONITORING) + bool agc_is_supported = false; + agc_is_supported = stream_->SetAutomaticGainControl(agc_is_enabled_); + // Disable power measurements on platforms that does not support AGC at a + // lower level. AGC can fail on platforms where we don't support the + // functionality to modify the input volume slider. One such example is + // Windows XP. + power_measurement_is_enabled_ &= agc_is_supported; +#else stream_->SetAutomaticGainControl(agc_is_enabled_); +#endif // Create the data timer which will call FirstCheckForNoData(). The timer // is started in DoRecord() and restarted in each DoCheckForNoData()
diff --git a/media/audio/audio_io.h b/media/audio/audio_io.h index 3add053..e3b5c60 100644 --- a/media/audio/audio_io.h +++ b/media/audio/audio_io.h
@@ -160,7 +160,7 @@ virtual double GetVolume() = 0; // Sets the Automatic Gain Control (AGC) state. - virtual void SetAutomaticGainControl(bool enabled) = 0; + virtual bool SetAutomaticGainControl(bool enabled) = 0; // Returns the Automatic Gain Control (AGC) state. virtual bool GetAutomaticGainControl() = 0;
diff --git a/media/audio/fake_audio_input_stream.cc b/media/audio/fake_audio_input_stream.cc index ce65c690..7fe3f825d 100644 --- a/media/audio/fake_audio_input_stream.cc +++ b/media/audio/fake_audio_input_stream.cc
@@ -305,10 +305,12 @@ return false; } -void FakeAudioInputStream::SetAutomaticGainControl(bool enabled) {} +bool FakeAudioInputStream::SetAutomaticGainControl(bool enabled) { + return false; +} bool FakeAudioInputStream::GetAutomaticGainControl() { - return true; + return false; } // static
diff --git a/media/audio/fake_audio_input_stream.h b/media/audio/fake_audio_input_stream.h index 1fed3052a..659ac93 100644 --- a/media/audio/fake_audio_input_stream.h +++ b/media/audio/fake_audio_input_stream.h
@@ -38,7 +38,7 @@ void SetVolume(double volume) override; double GetVolume() override; bool IsMuted() override; - void SetAutomaticGainControl(bool enabled) override; + bool SetAutomaticGainControl(bool enabled) override; bool GetAutomaticGainControl() override; // Generate one beep sound. This method is called by
diff --git a/media/audio/mac/audio_input_mac.cc b/media/audio/mac/audio_input_mac.cc index af5d9bc..bc44386 100644 --- a/media/audio/mac/audio_input_mac.cc +++ b/media/audio/mac/audio_input_mac.cc
@@ -141,8 +141,9 @@ return false; } -void PCMQueueInAudioInputStream::SetAutomaticGainControl(bool enabled) { +bool PCMQueueInAudioInputStream::SetAutomaticGainControl(bool enabled) { NOTREACHED() << "Only supported for low-latency mode."; + return false; } bool PCMQueueInAudioInputStream::GetAutomaticGainControl() {
diff --git a/media/audio/mac/audio_input_mac.h b/media/audio/mac/audio_input_mac.h index 56453d2..02203343 100644 --- a/media/audio/mac/audio_input_mac.h +++ b/media/audio/mac/audio_input_mac.h
@@ -36,7 +36,7 @@ double GetMaxVolume() override; void SetVolume(double volume) override; double GetVolume() override; - void SetAutomaticGainControl(bool enabled) override; + bool SetAutomaticGainControl(bool enabled) override; bool GetAutomaticGainControl() override; bool IsMuted() override;
diff --git a/media/audio/virtual_audio_input_stream.cc b/media/audio/virtual_audio_input_stream.cc index a961b53..04e421a1 100644 --- a/media/audio/virtual_audio_input_stream.cc +++ b/media/audio/virtual_audio_input_stream.cc
@@ -38,7 +38,7 @@ private: double ProvideInput(AudioBus* audio_bus, base::TimeDelta buffer_delay) override { - audio_converter_.Convert(audio_bus); + audio_converter_.ConvertWithDelay(buffer_delay, audio_bus); return 1.0; } @@ -137,9 +137,13 @@ { base::AutoLock scoped_lock(converter_network_lock_); - mixer_.Convert(audio_bus); + // Because the audio is being looped-back, the delay until it will be played + // out is zero. + mixer_.ConvertWithDelay(base::TimeDelta(), audio_bus); } - callback_->OnData(this, audio_bus, params_.GetBytesPerBuffer(), 1.0); + // Because the audio is being looped-back, the delay since since it was + // recorded is zero. + callback_->OnData(this, audio_bus, 0, 1.0); } void VirtualAudioInputStream::Close() { @@ -167,7 +171,9 @@ return 1.0; } -void VirtualAudioInputStream::SetAutomaticGainControl(bool enabled) {} +bool VirtualAudioInputStream::SetAutomaticGainControl(bool enabled) { + return false; +} bool VirtualAudioInputStream::GetAutomaticGainControl() { return false;
diff --git a/media/audio/virtual_audio_input_stream.h b/media/audio/virtual_audio_input_stream.h index 66d1a46f..3b98f6d 100644 --- a/media/audio/virtual_audio_input_stream.h +++ b/media/audio/virtual_audio_input_stream.h
@@ -54,7 +54,7 @@ double GetMaxVolume() override; void SetVolume(double volume) override; double GetVolume() override; - void SetAutomaticGainControl(bool enabled) override; + bool SetAutomaticGainControl(bool enabled) override; bool GetAutomaticGainControl() override; bool IsMuted() override;
diff --git a/media/audio/virtual_audio_output_stream.cc b/media/audio/virtual_audio_output_stream.cc index 016c2f3..29e3804f 100644 --- a/media/audio/virtual_audio_output_stream.cc +++ b/media/audio/virtual_audio_output_stream.cc
@@ -77,7 +77,12 @@ // platform. DCHECK(callback_); - const int frames = callback_->OnMoreData(audio_bus, 0); + DCHECK_GE(buffer_delay, base::TimeDelta()); + const int64 upstream_delay_in_bytes = + params_.GetBytesPerSecond() * buffer_delay / + base::TimeDelta::FromSeconds(1); + const int frames = callback_->OnMoreData( + audio_bus, static_cast<uint32>(upstream_delay_in_bytes)); if (frames < audio_bus->frames()) audio_bus->ZeroFramesPartial(frames, audio_bus->frames() - frames);
diff --git a/media/audio/win/wavein_input_win.cc b/media/audio/win/wavein_input_win.cc index 72c5841..6543ee5e 100644 --- a/media/audio/win/wavein_input_win.cc +++ b/media/audio/win/wavein_input_win.cc
@@ -215,9 +215,10 @@ return 0.0; } -void PCMWaveInAudioInputStream::SetAutomaticGainControl(bool enabled) { +bool PCMWaveInAudioInputStream::SetAutomaticGainControl(bool enabled) { // TODO(henrika): Add AGC support when volume control has been added. NOTIMPLEMENTED(); + return false; } bool PCMWaveInAudioInputStream::GetAutomaticGainControl() {
diff --git a/media/audio/win/wavein_input_win.h b/media/audio/win/wavein_input_win.h index 8c22c9b..6b98d0d 100644 --- a/media/audio/win/wavein_input_win.h +++ b/media/audio/win/wavein_input_win.h
@@ -43,7 +43,7 @@ virtual double GetMaxVolume() override; virtual void SetVolume(double volume) override; virtual double GetVolume() override; - virtual void SetAutomaticGainControl(bool enabled) override; + virtual bool SetAutomaticGainControl(bool enabled) override; virtual bool GetAutomaticGainControl() override; virtual bool IsMuted() override;
diff --git a/media/base/mac/avfoundation_glue.h b/media/base/mac/avfoundation_glue.h index 73a747b..c1b8aa8 100644 --- a/media/base/mac/avfoundation_glue.h +++ b/media/base/mac/avfoundation_glue.h
@@ -26,8 +26,6 @@ static NSBundle const* AVFoundationBundle(); - static void* AVFoundationLibraryHandle(); - // Originally coming from AVCaptureDevice.h but in global namespace. static NSString* AVCaptureDeviceWasConnectedNotification(); static NSString* AVCaptureDeviceWasDisconnectedNotification();
diff --git a/media/base/mac/avfoundation_glue.mm b/media/base/mac/avfoundation_glue.mm index c9985c4e..9fec550 100644 --- a/media/base/mac/avfoundation_glue.mm +++ b/media/base/mac/avfoundation_glue.mm
@@ -9,7 +9,6 @@ #include "base/command_line.h" #include "base/lazy_instance.h" #include "base/mac/mac_util.h" -#include "base/metrics/field_trial.h" #include "media/base/media_switches.h" namespace { @@ -57,7 +56,6 @@ } NSBundle* bundle() const { return bundle_; } - void* library_handle() const { return library_handle_; } NSString* AVCaptureDeviceWasConnectedNotification() const { return AVCaptureDeviceWasConnectedNotification_; @@ -100,45 +98,39 @@ DISALLOW_COPY_AND_ASSIGN(AVFoundationInternal); }; -} // namespace - -static base::LazyInstance<AVFoundationInternal> g_avfoundation_handle = - LAZY_INSTANCE_INITIALIZER; - -bool AVFoundationGlue::IsAVFoundationSupported() { - // DeviceMonitorMac will initialize this static bool from the main UI thread - // once, during Chrome startup so this construction is thread safe. - // Use AVFoundation if possible, enabled, and QTKit is not explicitly forced. - static CommandLine* command_line = CommandLine::ForCurrentProcess(); - +// This contains the logic of checking whether AVFoundation is supported. +// It's called only once and the results are cached in a static bool. +bool IsAVFoundationSupportedHelper() { // AVFoundation is only available on OS Lion and above. if (!base::mac::IsOSLionOrLater()) return false; + const CommandLine* command_line = CommandLine::ForCurrentProcess(); + // The force-qtkit flag takes precedence over enable-avfoundation. if (command_line->HasSwitch(switches::kForceQTKit)) return false; - // Next in precedence is the enable-avfoundation flag. - // TODO(vrk): Does this really need to be static? - static bool should_enable_avfoundation = - command_line->HasSwitch(switches::kEnableAVFoundation) || - base::FieldTrialList::FindFullName("AVFoundationMacVideoCapture") - == "Enabled"; - // Try to load AVFoundation. Save result in static bool to avoid loading - // AVFoundationBundle every call. - static bool loaded_successfully = [AVFoundationBundle() load]; - return should_enable_avfoundation && loaded_successfully; + return command_line->HasSwitch(switches::kEnableAVFoundation) && + [AVFoundationGlue::AVFoundationBundle() load]; +} + +} // namespace + +static base::LazyInstance<AVFoundationInternal>::Leaky g_avfoundation_handle = + LAZY_INSTANCE_INITIALIZER; + +bool AVFoundationGlue::IsAVFoundationSupported() { + // DeviceMonitorMac will initialize this static bool from the main UI thread + // once, during Chrome startup so this construction is thread safe. + static const bool is_supported = IsAVFoundationSupportedHelper(); + return is_supported; } NSBundle const* AVFoundationGlue::AVFoundationBundle() { return g_avfoundation_handle.Get().bundle(); } -void* AVFoundationGlue::AVFoundationLibraryHandle() { - return g_avfoundation_handle.Get().library_handle(); -} - NSString* AVFoundationGlue::AVCaptureDeviceWasConnectedNotification() { return g_avfoundation_handle.Get().AVCaptureDeviceWasConnectedNotification(); }
diff --git a/media/base/pipeline.cc b/media/base/pipeline.cc index 79a50fd..68ae42f 100644 --- a/media/base/pipeline.cc +++ b/media/base/pipeline.cc
@@ -357,14 +357,14 @@ start_timestamp_ = demuxer_->GetStartTime(); } - base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK); - DCHECK(start_timestamp_ >= base::TimeDelta()); renderer_->StartPlayingFrom(start_timestamp_); if (text_renderer_) text_renderer_->StartPlaying(); + base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK); + PlaybackRateChangedTask(GetPlaybackRate()); VolumeChangedTask(GetVolume()); return;
diff --git a/media/blink/encrypted_media_player_support.cc b/media/blink/encrypted_media_player_support.cc index bfb6ed52..01422e5 100644 --- a/media/blink/encrypted_media_player_support.cc +++ b/media/blink/encrypted_media_player_support.cc
@@ -20,7 +20,6 @@ #include "third_party/WebKit/public/platform/WebMediaPlayerClient.h" #include "third_party/WebKit/public/web/WebDocument.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" -#include "third_party/WebKit/public/web/WebRuntimeFeatures.h" using blink::WebMediaPlayer; using blink::WebMediaPlayerClient; @@ -138,9 +137,8 @@ std::string ascii_key_system = GetUnprefixedKeySystemName(ToASCIIOrEmpty(key_system)); - WebMediaPlayer::MediaKeyException e = - GenerateKeyRequestInternal(frame, ascii_key_system, init_data, - init_data_length); + WebMediaPlayer::MediaKeyException e = GenerateKeyRequestInternal( + frame, ascii_key_system, init_data, init_data_length); ReportMediaKeyExceptionToUMA("generateKeyRequest", ascii_key_system, e); return e; } @@ -185,11 +183,8 @@ if (init_data_type.empty()) init_data_type = GuessInitDataType(init_data, init_data_length); - // TODO(xhwang): We assume all streams are from the same container (thus have - // the same "type") for now. In the future, the "type" should be passed down - // from the application. - if (!proxy_decryptor_->GenerateKeyRequest( - init_data_type, init_data, init_data_length)) { + if (!proxy_decryptor_->GenerateKeyRequest(init_data_type, init_data, + init_data_length)) { current_key_system_.clear(); return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported; } @@ -278,34 +273,20 @@ return WebMediaPlayer::MediaKeyExceptionNoError; } -Demuxer::NeedKeyCB EncryptedMediaPlayerSupport::CreateNeedKeyCB() { - return BIND_TO_RENDER_LOOP(&EncryptedMediaPlayerSupport::OnNeedKey); +void EncryptedMediaPlayerSupport::SetInitDataType( + const std::string& init_data_type) { + DCHECK(!init_data_type.empty()); + DLOG_IF(WARNING, + !init_data_type_.empty() && init_data_type != init_data_type_) + << "Mixed init data type not supported. The new type is ignored."; + if (init_data_type_.empty()) + init_data_type_ = init_data_type; } void EncryptedMediaPlayerSupport::OnPipelineDecryptError() { EmeUMAHistogramCounts(current_key_system_, "DecryptError", 1); } -void EncryptedMediaPlayerSupport::OnNeedKey( - const std::string& type, - const std::vector<uint8>& init_data) { - // Do not fire NeedKey event if encrypted media is not enabled. - if (!blink::WebRuntimeFeatures::isPrefixedEncryptedMediaEnabled() && - !blink::WebRuntimeFeatures::isEncryptedMediaEnabled()) { - return; - } - - UMA_HISTOGRAM_COUNTS(kMediaEme + std::string("NeedKey"), 1); - - DCHECK(init_data_type_.empty() || type.empty() || type == init_data_type_); - if (init_data_type_.empty()) - init_data_type_ = type; - - const uint8* init_data_ptr = init_data.empty() ? NULL : &init_data[0]; - client_->encrypted(WebString::fromUTF8(type), init_data_ptr, - base::saturated_cast<unsigned int>(init_data.size())); -} - void EncryptedMediaPlayerSupport::OnKeyAdded(const std::string& session_id) { EmeUMAHistogramCounts(current_key_system_, "KeyAdded", 1); client_->keyAdded(
diff --git a/media/blink/encrypted_media_player_support.h b/media/blink/encrypted_media_player_support.h index a80ff58..c261ec3 100644 --- a/media/blink/encrypted_media_player_support.h +++ b/media/blink/encrypted_media_player_support.h
@@ -31,9 +31,7 @@ // Provides support to prefixed EME implementation. // Do NOT add unprefixed EME functionality to this class! -// TODO(xhwang): Move CreateNeedKeyCB() outside this class. Then when we -// deprecate prefixed EME support, drop this whole file. - +// TODO(xhwang): When deprecating prefixed EME support, drop this whole file. class EncryptedMediaPlayerSupport : public base::SupportsWeakPtr<EncryptedMediaPlayerSupport> { public: @@ -63,7 +61,7 @@ const blink::WebString& key_system, const blink::WebString& session_id); - Demuxer::NeedKeyCB CreateNeedKeyCB(); + void SetInitDataType(const std::string& init_data_type); void OnPipelineDecryptError(); @@ -86,9 +84,6 @@ const std::string& key_system, const std::string& session_id); - void OnNeedKey(const std::string& type, - const std::vector<uint8>& init_data); - void OnKeyAdded(const std::string& session_id); void OnKeyError(const std::string& session_id, MediaKeys::KeyError error_code, @@ -105,8 +100,8 @@ // has been selected. std::string current_key_system_; - // Temporary for EME v0.1. In the future the init data type should be passed - // through GenerateKeyRequest() directly from WebKit. + // We assume all streams are from the same container, thus have the same + // init data type. std::string init_data_type_; SetCdmContextCB set_cdm_context_cb_;
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc index e5f73f0..b862928 100644 --- a/media/blink/webmediaplayer_impl.cc +++ b/media/blink/webmediaplayer_impl.cc
@@ -60,6 +60,7 @@ #include "third_party/WebKit/public/platform/WebString.h" #include "third_party/WebKit/public/platform/WebURL.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" +#include "third_party/WebKit/public/web/WebRuntimeFeatures.h" #include "third_party/WebKit/public/web/WebSecurityOrigin.h" #include "third_party/WebKit/public/web/WebView.h" @@ -325,7 +326,7 @@ } void WebMediaPlayerImpl::seek(double seconds) { - DVLOG(1) << __FUNCTION__ << "(" << seconds << ")"; + DVLOG(1) << __FUNCTION__ << "(" << seconds << "s)"; DCHECK(main_task_runner_->BelongsToCurrentThread()); ended_ = false; @@ -699,6 +700,26 @@ BIND_TO_RENDER_LOOP1(&WebMediaPlayerImpl::OnCdmAttached, result)); } +void WebMediaPlayerImpl::OnNeedKey(const std::string& init_data_type, + const std::vector<uint8>& init_data) { + DCHECK(!init_data_type.empty()); + + // Do not fire NeedKey event if encrypted media is not enabled. + // TODO(xhwang): Handle this in |client_|. + if (!blink::WebRuntimeFeatures::isPrefixedEncryptedMediaEnabled() && + !blink::WebRuntimeFeatures::isEncryptedMediaEnabled()) { + return; + } + + UMA_HISTOGRAM_COUNTS("Media.EME.NeedKey", 1); + + encrypted_media_support_.SetInitDataType(init_data_type); + + const uint8* init_data_ptr = init_data.empty() ? nullptr : &init_data[0]; + client_->encrypted(WebString::fromUTF8(init_data_type), init_data_ptr, + base::saturated_cast<unsigned int>(init_data.size())); +} + void WebMediaPlayerImpl::SetCdm(CdmContext* cdm_context, const CdmAttachedCB& cdm_attached_cb) { pipeline_.SetCdm(cdm_context, cdm_attached_cb); @@ -910,7 +931,7 @@ LogCB mse_log_cb; Demuxer::NeedKeyCB need_key_cb = - encrypted_media_support_.CreateNeedKeyCB(); + BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnNeedKey); // Figure out which demuxer to use. if (load_type_ != LoadTypeMediaSource) {
diff --git a/media/blink/webmediaplayer_impl.h b/media/blink/webmediaplayer_impl.h index 596df9e7..466b566 100644 --- a/media/blink/webmediaplayer_impl.h +++ b/media/blink/webmediaplayer_impl.h
@@ -209,6 +209,10 @@ // compositor can return the frame. scoped_refptr<VideoFrame> GetCurrentFrameFromCompositor(); + // Called when the demuxer encounters encrypted streams. + void OnNeedKey(const std::string& init_data_type, + const std::vector<uint8>& init_data); + void SetCdm(CdmContext* cdm_context, const CdmAttachedCB& cdm_attached_cb); // Called when a CDM has been attached to the |pipeline_|.
diff --git a/media/ffmpeg/ffmpeg_regression_tests.cc b/media/ffmpeg/ffmpeg_regression_tests.cc index ebb2b9a6..644fd037 100644 --- a/media/ffmpeg/ffmpeg_regression_tests.cc +++ b/media/ffmpeg/ffmpeg_regression_tests.cc
@@ -18,51 +18,32 @@ // // Test cases labeled FLAKY may not always pass, but they should never crash or // cause any kind of warnings or errors under tooling. -// -// Frame hashes must be generated with --video-threads=1 for correctness. -// -// Known issues: -// Cr47325 will generate an UninitValue error under Valgrind inside of the -// MD5 hashing code. The error occurs due to some problematic error -// resilence code for H264 inside of FFmpeg. See http://crbug.com/119020 -// -// Some OGG files leak ~30 bytes of memory, upstream tracking bug: -// https://ffmpeg.org/trac/ffmpeg/ticket/1244 -// -// Some OGG files leak hundreds of kilobytes of memory, upstream bug: -// https://ffmpeg.org/trac/ffmpeg/ticket/1931 #include "media/filters/pipeline_integration_test_base.h" #include <string> #include "base/bind.h" -#include "media/base/test_data_util.h" namespace media { const char kRegressionTestDataPathPrefix[] = "internal/"; struct RegressionTestData { - RegressionTestData(const char* filename, PipelineStatus init_status, - PipelineStatus end_status, const char* video_md5, - const char* audio_md5) - : video_md5(video_md5), - audio_md5(audio_md5), - filename(std::string(kRegressionTestDataPathPrefix) + filename), + RegressionTestData(const char* filename, + PipelineStatus init_status, + PipelineStatus end_status) + : filename(std::string(kRegressionTestDataPathPrefix) + filename), init_status(init_status), - end_status(end_status) { - } + end_status(end_status) {} - const char* video_md5; - const char* audio_md5; std::string filename; PipelineStatus init_status; PipelineStatus end_status; }; // Used for tests which just need to run without crashing or tooling errors, but -// which may have undefined behavior for hashing, etc. +// which may have undefined PipelineStatus results. struct FlakyRegressionTestData { FlakyRegressionTestData(const char* filename) : filename(std::string(kRegressionTestDataPathPrefix) + filename) { @@ -81,243 +62,235 @@ public PipelineIntegrationTestBase { }; -#define FFMPEG_TEST_CASE(name, fn, init_status, end_status, video_md5, \ - audio_md5) \ - INSTANTIATE_TEST_CASE_P(name, FFmpegRegressionTest, \ - testing::Values(RegressionTestData(fn, \ - init_status, \ - end_status, \ - video_md5, \ - audio_md5))); +#define FFMPEG_TEST_CASE(name, fn, init_status, end_status) \ + INSTANTIATE_TEST_CASE_P( \ + name, FFmpegRegressionTest, \ + testing::Values(RegressionTestData(fn, init_status, end_status))); #define FLAKY_FFMPEG_TEST_CASE(name, fn) \ INSTANTIATE_TEST_CASE_P(FLAKY_##name, FlakyFFmpegRegressionTest, \ testing::Values(FlakyRegressionTestData(fn))); // Test cases from issues. -FFMPEG_TEST_CASE(Cr47325, "security/47325.mp4", PIPELINE_OK, PIPELINE_OK, - "2a7a938c6b5979621cec998f02d9bbb6", - "3.61,1.64,-3.24,0.12,1.50,-0.86,"); -FFMPEG_TEST_CASE(Cr47761, "crbug47761.ogg", PIPELINE_OK, PIPELINE_OK, - kNullVideoHash, - "8.89,8.55,8.88,8.01,8.23,7.69,"); -FFMPEG_TEST_CASE(Cr50045, "crbug50045.mp4", PIPELINE_OK, PIPELINE_OK, - "c345e9ef9ebfc6bfbcbe3f0ddc3125ba", - "2.72,-6.27,-6.11,-3.17,-5.58,1.26,"); -FFMPEG_TEST_CASE(Cr62127, "crbug62127.webm", PIPELINE_OK, - PIPELINE_OK, "a064b2776fc5aef3e9cba47967a75db9", - kNullAudioHash); -FFMPEG_TEST_CASE(Cr93620, "security/93620.ogg", PIPELINE_OK, PIPELINE_OK, - kNullVideoHash, - "-10.55,-10.10,-10.42,-10.35,-10.29,-10.72,"); -FFMPEG_TEST_CASE(Cr100492, "security/100492.webm", DECODER_ERROR_NOT_SUPPORTED, - DECODER_ERROR_NOT_SUPPORTED, kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(Cr100543, "security/100543.webm", PIPELINE_OK, PIPELINE_OK, - "c16691cc9178db3adbf7e562cadcd6e6", - "1211.73,304.89,1311.54,371.34,1283.06,299.63,"); -FFMPEG_TEST_CASE(Cr101458, "security/101458.webm", DECODER_ERROR_NOT_SUPPORTED, - DECODER_ERROR_NOT_SUPPORTED, kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(Cr108416, "security/108416.webm", PIPELINE_OK, PIPELINE_OK, - "5cb3a934795cd552753dec7687928291", - "-17.87,-37.20,-23.33,45.57,8.13,-9.92,"); -FFMPEG_TEST_CASE(Cr110849, "security/110849.mkv", +FFMPEG_TEST_CASE(Cr47325, "security/47325.mp4", PIPELINE_OK, PIPELINE_OK); +FFMPEG_TEST_CASE(Cr47761, "crbug47761.ogg", PIPELINE_OK, PIPELINE_OK); +FFMPEG_TEST_CASE(Cr50045, "crbug50045.mp4", PIPELINE_OK, PIPELINE_OK); +FFMPEG_TEST_CASE(Cr62127, "crbug62127.webm", PIPELINE_OK, PIPELINE_OK); +FFMPEG_TEST_CASE(Cr93620, "security/93620.ogg", PIPELINE_OK, PIPELINE_OK); +FFMPEG_TEST_CASE(Cr100492, + "security/100492.webm", + DECODER_ERROR_NOT_SUPPORTED, + DECODER_ERROR_NOT_SUPPORTED); +FFMPEG_TEST_CASE(Cr100543, "security/100543.webm", PIPELINE_OK, PIPELINE_OK); +FFMPEG_TEST_CASE(Cr101458, "security/101458.webm", PIPELINE_OK, PIPELINE_OK); +FFMPEG_TEST_CASE(Cr108416, "security/108416.webm", PIPELINE_OK, PIPELINE_OK); +FFMPEG_TEST_CASE(Cr110849, + "security/110849.mkv", DEMUXER_ERROR_COULD_NOT_OPEN, + DEMUXER_ERROR_NO_SUPPORTED_STREAMS); +FFMPEG_TEST_CASE(Cr112384, + "security/112384.webm", + DEMUXER_ERROR_COULD_NOT_PARSE, + DEMUXER_ERROR_COULD_NOT_PARSE); +FFMPEG_TEST_CASE(Cr112976, "security/112976.ogg", PIPELINE_OK, PIPELINE_OK); +FFMPEG_TEST_CASE(Cr116927, + "security/116927.ogv", DEMUXER_ERROR_NO_SUPPORTED_STREAMS, - kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(Cr112384, "security/112384.webm", - DEMUXER_ERROR_COULD_NOT_PARSE, DEMUXER_ERROR_COULD_NOT_PARSE, - kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(Cr117912, "security/117912.webm", DEMUXER_ERROR_COULD_NOT_OPEN, - DEMUXER_ERROR_COULD_NOT_OPEN, kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(Cr123481, "security/123481.ogv", PIPELINE_OK, - PIPELINE_OK, "e6dd853fcbd746c8bb2ab2b8fc376fc7", - "1.28,-0.32,-0.81,0.08,1.66,0.89,"); -FFMPEG_TEST_CASE(Cr132779, "security/132779.webm", - DEMUXER_ERROR_COULD_NOT_PARSE, DEMUXER_ERROR_COULD_NOT_PARSE, - kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(Cr140165, "security/140165.ogg", PIPELINE_ERROR_DECODE, - PIPELINE_ERROR_DECODE, kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(Cr140647, "security/140647.ogv", DEMUXER_ERROR_COULD_NOT_OPEN, - DEMUXER_ERROR_COULD_NOT_OPEN, kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(Cr142738, "crbug142738.ogg", PIPELINE_OK, PIPELINE_OK, - kNullVideoHash, - "-1.22,0.45,1.79,1.80,-0.30,-1.21,"); -FFMPEG_TEST_CASE(Cr152691, "security/152691.mp3", PIPELINE_ERROR_DECODE, - PIPELINE_ERROR_DECODE, kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(Cr161639, "security/161639.m4a", PIPELINE_ERROR_DECODE, - PIPELINE_ERROR_DECODE, kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(Cr222754, "security/222754.mp4", PIPELINE_ERROR_DECODE, - PIPELINE_ERROR_DECODE, kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(Cr234630a, "security/234630a.mov", PIPELINE_OK, - PIPELINE_OK, kNullVideoHash, - "-15.52,-18.90,-15.33,-16.68,-14.41,-15.89,"); -FFMPEG_TEST_CASE(Cr234630b, "security/234630b.mov", PIPELINE_ERROR_DECODE, - PIPELINE_ERROR_DECODE, kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(Cr242786, "security/242786.webm", PIPELINE_OK, - PIPELINE_OK, kNullVideoHash, - "-1.72,-0.83,0.84,1.70,1.23,-0.53,"); + DEMUXER_ERROR_NO_SUPPORTED_STREAMS); +FFMPEG_TEST_CASE(Cr117912, + "security/117912.webm", + DEMUXER_ERROR_COULD_NOT_OPEN, + DEMUXER_ERROR_COULD_NOT_OPEN); +FFMPEG_TEST_CASE(Cr123481, "security/123481.ogv", PIPELINE_OK, PIPELINE_OK); +FFMPEG_TEST_CASE(Cr132779, + "security/132779.webm", + DEMUXER_ERROR_COULD_NOT_PARSE, + DEMUXER_ERROR_COULD_NOT_PARSE); +FFMPEG_TEST_CASE(Cr140165, "security/140165.ogg", PIPELINE_OK, PIPELINE_OK); +FFMPEG_TEST_CASE(Cr140647, + "security/140647.ogv", + DEMUXER_ERROR_COULD_NOT_OPEN, + DEMUXER_ERROR_COULD_NOT_OPEN); +FFMPEG_TEST_CASE(Cr142738, "crbug142738.ogg", PIPELINE_OK, PIPELINE_OK); +FFMPEG_TEST_CASE(Cr152691, + "security/152691.mp3", + PIPELINE_OK, + PIPELINE_ERROR_DECODE); +FFMPEG_TEST_CASE(Cr161639, + "security/161639.m4a", + PIPELINE_OK, + PIPELINE_ERROR_DECODE); +FFMPEG_TEST_CASE(Cr222754, + "security/222754.mp4", + PIPELINE_OK, + PIPELINE_ERROR_DECODE); +FFMPEG_TEST_CASE(Cr234630a, "security/234630a.mov", PIPELINE_OK, PIPELINE_OK); +FFMPEG_TEST_CASE(Cr234630b, + "security/234630b.mov", + PIPELINE_OK, + PIPELINE_ERROR_DECODE); +FFMPEG_TEST_CASE(Cr242786, "security/242786.webm", PIPELINE_OK, PIPELINE_OK); // Test for out-of-bounds access with slightly corrupt file (detection logic // thinks it's a MONO file, but actually contains STEREO audio). -FFMPEG_TEST_CASE(Cr275590, "security/275590.m4a", - DECODER_ERROR_NOT_SUPPORTED, DEMUXER_ERROR_COULD_NOT_OPEN, - kNullVideoHash, kNullAudioHash); +FFMPEG_TEST_CASE(Cr275590, + "security/275590.m4a", + DECODER_ERROR_NOT_SUPPORTED, + DEMUXER_ERROR_COULD_NOT_OPEN); // General MP4 test cases. -FFMPEG_TEST_CASE(MP4_0, "security/aac.10419.mp4", DEMUXER_ERROR_COULD_NOT_OPEN, - DEMUXER_ERROR_COULD_NOT_OPEN, kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(MP4_1, "security/clockh264aac_200021889.mp4", - DEMUXER_ERROR_COULD_NOT_OPEN, DEMUXER_ERROR_COULD_NOT_OPEN, - kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(MP4_2, "security/clockh264aac_200701257.mp4", PIPELINE_OK, - PIPELINE_OK, kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(MP4_5, "security/clockh264aac_3022500.mp4", +FFMPEG_TEST_CASE(MP4_0, + "security/aac.10419.mp4", + DEMUXER_ERROR_COULD_NOT_OPEN, + DEMUXER_ERROR_COULD_NOT_OPEN); +FFMPEG_TEST_CASE(MP4_1, + "security/clockh264aac_200021889.mp4", + DEMUXER_ERROR_COULD_NOT_OPEN, + DEMUXER_ERROR_COULD_NOT_OPEN); +FFMPEG_TEST_CASE(MP4_2, + "security/clockh264aac_200701257.mp4", + PIPELINE_OK, + PIPELINE_OK); +FFMPEG_TEST_CASE(MP4_5, + "security/clockh264aac_3022500.mp4", DEMUXER_ERROR_NO_SUPPORTED_STREAMS, - DEMUXER_ERROR_NO_SUPPORTED_STREAMS, - kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(MP4_6, "security/clockh264aac_344289.mp4", PIPELINE_OK, - PIPELINE_OK, kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(MP4_7, "security/clockh264mp3_187697.mp4", - DEMUXER_ERROR_NO_SUPPORTED_STREAMS, - DEMUXER_ERROR_NO_SUPPORTED_STREAMS, - kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(MP4_8, "security/h264.705767.mp4", - DEMUXER_ERROR_COULD_NOT_PARSE, DEMUXER_ERROR_COULD_NOT_PARSE, - kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(MP4_9, "security/smclockmp4aac_1_0.mp4", - DEMUXER_ERROR_COULD_NOT_OPEN, DEMUXER_ERROR_COULD_NOT_OPEN, - kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(MP4_16, "security/looping2.mov", - DEMUXER_ERROR_COULD_NOT_OPEN, DEMUXER_ERROR_COULD_NOT_OPEN, - kNullVideoHash, kNullAudioHash); + DEMUXER_ERROR_NO_SUPPORTED_STREAMS); +FFMPEG_TEST_CASE(MP4_6, + "security/clockh264aac_344289.mp4", + PIPELINE_OK, + PIPELINE_OK); +FFMPEG_TEST_CASE(MP4_7, + "security/clockh264mp3_187697.mp4", + PIPELINE_OK, + PIPELINE_OK); +FFMPEG_TEST_CASE(MP4_8, + "security/h264.705767.mp4", + DEMUXER_ERROR_COULD_NOT_PARSE, + DEMUXER_ERROR_COULD_NOT_PARSE); +FFMPEG_TEST_CASE(MP4_9, + "security/smclockmp4aac_1_0.mp4", + DEMUXER_ERROR_COULD_NOT_OPEN, + DEMUXER_ERROR_COULD_NOT_OPEN); +FFMPEG_TEST_CASE(MP4_11, "security/null1.mp4", PIPELINE_OK, PIPELINE_OK); +FFMPEG_TEST_CASE(MP4_16, + "security/looping2.mov", + DEMUXER_ERROR_COULD_NOT_OPEN, + DEMUXER_ERROR_COULD_NOT_OPEN); +FFMPEG_TEST_CASE(MP4_17, "security/assert2.mov", PIPELINE_OK, PIPELINE_OK); // General OGV test cases. -FFMPEG_TEST_CASE(OGV_1, "security/out.163.ogv", DECODER_ERROR_NOT_SUPPORTED, - DECODER_ERROR_NOT_SUPPORTED, kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(OGV_2, "security/out.391.ogv", DECODER_ERROR_NOT_SUPPORTED, - DECODER_ERROR_NOT_SUPPORTED, kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(OGV_5, "security/smclocktheora_1_0.ogv", - DECODER_ERROR_NOT_SUPPORTED, DECODER_ERROR_NOT_SUPPORTED, - kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(OGV_7, "security/smclocktheora_1_102.ogv", - DECODER_ERROR_NOT_SUPPORTED, DECODER_ERROR_NOT_SUPPORTED, - kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(OGV_8, "security/smclocktheora_1_104.ogv", - DECODER_ERROR_NOT_SUPPORTED, DECODER_ERROR_NOT_SUPPORTED, - kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(OGV_9, "security/smclocktheora_1_110.ogv", - DECODER_ERROR_NOT_SUPPORTED, DECODER_ERROR_NOT_SUPPORTED, - kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(OGV_10, "security/smclocktheora_1_179.ogv", - DECODER_ERROR_NOT_SUPPORTED, DECODER_ERROR_NOT_SUPPORTED, - kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(OGV_11, "security/smclocktheora_1_20.ogv", - DECODER_ERROR_NOT_SUPPORTED, DECODER_ERROR_NOT_SUPPORTED, - kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(OGV_12, "security/smclocktheora_1_723.ogv", - DECODER_ERROR_NOT_SUPPORTED, DECODER_ERROR_NOT_SUPPORTED, - kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(OGV_14, "security/smclocktheora_2_10405.ogv", - DECODER_ERROR_NOT_SUPPORTED, DECODER_ERROR_NOT_SUPPORTED, - kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(OGV_15, "security/smclocktheora_2_10619.ogv", - DECODER_ERROR_NOT_SUPPORTED, DECODER_ERROR_NOT_SUPPORTED, - kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(OGV_16, "security/smclocktheora_2_1075.ogv", - DECODER_ERROR_NOT_SUPPORTED, DECODER_ERROR_NOT_SUPPORTED, - kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(OGV_18, "security/wav.711.ogv", DECODER_ERROR_NOT_SUPPORTED, - DECODER_ERROR_NOT_SUPPORTED, kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(OGV_19, "security/null1.ogv", DECODER_ERROR_NOT_SUPPORTED, - DECODER_ERROR_NOT_SUPPORTED, kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(OGV_20, "security/null2.ogv", DECODER_ERROR_NOT_SUPPORTED, - DECODER_ERROR_NOT_SUPPORTED, kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(OGV_21, "security/assert1.ogv", DECODER_ERROR_NOT_SUPPORTED, - DECODER_ERROR_NOT_SUPPORTED, kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(OGV_22, "security/assert2.ogv", DECODER_ERROR_NOT_SUPPORTED, - DECODER_ERROR_NOT_SUPPORTED, kNullVideoHash, kNullAudioHash); +FFMPEG_TEST_CASE(OGV_1, + "security/out.163.ogv", + DECODER_ERROR_NOT_SUPPORTED, + DECODER_ERROR_NOT_SUPPORTED); +FFMPEG_TEST_CASE(OGV_2, + "security/out.391.ogv", + DECODER_ERROR_NOT_SUPPORTED, + DECODER_ERROR_NOT_SUPPORTED); +FFMPEG_TEST_CASE(OGV_5, + "security/smclocktheora_1_0.ogv", + DECODER_ERROR_NOT_SUPPORTED, + DECODER_ERROR_NOT_SUPPORTED); +FFMPEG_TEST_CASE(OGV_7, + "security/smclocktheora_1_102.ogv", + DECODER_ERROR_NOT_SUPPORTED, + DECODER_ERROR_NOT_SUPPORTED); +FFMPEG_TEST_CASE(OGV_8, + "security/smclocktheora_1_104.ogv", + DECODER_ERROR_NOT_SUPPORTED, + DECODER_ERROR_NOT_SUPPORTED); +FFMPEG_TEST_CASE(OGV_9, + "security/smclocktheora_1_110.ogv", + DECODER_ERROR_NOT_SUPPORTED, + DECODER_ERROR_NOT_SUPPORTED); +FFMPEG_TEST_CASE(OGV_10, + "security/smclocktheora_1_179.ogv", + DECODER_ERROR_NOT_SUPPORTED, + DECODER_ERROR_NOT_SUPPORTED); +FFMPEG_TEST_CASE(OGV_11, + "security/smclocktheora_1_20.ogv", + DECODER_ERROR_NOT_SUPPORTED, + DECODER_ERROR_NOT_SUPPORTED); +FFMPEG_TEST_CASE(OGV_12, + "security/smclocktheora_1_723.ogv", + DECODER_ERROR_NOT_SUPPORTED, + DECODER_ERROR_NOT_SUPPORTED); +FFMPEG_TEST_CASE(OGV_14, + "security/smclocktheora_2_10405.ogv", + PIPELINE_OK, + PIPELINE_OK); +FFMPEG_TEST_CASE(OGV_15, + "security/smclocktheora_2_10619.ogv", + DECODER_ERROR_NOT_SUPPORTED, + DECODER_ERROR_NOT_SUPPORTED); +FFMPEG_TEST_CASE(OGV_16, + "security/smclocktheora_2_1075.ogv", + DECODER_ERROR_NOT_SUPPORTED, + DECODER_ERROR_NOT_SUPPORTED); +FFMPEG_TEST_CASE(OGV_17, + "security/vorbis.482086.ogv", + PIPELINE_OK, + PIPELINE_OK); +FFMPEG_TEST_CASE(OGV_18, + "security/wav.711.ogv", + DECODER_ERROR_NOT_SUPPORTED, + DECODER_ERROR_NOT_SUPPORTED); +FFMPEG_TEST_CASE(OGV_19, + "security/null1.ogv", + DECODER_ERROR_NOT_SUPPORTED, + DECODER_ERROR_NOT_SUPPORTED); +FFMPEG_TEST_CASE(OGV_20, + "security/null2.ogv", + DECODER_ERROR_NOT_SUPPORTED, + DECODER_ERROR_NOT_SUPPORTED); +FFMPEG_TEST_CASE(OGV_21, + "security/assert1.ogv", + DECODER_ERROR_NOT_SUPPORTED, + DECODER_ERROR_NOT_SUPPORTED); +FFMPEG_TEST_CASE(OGV_22, + "security/assert2.ogv", + DECODER_ERROR_NOT_SUPPORTED, + DECODER_ERROR_NOT_SUPPORTED); +FFMPEG_TEST_CASE(OGV_23, + "security/assert2.ogv", + DECODER_ERROR_NOT_SUPPORTED, + DECODER_ERROR_NOT_SUPPORTED); // General WebM test cases. -FFMPEG_TEST_CASE(WEBM_1, "security/no-bug.webm", PIPELINE_OK, PIPELINE_OK, - "39e92700cbb77478fd63f49db855e7e5", kNullAudioHash); -FFMPEG_TEST_CASE(WEBM_3, "security/out.webm.139771.2965", - DECODER_ERROR_NOT_SUPPORTED, DECODER_ERROR_NOT_SUPPORTED, - kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(WEBM_4, "security/out.webm.68798.1929", - DECODER_ERROR_NOT_SUPPORTED, DECODER_ERROR_NOT_SUPPORTED, - kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(WEBM_5, "frame_size_change.webm", PIPELINE_OK, - PIPELINE_OK, "d8fcf2896b7400a2261bac9e9ea930f8", - kNullAudioHash); +FFMPEG_TEST_CASE(WEBM_0, "security/memcpy.webm", PIPELINE_OK, PIPELINE_OK); +FFMPEG_TEST_CASE(WEBM_1, "security/no-bug.webm", PIPELINE_OK, PIPELINE_OK); +FFMPEG_TEST_CASE(WEBM_2, + "security/uninitialize.webm", + DEMUXER_ERROR_NO_SUPPORTED_STREAMS, + DEMUXER_ERROR_NO_SUPPORTED_STREAMS); +FFMPEG_TEST_CASE(WEBM_4, + "security/out.webm.68798.1929", + DECODER_ERROR_NOT_SUPPORTED, + DECODER_ERROR_NOT_SUPPORTED); +FFMPEG_TEST_CASE(WEBM_5, "frame_size_change.webm", PIPELINE_OK, PIPELINE_OK); -// Audio Functional Tests -FFMPEG_TEST_CASE(AUDIO_GAMING_0, "gaming/a_220_00.mp3", PIPELINE_OK, - PIPELINE_OK, kNullVideoHash, - "0.36,1.25,2.98,4.29,4.19,2.76,"); -FFMPEG_TEST_CASE(AUDIO_GAMING_1, "gaming/a_220_00_v2.ogg", PIPELINE_OK, - PIPELINE_OK, kNullVideoHash, - "2.17,3.31,5.15,6.33,5.97,4.35,"); -FFMPEG_TEST_CASE(AUDIO_GAMING_2, "gaming/ai_laser1.ogg", PIPELINE_OK, - PIPELINE_OK, kNullVideoHash, - "7.70,10.81,13.19,10.07,7.39,7.56,"); -FFMPEG_TEST_CASE(AUDIO_GAMING_3, "gaming/ai_laser2.ogg", PIPELINE_OK, - PIPELINE_OK, kNullVideoHash, - "5.99,8.04,9.71,8.69,7.81,7.52,"); -FFMPEG_TEST_CASE(AUDIO_GAMING_4, "gaming/ai_laser3.ogg", PIPELINE_OK, - PIPELINE_OK, kNullVideoHash, - "-0.32,1.44,3.75,5.88,6.32,3.22,"); -FFMPEG_TEST_CASE(AUDIO_GAMING_5, "gaming/ai_laser4.ogg", PIPELINE_OK, - PIPELINE_OK, kNullVideoHash, - "4.75,4.16,2.21,3.01,5.51,6.11,"); -FFMPEG_TEST_CASE(AUDIO_GAMING_6, "gaming/ai_laser5.ogg", PIPELINE_OK, - PIPELINE_OK, kNullVideoHash, - "6.04,7.46,8.78,7.32,4.16,3.97,"); -FFMPEG_TEST_CASE(AUDIO_GAMING_7, "gaming/footstep1.ogg", PIPELINE_OK, - PIPELINE_OK, kNullVideoHash, - "-0.50,0.29,2.35,4.79,5.14,2.24,"); -FFMPEG_TEST_CASE(AUDIO_GAMING_8, "gaming/footstep3.ogg", PIPELINE_OK, - PIPELINE_OK, kNullVideoHash, - "-2.87,-3.05,-4.10,-3.20,-2.20,-2.20,"); -FFMPEG_TEST_CASE(AUDIO_GAMING_9, "gaming/footstep4.ogg", PIPELINE_OK, - PIPELINE_OK, kNullVideoHash, - "10.35,10.74,11.60,12.83,12.69,10.67,"); -FFMPEG_TEST_CASE(AUDIO_GAMING_10, "gaming/laser1.ogg", PIPELINE_OK, - PIPELINE_OK, kNullVideoHash, - "-9.48,-12.94,-1.75,7.66,5.61,-0.58,"); -FFMPEG_TEST_CASE(AUDIO_GAMING_11, "gaming/laser2.ogg", PIPELINE_OK, - PIPELINE_OK, kNullVideoHash, - "-7.53,-6.28,3.37,0.73,-5.83,-4.70,"); -FFMPEG_TEST_CASE(AUDIO_GAMING_12, "gaming/laser3.ogg", PIPELINE_OK, - PIPELINE_OK, kNullVideoHash, - "-13.62,-6.55,2.52,-10.10,-10.68,-5.43,"); -FFMPEG_TEST_CASE(AUDIO_GAMING_13, "gaming/leg1.ogg", PIPELINE_OK, - PIPELINE_OK, kNullVideoHash, - "5.62,5.79,5.81,5.60,6.18,6.15,"); -FFMPEG_TEST_CASE(AUDIO_GAMING_14, "gaming/leg2.ogg", PIPELINE_OK, - PIPELINE_OK, kNullVideoHash, - "-0.88,1.32,2.74,3.07,0.88,-0.03,"); -FFMPEG_TEST_CASE(AUDIO_GAMING_15, "gaming/leg3.ogg", PIPELINE_OK, - PIPELINE_OK, kNullVideoHash, - "17.77,18.59,19.57,18.84,17.62,17.22,"); -FFMPEG_TEST_CASE(AUDIO_GAMING_16, "gaming/lock_on.ogg", PIPELINE_OK, - PIPELINE_OK, kNullVideoHash, - "3.08,-4.33,-5.04,-0.24,1.83,5.16,"); -FFMPEG_TEST_CASE(AUDIO_GAMING_17, "gaming/enemy_lock_on.ogg", - PIPELINE_OK, PIPELINE_OK, kNullVideoHash, - "-2.24,-1.00,-2.75,-0.87,1.11,-0.58,"); -FFMPEG_TEST_CASE(AUDIO_GAMING_18, "gaming/rocket_launcher.mp3", - PIPELINE_OK, PIPELINE_OK, kNullVideoHash, - "-3.08,0.18,2.49,1.98,-2.20,-4.74,"); +// General MKV test cases. +FFMPEG_TEST_CASE(MKV_0, + "security/nested_tags_lang.mka.627.628", + PIPELINE_OK, + PIPELINE_ERROR_DECODE); +FFMPEG_TEST_CASE(MKV_1, + "security/nested_tags_lang.mka.667.628", + PIPELINE_OK, + PIPELINE_ERROR_DECODE); // Allocate gigabytes of memory, likely can't be run on 32bit machines. -FFMPEG_TEST_CASE(BIG_MEM_1, "security/bigmem1.mov", - DEMUXER_ERROR_COULD_NOT_OPEN, DEMUXER_ERROR_COULD_NOT_OPEN, - kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(BIG_MEM_2, "security/looping1.mov", - DEMUXER_ERROR_COULD_NOT_OPEN, DEMUXER_ERROR_COULD_NOT_OPEN, - kNullVideoHash, kNullAudioHash); -FFMPEG_TEST_CASE(BIG_MEM_5, "security/looping5.mov", - DEMUXER_ERROR_COULD_NOT_OPEN, DEMUXER_ERROR_COULD_NOT_OPEN, - kNullVideoHash, kNullAudioHash); +FFMPEG_TEST_CASE(BIG_MEM_1, + "security/bigmem1.mov", + DEMUXER_ERROR_COULD_NOT_OPEN, + DEMUXER_ERROR_COULD_NOT_OPEN); +FFMPEG_TEST_CASE(BIG_MEM_2, + "security/looping1.mov", + DEMUXER_ERROR_COULD_NOT_OPEN, + DEMUXER_ERROR_COULD_NOT_OPEN); +FFMPEG_TEST_CASE(BIG_MEM_5, + "security/looping5.mov", + DEMUXER_ERROR_COULD_NOT_OPEN, + DEMUXER_ERROR_COULD_NOT_OPEN); FLAKY_FFMPEG_TEST_CASE(BIG_MEM_3, "security/looping3.mov"); FLAKY_FFMPEG_TEST_CASE(BIG_MEM_4, "security/looping4.mov"); @@ -336,44 +309,17 @@ FLAKY_FFMPEG_TEST_CASE(MP4_3, "security/clockh264aac_300413969.mp4"); FLAKY_FFMPEG_TEST_CASE(MP4_4, "security/clockh264aac_301350139.mp4"); FLAKY_FFMPEG_TEST_CASE(MP4_12, "security/assert1.mov"); +FLAKY_FFMPEG_TEST_CASE(WEBM_3, "security/out.webm.139771.2965"); + // Not really flaky, but can't pass the seek test. FLAKY_FFMPEG_TEST_CASE(MP4_10, "security/null1.m4a"); - -// TODO(wolenetz/dalecurtis): The following have flaky audio hash result. -// See http://crbug.com/237371 -FLAKY_FFMPEG_TEST_CASE(Cr112976, "security/112976.ogg"); -FLAKY_FFMPEG_TEST_CASE(MKV_0, "security/nested_tags_lang.mka.627.628"); -FLAKY_FFMPEG_TEST_CASE(MKV_1, "security/nested_tags_lang.mka.667.628"); -FLAKY_FFMPEG_TEST_CASE(MP4_11, "security/null1.mp4"); - -// TODO(wolenetz/dalecurtis): The following have flaky init status: on mac -// ia32 Chrome, observed PIPELINE_OK instead of DECODER_ERROR_NOT_SUPPORTED. FLAKY_FFMPEG_TEST_CASE(Cr112670, "security/112670.mp4"); -FLAKY_FFMPEG_TEST_CASE(OGV_17, "security/vorbis.482086.ogv"); - -// TODO(wolenetz/dalecurtis): The following have flaky init status: on mac -// ia32 Chrome, observed DUMUXER_ERROR_NO_SUPPORTED_STREAMS instead of -// DECODER_ERROR_NOT_SUPPORTED. -FLAKY_FFMPEG_TEST_CASE(Cr116927, "security/116927.ogv"); -FLAKY_FFMPEG_TEST_CASE(WEBM_2, "security/uninitialize.webm"); - -// Videos with massive gaps between frame timestamps that result in long hangs -// with our pipeline. Should be uncommented when we support clockless playback. -// FFMPEG_TEST_CASE(WEBM_0, "security/memcpy.webm", PIPELINE_OK, PIPELINE_OK, -// kNullVideoHash, kNullAudioHash); -// FFMPEG_TEST_CASE(MP4_17, "security/assert2.mov", PIPELINE_OK, PIPELINE_OK, -// kNullVideoHash, kNullAudioHash); -// FFMPEG_TEST_CASE(OGV_23, "security/assert2.ogv", PIPELINE_OK, PIPELINE_OK, -// kNullVideoHash, kNullAudioHash); TEST_P(FFmpegRegressionTest, BasicPlayback) { if (GetParam().init_status == PIPELINE_OK) { - ASSERT_TRUE(Start(GetTestDataFilePath(GetParam().filename), - GetParam().init_status, kHashed)); + ASSERT_EQ(PIPELINE_OK, Start(GetParam().filename, kClockless)); Play(); ASSERT_EQ(WaitUntilEndedOrError(), GetParam().end_status); - EXPECT_EQ(GetParam().video_md5, GetVideoHash()); - EXPECT_EQ(GetParam().audio_md5, GetAudioHash()); // Check for ended if the pipeline is expected to finish okay. if (GetParam().end_status == PIPELINE_OK) { @@ -383,15 +329,14 @@ Seek(base::TimeDelta::FromMilliseconds(0)); } } else { - ASSERT_FALSE(Start(GetTestDataFilePath(GetParam().filename), - GetParam().init_status, kHashed)); - EXPECT_EQ(GetParam().video_md5, GetVideoHash()); - EXPECT_EQ(GetParam().audio_md5, GetAudioHash()); + // Don't bother checking the exact status as we only care that the + // pipeline failed to start. + EXPECT_NE(PIPELINE_OK, Start(GetParam().filename)); } } TEST_P(FlakyFFmpegRegressionTest, BasicPlayback) { - if (Start(GetTestDataFilePath(GetParam().filename))) { + if (Start(GetParam().filename, kClockless) == PIPELINE_OK) { Play(); WaitUntilEndedOrError(); }
diff --git a/media/filters/audio_renderer_impl.cc b/media/filters/audio_renderer_impl.cc index 8708a91..04303703 100644 --- a/media/filters/audio_renderer_impl.cc +++ b/media/filters/audio_renderer_impl.cc
@@ -138,7 +138,7 @@ } void AudioRendererImpl::SetMediaTime(base::TimeDelta time) { - DVLOG(1) << __FUNCTION__ << "(" << time.InMicroseconds() << ")"; + DVLOG(1) << __FUNCTION__ << "(" << time << ")"; DCHECK(task_runner_->BelongsToCurrentThread()); base::AutoLock auto_lock(lock_); @@ -162,13 +162,12 @@ current_media_time = audio_clock_->front_timestamp(); } - DVLOG(3) << __FUNCTION__ << ": " << current_media_time.InMilliseconds() - << " ms"; + DVLOG(2) << __FUNCTION__ << ": " << current_media_time; return current_media_time; } base::TimeDelta AudioRendererImpl::CurrentMediaTimeForSyncingVideo() { - DVLOG(2) << __FUNCTION__; + DVLOG(3) << __FUNCTION__; base::AutoLock auto_lock(lock_); if (last_render_ticks_.is_null())
diff --git a/media/filters/chunk_demuxer.cc b/media/filters/chunk_demuxer.cc index 7e96553..3114143 100644 --- a/media/filters/chunk_demuxer.cc +++ b/media/filters/chunk_demuxer.cc
@@ -1000,6 +1000,7 @@ DemuxerStream::Type ChunkDemuxerStream::type() const { return type_; } DemuxerStream::Liveness ChunkDemuxerStream::liveness() const { + base::AutoLock auto_lock(lock_); return liveness_; } @@ -1017,14 +1018,19 @@ bool ChunkDemuxerStream::SupportsConfigChanges() { return true; } +VideoRotation ChunkDemuxerStream::video_rotation() { + return VIDEO_ROTATION_0; +} + TextTrackConfig ChunkDemuxerStream::text_track_config() { CHECK_EQ(type_, TEXT); base::AutoLock auto_lock(lock_); return stream_->GetCurrentTextTrackConfig(); } -VideoRotation ChunkDemuxerStream::video_rotation() { - return VIDEO_ROTATION_0; +void ChunkDemuxerStream::SetLiveness(Liveness liveness) { + base::AutoLock auto_lock(lock_); + liveness_ = liveness; } void ChunkDemuxerStream::ChangeState_Locked(State state) { @@ -1673,7 +1679,13 @@ return; } - liveness_ = params.liveness; + if (liveness_ != params.liveness) { + liveness_ = params.liveness; + if (audio_) + audio_->SetLiveness(liveness_); + if (video_) + video_->SetLiveness(liveness_); + } } // Wait until all streams have initialized.
diff --git a/media/filters/chunk_demuxer.h b/media/filters/chunk_demuxer.h index d778db6..63698b1 100644 --- a/media/filters/chunk_demuxer.h +++ b/media/filters/chunk_demuxer.h
@@ -102,6 +102,8 @@ return partial_append_window_trimming_enabled_; } + void SetLiveness(Liveness liveness); + private: enum State { UNINITIALIZED,
diff --git a/media/filters/chunk_demuxer_unittest.cc b/media/filters/chunk_demuxer_unittest.cc index 4ad6e7e..09163dc 100644 --- a/media/filters/chunk_demuxer_unittest.cc +++ b/media/filters/chunk_demuxer_unittest.cc
@@ -2007,6 +2007,11 @@ ASSERT_TRUE(ParseWebMFile("bear-320x240-live.webm", buffer_timestamps, kInfiniteDuration())); + + DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO); + EXPECT_EQ(DemuxerStream::LIVENESS_LIVE, audio->liveness()); + DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO); + EXPECT_EQ(DemuxerStream::LIVENESS_LIVE, video->liveness()); } TEST_F(ChunkDemuxerTest, WebMFile_AudioOnly) {
diff --git a/media/filters/gpu_video_accelerator_factories.h b/media/filters/gpu_video_accelerator_factories.h index 6ed04c7..497e0cc 100644 --- a/media/filters/gpu_video_accelerator_factories.h +++ b/media/filters/gpu_video_accelerator_factories.h
@@ -66,9 +66,8 @@ const gfx::Rect& visible_rect, const SkBitmap& pixels) = 0; - // Allocate & return a shared memory segment. Caller is responsible for - // Close()ing the returned pointer. - virtual base::SharedMemory* CreateSharedMemory(size_t size) = 0; + // Allocate & return a shared memory segment. + virtual scoped_ptr<base::SharedMemory> CreateSharedMemory(size_t size) = 0; // Returns the task runner the video accelerator runs on. virtual scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner() = 0;
diff --git a/media/filters/gpu_video_decoder.cc b/media/filters/gpu_video_decoder.cc index aea4816..45adef7 100644 --- a/media/filters/gpu_video_decoder.cc +++ b/media/filters/gpu_video_decoder.cc
@@ -38,8 +38,9 @@ // be on the beefy side. static const size_t kSharedMemorySegmentBytes = 100 << 10; -GpuVideoDecoder::SHMBuffer::SHMBuffer(base::SharedMemory* m, size_t s) - : shm(m), size(s) { +GpuVideoDecoder::SHMBuffer::SHMBuffer(scoped_ptr<base::SharedMemory> m, + size_t s) + : shm(m.Pass()), size(s) { } GpuVideoDecoder::SHMBuffer::~SHMBuffer() {} @@ -253,7 +254,7 @@ } size_t size = buffer->data_size(); - SHMBuffer* shm_buffer = GetSHM(size); + scoped_ptr<SHMBuffer> shm_buffer = GetSHM(size); if (!shm_buffer) { bound_decode_cb.Run(kDecodeError); return; @@ -265,9 +266,9 @@ // Mask against 30 bits, to avoid (undefined) wraparound on signed integer. next_bitstream_buffer_id_ = (next_bitstream_buffer_id_ + 1) & 0x3FFFFFFF; DCHECK(!ContainsKey(bitstream_buffers_in_decoder_, bitstream_buffer.id())); - bitstream_buffers_in_decoder_.insert( - std::make_pair(bitstream_buffer.id(), - PendingDecoderBuffer(shm_buffer, buffer, decode_cb))); + bitstream_buffers_in_decoder_.insert(std::make_pair( + bitstream_buffer.id(), + PendingDecoderBuffer(shm_buffer.release(), buffer, decode_cb))); DCHECK_LE(static_cast<int>(bitstream_buffers_in_decoder_.size()), kMaxInFlightDecodes); RecordBufferData(bitstream_buffer, *buffer.get()); @@ -531,25 +532,27 @@ vda_->ReusePictureBuffer(picture_buffer_id); } -GpuVideoDecoder::SHMBuffer* GpuVideoDecoder::GetSHM(size_t min_size) { +scoped_ptr<GpuVideoDecoder::SHMBuffer> GpuVideoDecoder::GetSHM( + size_t min_size) { DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); if (available_shm_segments_.empty() || available_shm_segments_.back()->size < min_size) { size_t size_to_allocate = std::max(min_size, kSharedMemorySegmentBytes); - base::SharedMemory* shm = factories_->CreateSharedMemory(size_to_allocate); + scoped_ptr<base::SharedMemory> shm = + factories_->CreateSharedMemory(size_to_allocate); // CreateSharedMemory() can return NULL during Shutdown. if (!shm) return NULL; - return new SHMBuffer(shm, size_to_allocate); + return make_scoped_ptr(new SHMBuffer(shm.Pass(), size_to_allocate)); } - SHMBuffer* ret = available_shm_segments_.back(); + scoped_ptr<SHMBuffer> ret(available_shm_segments_.back()); available_shm_segments_.pop_back(); - return ret; + return ret.Pass(); } -void GpuVideoDecoder::PutSHM(SHMBuffer* shm_buffer) { +void GpuVideoDecoder::PutSHM(scoped_ptr<SHMBuffer> shm_buffer) { DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent(); - available_shm_segments_.push_back(shm_buffer); + available_shm_segments_.push_back(shm_buffer.release()); } void GpuVideoDecoder::NotifyEndOfBitstreamBuffer(int32 id) { @@ -564,7 +567,7 @@ return; } - PutSHM(it->second.shm_buffer); + PutSHM(make_scoped_ptr(it->second.shm_buffer)); it->second.done_cb.Run(state_ == kError ? kDecodeError : kOk); bitstream_buffers_in_decoder_.erase(it); } @@ -578,7 +581,6 @@ DCHECK(assigned_picture_buffers_.empty()); for (size_t i = 0; i < available_shm_segments_.size(); ++i) { - available_shm_segments_[i]->shm->Close(); delete available_shm_segments_[i]; } available_shm_segments_.clear(); @@ -586,7 +588,7 @@ for (std::map<int32, PendingDecoderBuffer>::iterator it = bitstream_buffers_in_decoder_.begin(); it != bitstream_buffers_in_decoder_.end(); ++it) { - it->second.shm_buffer->shm->Close(); + delete it->second.shm_buffer; it->second.done_cb.Run(kAborted); } bitstream_buffers_in_decoder_.clear();
diff --git a/media/filters/gpu_video_decoder.h b/media/filters/gpu_video_decoder.h index 65c85d5d..a4157b19 100644 --- a/media/filters/gpu_video_decoder.h +++ b/media/filters/gpu_video_decoder.h
@@ -79,9 +79,9 @@ // A shared memory segment and its allocated size. struct SHMBuffer { - SHMBuffer(base::SharedMemory* m, size_t s); + SHMBuffer(scoped_ptr<base::SharedMemory> m, size_t s); ~SHMBuffer(); - base::SharedMemory* shm; + scoped_ptr<base::SharedMemory> shm; size_t size; }; @@ -118,11 +118,11 @@ void DestroyVDA(); // Request a shared-memory segment of at least |min_size| bytes. Will - // allocate as necessary. Caller does not own returned pointer. - SHMBuffer* GetSHM(size_t min_size); + // allocate as necessary. + scoped_ptr<SHMBuffer> GetSHM(size_t min_size); // Return a shared-memory segment to the available pool. - void PutSHM(SHMBuffer* shm_buffer); + void PutSHM(scoped_ptr<SHMBuffer> shm_buffer); // Destroy all PictureBuffers in |buffers|, and delete their textures. void DestroyPictureBuffers(PictureBufferMap* buffers);
diff --git a/media/filters/mock_gpu_video_accelerator_factories.cc b/media/filters/mock_gpu_video_accelerator_factories.cc index eeb3ba6d..1c4465a 100644 --- a/media/filters/mock_gpu_video_accelerator_factories.cc +++ b/media/filters/mock_gpu_video_accelerator_factories.cc
@@ -10,6 +10,11 @@ MockGpuVideoAcceleratorFactories::~MockGpuVideoAcceleratorFactories() {} +scoped_ptr<base::SharedMemory> +MockGpuVideoAcceleratorFactories::CreateSharedMemory(size_t size) { + return nullptr; +} + scoped_ptr<VideoDecodeAccelerator> MockGpuVideoAcceleratorFactories::CreateVideoDecodeAccelerator() { return scoped_ptr<VideoDecodeAccelerator>(DoCreateVideoDecodeAccelerator());
diff --git a/media/filters/mock_gpu_video_accelerator_factories.h b/media/filters/mock_gpu_video_accelerator_factories.h index 949f35d..c06c6c4c 100644 --- a/media/filters/mock_gpu_video_accelerator_factories.h +++ b/media/filters/mock_gpu_video_accelerator_factories.h
@@ -43,11 +43,12 @@ void(uint32 texture_id, const gfx::Rect& visible_rect, const SkBitmap& pixels)); - MOCK_METHOD1(CreateSharedMemory, base::SharedMemory*(size_t size)); MOCK_METHOD0(GetTaskRunner, scoped_refptr<base::SingleThreadTaskRunner>()); MOCK_METHOD0(GetVideoEncodeAcceleratorSupportedProfiles, std::vector<VideoEncodeAccelerator::SupportedProfile>()); + scoped_ptr<base::SharedMemory> CreateSharedMemory(size_t size) override; + virtual scoped_ptr<VideoDecodeAccelerator> CreateVideoDecodeAccelerator() override;
diff --git a/media/filters/pipeline_integration_perftest.cc b/media/filters/pipeline_integration_perftest.cc index d84bd13..eac3be883d 100644 --- a/media/filters/pipeline_integration_perftest.cc +++ b/media/filters/pipeline_integration_perftest.cc
@@ -20,9 +20,9 @@ for (int i = 0; i < iterations; ++i) { PipelineIntegrationTestBase pipeline; - ASSERT_TRUE(pipeline.Start(GetTestDataFilePath(filename), - PIPELINE_OK, - PipelineIntegrationTestBase::kClockless)); + ASSERT_EQ( + PIPELINE_OK, + pipeline.Start(filename, PipelineIntegrationTestBase::kClockless)); base::TimeTicks start = base::TimeTicks::HighResNow(); pipeline.Play();
diff --git a/media/filters/pipeline_integration_test.cc b/media/filters/pipeline_integration_test.cc index a568221..dffc5da 100644 --- a/media/filters/pipeline_integration_test.cc +++ b/media/filters/pipeline_integration_test.cc
@@ -404,8 +404,7 @@ MockMediaSource(const std::string& filename, const std::string& mimetype, int initial_append_size) - : file_path_(GetTestDataFilePath(filename)), - current_position_(0), + : current_position_(0), initial_append_size_(initial_append_size), mimetype_(mimetype), chunk_demuxer_(new ChunkDemuxer( @@ -416,7 +415,6 @@ scoped_refptr<MediaLog>(new MediaLog()), true)), owned_chunk_demuxer_(chunk_demuxer_) { - file_data_ = ReadTestDataFile(filename); if (initial_append_size_ == kAppendWholeFile) @@ -551,7 +549,6 @@ MOCK_METHOD0(InitSegmentReceived, void(void)); private: - base::FilePath file_path_; scoped_refptr<DecoderBuffer> file_data_; int current_position_; int initial_append_size_; @@ -578,7 +575,8 @@ demuxer_.get(), CreateRenderer(), base::Bind(&PipelineIntegrationTest::OnEnded, base::Unretained(this)), base::Bind(&PipelineIntegrationTest::OnError, base::Unretained(this)), - QuitOnStatusCB(PIPELINE_OK), + base::Bind(&PipelineIntegrationTest::OnStatusCallback, + base::Unretained(this)), base::Bind(&PipelineIntegrationTest::OnMetadata, base::Unretained(this)), base::Bind(&PipelineIntegrationTest::OnBufferingStateChanged, @@ -588,6 +586,7 @@ base::Closure(), base::Bind(&PipelineIntegrationTest::OnAddTextTrack, base::Unretained(this))); message_loop_.Run(); + EXPECT_EQ(PIPELINE_OK, pipeline_status_); } void StartHashedPipelineWithMediaSource(MockMediaSource* source) { @@ -616,7 +615,8 @@ demuxer_.get(), CreateRenderer(), base::Bind(&PipelineIntegrationTest::OnEnded, base::Unretained(this)), base::Bind(&PipelineIntegrationTest::OnError, base::Unretained(this)), - QuitOnStatusCB(PIPELINE_OK), + base::Bind(&PipelineIntegrationTest::OnStatusCallback, + base::Unretained(this)), base::Bind(&PipelineIntegrationTest::OnMetadata, base::Unretained(this)), base::Bind(&PipelineIntegrationTest::OnBufferingStateChanged, @@ -630,6 +630,7 @@ base::Unretained(encrypted_media))); message_loop_.Run(); + EXPECT_EQ(PIPELINE_OK, pipeline_status_); } // Verifies that seeking works properly for ChunkDemuxer when the @@ -665,7 +666,7 @@ }; TEST_F(PipelineIntegrationTest, BasicPlayback) { - ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240.webm"), PIPELINE_OK)); + ASSERT_EQ(PIPELINE_OK, Start("bear-320x240.webm")); Play(); @@ -673,7 +674,7 @@ } TEST_F(PipelineIntegrationTest, BasicPlaybackOpusOgg) { - ASSERT_TRUE(Start(GetTestDataFilePath("bear-opus.ogg"), PIPELINE_OK)); + ASSERT_EQ(PIPELINE_OK, Start("bear-opus.ogg")); Play(); @@ -681,8 +682,7 @@ } TEST_F(PipelineIntegrationTest, BasicPlaybackHashed) { - ASSERT_TRUE(Start( - GetTestDataFilePath("bear-320x240.webm"), PIPELINE_OK, kHashed)); + ASSERT_EQ(PIPELINE_OK, Start("bear-320x240.webm", kHashed)); Play(); @@ -694,8 +694,7 @@ } TEST_F(PipelineIntegrationTest, BasicPlaybackLive) { - ASSERT_TRUE(Start( - GetTestDataFilePath("bear-320x240-live.webm"), PIPELINE_OK, kHashed)); + ASSERT_EQ(PIPELINE_OK, Start("bear-320x240-live.webm", kHashed)); Play(); @@ -711,8 +710,7 @@ } TEST_F(PipelineIntegrationTest, F32PlaybackHashed) { - ASSERT_TRUE( - Start(GetTestDataFilePath("sfx_f32le.wav"), PIPELINE_OK, kHashed)); + ASSERT_EQ(PIPELINE_OK, Start("sfx_f32le.wav", kHashed)); Play(); ASSERT_TRUE(WaitUntilOnEnded()); EXPECT_EQ(std::string(kNullVideoHash), GetVideoHash()); @@ -724,8 +722,8 @@ set_need_key_cb(base::Bind(&FakeEncryptedMedia::NeedKey, base::Unretained(&encrypted_media))); - ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240-av_enc-av.webm"), - encrypted_media.GetCdmContext())); + ASSERT_EQ(PIPELINE_OK, Start("bear-320x240-av_enc-av.webm", + encrypted_media.GetCdmContext())); Play(); @@ -1010,7 +1008,7 @@ } TEST_F(PipelineIntegrationTest, BasicPlaybackHashed_MP3) { - ASSERT_TRUE(Start(GetTestDataFilePath("sfx.mp3"), PIPELINE_OK, kHashed)); + ASSERT_EQ(PIPELINE_OK, Start("sfx.mp3", kHashed)); Play(); @@ -1217,8 +1215,7 @@ // Verify files which change configuration midstream fail gracefully. TEST_F(PipelineIntegrationTest, MidStreamConfigChangesFail) { - ASSERT_TRUE(Start( - GetTestDataFilePath("midstream_config_change.mp3"), PIPELINE_OK)); + ASSERT_EQ(PIPELINE_OK, Start("midstream_config_change.mp3")); Play(); ASSERT_EQ(WaitUntilEndedOrError(), PIPELINE_ERROR_DECODE); } @@ -1226,8 +1223,7 @@ #endif TEST_F(PipelineIntegrationTest, BasicPlayback_16x9AspectRatio) { - ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240-16x9-aspect.webm"), - PIPELINE_OK)); + ASSERT_EQ(PIPELINE_OK, Start("bear-320x240-16x9-aspect.webm")); Play(); ASSERT_TRUE(WaitUntilOnEnded()); } @@ -1397,9 +1393,8 @@ } #endif -// TODO(acolwell): Fix flakiness http://crbug.com/117921 -TEST_F(PipelineIntegrationTest, DISABLED_SeekWhilePaused) { - ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240.webm"), PIPELINE_OK)); +TEST_F(PipelineIntegrationTest, SeekWhilePaused) { + ASSERT_EQ(PIPELINE_OK, Start("bear-320x240.webm")); base::TimeDelta duration(pipeline_->GetMediaDuration()); base::TimeDelta start_seek_time(duration / 4); @@ -1409,21 +1404,20 @@ ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(start_seek_time)); Pause(); ASSERT_TRUE(Seek(seek_time)); - EXPECT_EQ(pipeline_->GetMediaTime(), seek_time); + EXPECT_EQ(seek_time, pipeline_->GetMediaTime()); Play(); ASSERT_TRUE(WaitUntilOnEnded()); // Make sure seeking after reaching the end works as expected. Pause(); ASSERT_TRUE(Seek(seek_time)); - EXPECT_EQ(pipeline_->GetMediaTime(), seek_time); + EXPECT_EQ(seek_time, pipeline_->GetMediaTime()); Play(); ASSERT_TRUE(WaitUntilOnEnded()); } -// TODO(acolwell): Fix flakiness http://crbug.com/117921 -TEST_F(PipelineIntegrationTest, DISABLED_SeekWhilePlaying) { - ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240.webm"), PIPELINE_OK)); +TEST_F(PipelineIntegrationTest, SeekWhilePlaying) { + ASSERT_EQ(PIPELINE_OK, Start("bear-320x240.webm")); base::TimeDelta duration(pipeline_->GetMediaDuration()); base::TimeDelta start_seek_time(duration / 4); @@ -1443,22 +1437,22 @@ #if defined(USE_PROPRIETARY_CODECS) TEST_F(PipelineIntegrationTest, Rotated_Metadata_0) { - ASSERT_TRUE(Start(GetTestDataFilePath("bear_rotate_0.mp4"), PIPELINE_OK)); + ASSERT_EQ(PIPELINE_OK, Start("bear_rotate_0.mp4")); ASSERT_EQ(VIDEO_ROTATION_0, metadata_.video_rotation); } TEST_F(PipelineIntegrationTest, Rotated_Metadata_90) { - ASSERT_TRUE(Start(GetTestDataFilePath("bear_rotate_90.mp4"), PIPELINE_OK)); + ASSERT_EQ(PIPELINE_OK, Start("bear_rotate_90.mp4")); ASSERT_EQ(VIDEO_ROTATION_90, metadata_.video_rotation); } TEST_F(PipelineIntegrationTest, Rotated_Metadata_180) { - ASSERT_TRUE(Start(GetTestDataFilePath("bear_rotate_180.mp4"), PIPELINE_OK)); + ASSERT_EQ(PIPELINE_OK, Start("bear_rotate_180.mp4")); ASSERT_EQ(VIDEO_ROTATION_180, metadata_.video_rotation); } TEST_F(PipelineIntegrationTest, Rotated_Metadata_270) { - ASSERT_TRUE(Start(GetTestDataFilePath("bear_rotate_270.mp4"), PIPELINE_OK)); + ASSERT_EQ(PIPELINE_OK, Start("bear_rotate_270.mp4")); ASSERT_EQ(VIDEO_ROTATION_270, metadata_.video_rotation); } #endif @@ -1483,16 +1477,14 @@ // Verify that Opus audio in WebM containers can be played back. TEST_F(PipelineIntegrationTest, BasicPlayback_AudioOnly_Opus_WebM) { - ASSERT_TRUE(Start(GetTestDataFilePath("bear-opus-end-trimming.webm"), - PIPELINE_OK)); + ASSERT_EQ(PIPELINE_OK, Start("bear-opus-end-trimming.webm")); Play(); ASSERT_TRUE(WaitUntilOnEnded()); } // Verify that VP9 video in WebM containers can be played back. TEST_F(PipelineIntegrationTest, BasicPlayback_VideoOnly_VP9_WebM) { - ASSERT_TRUE(Start(GetTestDataFilePath("bear-vp9.webm"), - PIPELINE_OK)); + ASSERT_EQ(PIPELINE_OK, Start("bear-vp9.webm")); Play(); ASSERT_TRUE(WaitUntilOnEnded()); } @@ -1500,16 +1492,14 @@ // Verify that VP9 video and Opus audio in the same WebM container can be played // back. TEST_F(PipelineIntegrationTest, BasicPlayback_VP9_Opus_WebM) { - ASSERT_TRUE(Start(GetTestDataFilePath("bear-vp9-opus.webm"), - PIPELINE_OK)); + ASSERT_EQ(PIPELINE_OK, Start("bear-vp9-opus.webm")); Play(); ASSERT_TRUE(WaitUntilOnEnded()); } // Verify that VP8 video with alpha channel can be played back. TEST_F(PipelineIntegrationTest, BasicPlayback_VP8A_WebM) { - ASSERT_TRUE(Start(GetTestDataFilePath("bear-vp8a.webm"), - PIPELINE_OK)); + ASSERT_EQ(PIPELINE_OK, Start("bear-vp8a.webm")); Play(); ASSERT_TRUE(WaitUntilOnEnded()); EXPECT_EQ(last_video_frame_format_, VideoFrame::YV12A); @@ -1517,8 +1507,7 @@ // Verify that VP8A video with odd width/height can be played back. TEST_F(PipelineIntegrationTest, BasicPlayback_VP8A_Odd_WebM) { - ASSERT_TRUE(Start(GetTestDataFilePath("bear-vp8a-odd-dimensions.webm"), - PIPELINE_OK)); + ASSERT_EQ(PIPELINE_OK, Start("bear-vp8a-odd-dimensions.webm")); Play(); ASSERT_TRUE(WaitUntilOnEnded()); EXPECT_EQ(last_video_frame_format_, VideoFrame::YV12A); @@ -1526,8 +1515,7 @@ // Verify that VP9 video with odd width/height can be played back. TEST_F(PipelineIntegrationTest, BasicPlayback_VP9_Odd_WebM) { - ASSERT_TRUE(Start(GetTestDataFilePath("bear-vp9-odd-dimensions.webm"), - PIPELINE_OK)); + ASSERT_EQ(PIPELINE_OK, Start("bear-vp9-odd-dimensions.webm")); Play(); ASSERT_TRUE(WaitUntilOnEnded()); } @@ -1535,16 +1523,14 @@ // Verify that VP8 video with inband text track can be played back. TEST_F(PipelineIntegrationTest, BasicPlayback_VP8_WebVTT_WebM) { EXPECT_CALL(*this, OnAddTextTrack(_, _)); - ASSERT_TRUE(Start(GetTestDataFilePath("bear-vp8-webvtt.webm"), - PIPELINE_OK)); + ASSERT_EQ(PIPELINE_OK, Start("bear-vp8-webvtt.webm")); Play(); ASSERT_TRUE(WaitUntilOnEnded()); } // Verify that VP9 video with 4:4:4 subsampling can be played back. TEST_F(PipelineIntegrationTest, P444_VP9_WebM) { - ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240-P444.webm"), - PIPELINE_OK)); + ASSERT_EQ(PIPELINE_OK, Start("bear-320x240-P444.webm")); Play(); ASSERT_TRUE(WaitUntilOnEnded()); EXPECT_EQ(last_video_frame_format_, VideoFrame::YV24); @@ -1552,8 +1538,7 @@ // Verify that videos with an odd frame size playback successfully. TEST_F(PipelineIntegrationTest, BasicPlayback_OddVideoSize) { - ASSERT_TRUE(Start(GetTestDataFilePath("butterfly-853x480.webm"), - PIPELINE_OK)); + ASSERT_EQ(PIPELINE_OK, Start("butterfly-853x480.webm")); Play(); ASSERT_TRUE(WaitUntilOnEnded()); } @@ -1561,7 +1546,7 @@ // Verify that OPUS audio in a webm which reports a 44.1kHz sample rate plays // correctly at 48kHz TEST_F(PipelineIntegrationTest, BasicPlayback_Opus441kHz) { - ASSERT_TRUE(Start(GetTestDataFilePath("sfx-opus-441.webm"), PIPELINE_OK)); + ASSERT_EQ(PIPELINE_OK, Start("sfx-opus-441.webm")); Play(); ASSERT_TRUE(WaitUntilOnEnded()); EXPECT_EQ(48000, @@ -1589,7 +1574,7 @@ // Ensures audio-only playback with missing or negative timestamps works. Tests // the common live-streaming case for chained ogg. See http://crbug.com/396864. TEST_F(PipelineIntegrationTest, BasicPlaybackChainedOgg) { - ASSERT_TRUE(Start(GetTestDataFilePath("double-sfx.ogg"), PIPELINE_OK)); + ASSERT_EQ(PIPELINE_OK, Start("double-sfx.ogg")); Play(); ASSERT_TRUE(WaitUntilOnEnded()); ASSERT_EQ(base::TimeDelta(), demuxer_->GetStartTime()); @@ -1598,7 +1583,7 @@ // Ensures audio-video playback with missing or negative timestamps fails softly // instead of crashing. See http://crbug.com/396864. TEST_F(PipelineIntegrationTest, BasicPlaybackChainedOggVideo) { - ASSERT_TRUE(Start(GetTestDataFilePath("double-bear.ogv"), PIPELINE_OK)); + ASSERT_EQ(PIPELINE_OK, Start("double-bear.ogv")); Play(); EXPECT_EQ(PIPELINE_ERROR_DECODE, WaitUntilEndedOrError()); ASSERT_EQ(base::TimeDelta(), demuxer_->GetStartTime()); @@ -1606,8 +1591,7 @@ // Tests that we signal ended even when audio runs longer than video track. TEST_F(PipelineIntegrationTest, BasicPlaybackAudioLongerThanVideo) { - ASSERT_TRUE(Start(GetTestDataFilePath("bear_audio_longer_than_video.ogv"), - PIPELINE_OK)); + ASSERT_EQ(PIPELINE_OK, Start("bear_audio_longer_than_video.ogv")); // Audio track is 2000ms. Video track is 1001ms. Duration should be higher // of the two. EXPECT_EQ(2000, pipeline_->GetMediaDuration().InMilliseconds()); @@ -1617,8 +1601,7 @@ // Tests that we signal ended even when audio runs shorter than video track. TEST_F(PipelineIntegrationTest, BasicPlaybackAudioShorterThanVideo) { - ASSERT_TRUE(Start(GetTestDataFilePath("bear_audio_shorter_than_video.ogv"), - PIPELINE_OK)); + ASSERT_EQ(PIPELINE_OK, Start("bear_audio_shorter_than_video.ogv")); // Audio track is 500ms. Video track is 1001ms. Duration should be higher of // the two. EXPECT_EQ(1001, pipeline_->GetMediaDuration().InMilliseconds()); @@ -1627,8 +1610,7 @@ } TEST_F(PipelineIntegrationTest, BasicPlaybackPositiveStartTime) { - ASSERT_TRUE( - Start(GetTestDataFilePath("nonzero-start-time.webm"), PIPELINE_OK)); + ASSERT_EQ(PIPELINE_OK, Start("nonzero-start-time.webm")); Play(); ASSERT_TRUE(WaitUntilOnEnded()); ASSERT_EQ(base::TimeDelta::FromMicroseconds(396000),
diff --git a/media/filters/pipeline_integration_test_base.cc b/media/filters/pipeline_integration_test_base.cc index ca8176f..779e1b5 100644 --- a/media/filters/pipeline_integration_test_base.cc +++ b/media/filters/pipeline_integration_test_base.cc
@@ -8,6 +8,7 @@ #include "base/memory/scoped_vector.h" #include "media/base/cdm_context.h" #include "media/base/media_log.h" +#include "media/base/test_data_util.h" #include "media/filters/audio_renderer_impl.h" #include "media/filters/chunk_demuxer.h" #include "media/filters/ffmpeg_audio_decoder.h" @@ -48,7 +49,9 @@ Stop(); } -void PipelineIntegrationTestBase::SaveStatus(PipelineStatus status) { +void PipelineIntegrationTestBase::OnSeeked(base::TimeDelta seek_time, + PipelineStatus status) { + EXPECT_EQ(seek_time, pipeline_->GetMediaTime()); pipeline_status_ = status; } @@ -58,20 +61,6 @@ message_loop_.PostTask(FROM_HERE, base::MessageLoop::QuitClosure()); } -void PipelineIntegrationTestBase::OnStatusCallbackChecked( - PipelineStatus expected_status, - PipelineStatus status) { - EXPECT_EQ(expected_status, status); - OnStatusCallback(status); -} - -PipelineStatusCB PipelineIntegrationTestBase::QuitOnStatusCB( - PipelineStatus expected_status) { - return base::Bind(&PipelineIntegrationTestBase::OnStatusCallbackChecked, - base::Unretained(this), - expected_status); -} - void PipelineIntegrationTestBase::DemuxerNeedKeyCB( const std::string& type, const std::vector<uint8>& init_data) { @@ -108,57 +97,26 @@ message_loop_.PostTask(FROM_HERE, base::MessageLoop::QuitClosure()); } -bool PipelineIntegrationTestBase::Start(const base::FilePath& file_path, - PipelineStatus expected_status) { +PipelineStatus PipelineIntegrationTestBase::Start(const std::string& filename) { + return Start(filename, nullptr); +} + +PipelineStatus PipelineIntegrationTestBase::Start(const std::string& filename, + CdmContext* cdm_context) { EXPECT_CALL(*this, OnMetadata(_)) .Times(AtMost(1)) .WillRepeatedly(SaveArg<0>(&metadata_)); EXPECT_CALL(*this, OnBufferingStateChanged(BUFFERING_HAVE_ENOUGH)) .Times(AtMost(1)); - CreateDemuxer(file_path); - pipeline_->Start( - demuxer_.get(), CreateRenderer(), - base::Bind(&PipelineIntegrationTestBase::OnEnded, base::Unretained(this)), - base::Bind(&PipelineIntegrationTestBase::OnError, base::Unretained(this)), - QuitOnStatusCB(expected_status), - base::Bind(&PipelineIntegrationTestBase::OnMetadata, - base::Unretained(this)), - base::Bind(&PipelineIntegrationTestBase::OnBufferingStateChanged, - base::Unretained(this)), - base::Bind(&PipelineIntegrationTestBase::OnVideoFramePaint, - base::Unretained(this)), - base::Closure(), base::Bind(&PipelineIntegrationTestBase::OnAddTextTrack, - base::Unretained(this))); - message_loop_.Run(); - return (pipeline_status_ == PIPELINE_OK); -} + CreateDemuxer(filename); -bool PipelineIntegrationTestBase::Start(const base::FilePath& file_path, - PipelineStatus expected_status, - kTestType test_type) { - hashing_enabled_ = test_type == kHashed; - clockless_playback_ = test_type == kClockless; - return Start(file_path, expected_status); -} + if (cdm_context) { + EXPECT_CALL(*this, DecryptorAttached(true)); + pipeline_->SetCdm( + cdm_context, base::Bind(&PipelineIntegrationTestBase::DecryptorAttached, + base::Unretained(this))); + } -bool PipelineIntegrationTestBase::Start(const base::FilePath& file_path) { - return Start(file_path, NULL); -} - -bool PipelineIntegrationTestBase::Start(const base::FilePath& file_path, - CdmContext* cdm_context) { - EXPECT_CALL(*this, OnMetadata(_)) - .Times(AtMost(1)) - .WillRepeatedly(SaveArg<0>(&metadata_)); - EXPECT_CALL(*this, OnBufferingStateChanged(BUFFERING_HAVE_ENOUGH)) - .Times(AtMost(1)); - EXPECT_CALL(*this, DecryptorAttached(true)); - - CreateDemuxer(file_path); - - pipeline_->SetCdm(cdm_context, - base::Bind(&PipelineIntegrationTestBase::DecryptorAttached, - base::Unretained(this))); pipeline_->Start( demuxer_.get(), CreateRenderer(), base::Bind(&PipelineIntegrationTestBase::OnEnded, base::Unretained(this)), @@ -174,7 +132,14 @@ base::Closure(), base::Bind(&PipelineIntegrationTestBase::OnAddTextTrack, base::Unretained(this))); message_loop_.Run(); - return (pipeline_status_ == PIPELINE_OK); + return pipeline_status_; +} + +PipelineStatus PipelineIntegrationTestBase::Start(const std::string& filename, + kTestType test_type) { + hashing_enabled_ = test_type == kHashed; + clockless_playback_ = test_type == kClockless; + return Start(filename); } void PipelineIntegrationTestBase::Play() { @@ -190,9 +155,8 @@ EXPECT_CALL(*this, OnBufferingStateChanged(BUFFERING_HAVE_ENOUGH)) .WillOnce(InvokeWithoutArgs(&message_loop_, &base::MessageLoop::QuitNow)); - pipeline_->Seek(seek_time, - base::Bind(&PipelineIntegrationTestBase::SaveStatus, - base::Unretained(this))); + pipeline_->Seek(seek_time, base::Bind(&PipelineIntegrationTestBase::OnSeeked, + base::Unretained(this), seek_time)); message_loop_.Run(); return (pipeline_status_ == PIPELINE_OK); } @@ -234,9 +198,9 @@ return (pipeline_status_ == PIPELINE_OK); } -void PipelineIntegrationTestBase::CreateDemuxer( - const base::FilePath& file_path) { +void PipelineIntegrationTestBase::CreateDemuxer(const std::string& filename) { FileDataSource* file_data_source = new FileDataSource(); + base::FilePath file_path(GetTestDataFilePath(filename)); CHECK(file_data_source->Initialize(file_path)) << "Is " << file_path.value() << " missing?"; data_source_.reset(file_data_source);
diff --git a/media/filters/pipeline_integration_test_base.h b/media/filters/pipeline_integration_test_base.h index d05a9ed8..c98d82cc 100644 --- a/media/filters/pipeline_integration_test_base.h +++ b/media/filters/pipeline_integration_test_base.h
@@ -61,18 +61,18 @@ bool WaitUntilOnEnded(); PipelineStatus WaitUntilEndedOrError(); - bool Start(const base::FilePath& file_path, PipelineStatus expected_status); - // Enable playback with audio and video hashing enabled, or clockless - // playback (audio only). Frame dropping and audio underflow will be disabled - // if hashing enabled to ensure consistent hashes. + + // Starts the pipeline (optionally with a CdmContext), returning the final + // status code after it has started. |filename| points at a test file located + // under media/test/data/. + PipelineStatus Start(const std::string& filename); + PipelineStatus Start(const std::string& filename, CdmContext* cdm_context); + + // Starts the pipeline in a particular mode for advanced testing and + // benchmarking purposes (e.g., underflow is disabled to ensure consistent + // hashes). enum kTestType { kHashed, kClockless }; - bool Start(const base::FilePath& file_path, - PipelineStatus expected_status, - kTestType test_type); - // Initialize the pipeline and ignore any status updates. Useful for testing - // invalid audio/video clips which don't have deterministic results. - bool Start(const base::FilePath& file_path); - bool Start(const base::FilePath& file_path, CdmContext* cdm_context); + PipelineStatus Start(const std::string& filename, kTestType test_type); void Play(); void Pause(); @@ -113,11 +113,8 @@ AudioHardwareConfig hardware_config_; PipelineMetadata metadata_; - void SaveStatus(PipelineStatus status); - void OnStatusCallbackChecked(PipelineStatus expected_status, - PipelineStatus status); + void OnSeeked(base::TimeDelta seek_time, PipelineStatus status); void OnStatusCallback(PipelineStatus status); - PipelineStatusCB QuitOnStatusCB(PipelineStatus expected_status); void DemuxerNeedKeyCB(const std::string& type, const std::vector<uint8>& init_data); void set_need_key_cb(const Demuxer::NeedKeyCB& need_key_cb) { @@ -129,7 +126,7 @@ void QuitAfterCurrentTimeTask(const base::TimeDelta& quit_time); // Creates Demuxer and sets |demuxer_|. - void CreateDemuxer(const base::FilePath& file_path); + void CreateDemuxer(const std::string& filename); // Creates and returns a Renderer. scoped_ptr<Renderer> CreateRenderer();
diff --git a/media/filters/source_buffer_platform_lowmem.cc b/media/filters/source_buffer_platform_lowmem.cc new file mode 100644 index 0000000..79757cd --- /dev/null +++ b/media/filters/source_buffer_platform_lowmem.cc
@@ -0,0 +1,14 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/filters/source_buffer_platform.h" + +namespace media { + +// 2MB: approximately 1 minute of 256Kbps content. +// 30MB: approximately 1 minute of 4Mbps content. +const int kSourceBufferAudioMemoryLimit = 2 * 1024 * 1024; +const int kSourceBufferVideoMemoryLimit = 30 * 1024 * 1024; + +} // namespace media
diff --git a/media/media.gyp b/media/media.gyp index e73d51a1..49bdb7f 100644 --- a/media/media.gyp +++ b/media/media.gyp
@@ -40,6 +40,12 @@ }, { 'pkg-config': 'pkg-config' }], + # low memory buffer is used in non-Android based chromecast build due to hardware limitation. + ['chromecast==1 and OS!="android"', { + 'use_low_memory_buffer%': 1, + }, { + 'use_low_memory_buffer%': 0, + }], ], }, 'includes': [ @@ -448,8 +454,6 @@ 'filters/renderer_impl.h', 'filters/skcanvas_video_renderer.cc', 'filters/skcanvas_video_renderer.h', - 'filters/source_buffer_platform.cc', - 'filters/source_buffer_platform.h', 'filters/source_buffer_range.cc', 'filters/source_buffer_range.h', 'filters/source_buffer_stream.cc', @@ -1029,6 +1033,17 @@ 'base/keyboard_event_counter.h', ], }], + ['use_low_memory_buffer==1', { + 'sources': [ + 'filters/source_buffer_platform_lowmem.cc', + 'filters/source_buffer_platform.h', + ] + }, { # 'use_low_memory_buffer==0' + 'sources': [ + 'filters/source_buffer_platform.cc', + 'filters/source_buffer_platform.h', + ] + }], ], # conditions 'target_conditions': [ ['OS == "ios" and _toolset != "host"', {
diff --git a/media/mojo/services/media_renderer_apptest.cc b/media/mojo/services/media_renderer_apptest.cc index bdf5048..8813b38 100644 --- a/media/mojo/services/media_renderer_apptest.cc +++ b/media/mojo/services/media_renderer_apptest.cc
@@ -99,8 +99,7 @@ class MojoRendererTest : public mojo::test::ApplicationTestBase { public: MojoRendererTest() - : ApplicationTestBase(mojo::Array<mojo::String>()), - service_provider_(NULL) {} + : service_provider_(NULL) {} ~MojoRendererTest() override {} protected:
diff --git a/media/video/capture/file_video_capture_device.cc b/media/video/capture/file_video_capture_device.cc index 47330973..24673aa 100644 --- a/media/video/capture/file_video_capture_device.cc +++ b/media/video/capture/file_video_capture_device.cc
@@ -239,10 +239,14 @@ 0, base::TimeTicks::Now()); // Reschedule next CaptureTask. - const base::TimeDelta next_on_capture_timedelta = - base::TimeDelta::FromMicroseconds(1E6 / capture_format_.frame_rate) - + const base::TimeDelta frame_interval = + base::TimeDelta::FromMicroseconds(1E6 / capture_format_.frame_rate); + base::TimeDelta next_on_capture_timedelta = frame_interval - (base::TimeTicks::Now() - timestamp_before_reading); - + if (next_on_capture_timedelta.InMilliseconds() < 0) { + DLOG(WARNING) << "Frame reading took longer than the frame interval."; + next_on_capture_timedelta = frame_interval; + } base::MessageLoop::current()->PostDelayedTask( FROM_HERE, base::Bind(&FileVideoCaptureDevice::OnCaptureTask,
diff --git a/mojo/cc/output_surface_mojo.cc b/mojo/cc/output_surface_mojo.cc index 193c7ac..e7a8def4 100644 --- a/mojo/cc/output_surface_mojo.cc +++ b/mojo/cc/output_surface_mojo.cc
@@ -49,7 +49,8 @@ surface_size_ = frame_size; } - surface_->SubmitFrame(SurfaceId::From(surface_id_), Frame::From(*frame)); + surface_->SubmitFrame(SurfaceId::From(surface_id_), Frame::From(*frame), + mojo::Closure()); client_->DidSwapBuffers(); client_->DidSwapBuffersComplete();
diff --git a/mojo/edk/embedder/embedder_unittest.cc b/mojo/edk/embedder/embedder_unittest.cc index 16a5ce2..b138a2d 100644 --- a/mojo/edk/embedder/embedder_unittest.cc +++ b/mojo/edk/embedder/embedder_unittest.cc
@@ -282,7 +282,13 @@ // 10. (close) // 11. (wait/cl.) // 12. (wait/cl.) -TEST_F(EmbedderTest, MultiprocessChannels) { +#if defined(OS_ANDROID) +// Android multi-process tests are not executing the new process. This is flaky. +#define MAYBE_MultiprocessChannels DISABLED_MultiprocessChannels +#else +#define MAYBE_MultiprocessChannels MultiprocessChannels +#endif // defined(OS_ANDROID) +TEST_F(EmbedderTest, MAYBE_MultiprocessChannels) { mojo::embedder::test::InitWithSimplePlatformSupport(); mojo::test::MultiprocessTestHelper multiprocess_test_helper; multiprocess_test_helper.StartChild("MultiprocessChannelsClient");
diff --git a/mojo/edk/js/core.cc b/mojo/edk/js/core.cc index 232f0e3..e70931d 100644 --- a/mojo/edk/js/core.cc +++ b/mojo/edk/js/core.cc
@@ -288,6 +288,8 @@ .SetValue("HANDLE_SIGNAL_NONE", MOJO_HANDLE_SIGNAL_NONE) .SetValue("HANDLE_SIGNAL_READABLE", MOJO_HANDLE_SIGNAL_READABLE) .SetValue("HANDLE_SIGNAL_WRITABLE", MOJO_HANDLE_SIGNAL_WRITABLE) + .SetValue("HANDLE_SIGNAL_PEER_CLOSED", + MOJO_HANDLE_SIGNAL_PEER_CLOSED) .SetValue("CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE", MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE)
diff --git a/mojo/edk/mojo_edk.gyp b/mojo/edk/mojo_edk.gyp index 0959aac8..b85cae7 100644 --- a/mojo/edk/mojo_edk.gyp +++ b/mojo/edk/mojo_edk.gyp
@@ -15,115 +15,9 @@ '../../base/base.gyp:base', '../../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', ], - 'defines': [ - 'MOJO_SYSTEM_IMPL_IMPLEMENTATION', - 'MOJO_SYSTEM_IMPLEMENTATION', - 'MOJO_USE_SYSTEM_IMPL', + 'includes': [ + 'mojo_edk_system_impl.gypi', ], - 'sources': [ - 'embedder/configuration.h', - 'embedder/channel_info_forward.h', - 'embedder/channel_init.cc', - 'embedder/channel_init.h', - 'embedder/embedder.cc', - 'embedder/embedder.h', - 'embedder/embedder_internal.h', - 'embedder/entrypoints.cc', - 'embedder/platform_channel_pair.cc', - 'embedder/platform_channel_pair.h', - 'embedder/platform_channel_pair_posix.cc', - 'embedder/platform_channel_pair_win.cc', - 'embedder/platform_channel_utils_posix.cc', - 'embedder/platform_channel_utils_posix.h', - 'embedder/platform_handle.cc', - 'embedder/platform_handle.h', - 'embedder/platform_handle_utils.h', - 'embedder/platform_handle_utils_posix.cc', - 'embedder/platform_handle_utils_win.cc', - 'embedder/platform_handle_vector.h', - 'embedder/platform_shared_buffer.h', - 'embedder/platform_support.h', - 'embedder/scoped_platform_handle.h', - 'embedder/simple_platform_shared_buffer.cc', - 'embedder/simple_platform_shared_buffer.h', - 'embedder/simple_platform_shared_buffer_posix.cc', - 'embedder/simple_platform_shared_buffer_win.cc', - 'embedder/simple_platform_support.cc', - 'embedder/simple_platform_support.h', - 'system/channel.cc', - 'system/channel.h', - 'system/channel_endpoint.cc', - 'system/channel_endpoint.h', - 'system/channel_endpoint_client.h', - 'system/channel_endpoint_id.cc', - 'system/channel_endpoint_id.h', - 'system/channel_info.cc', - 'system/channel_info.h', - 'system/channel_manager.cc', - 'system/channel_manager.h', - 'system/configuration.cc', - 'system/configuration.h', - 'system/core.cc', - 'system/core.h', - 'system/data_pipe.cc', - 'system/data_pipe.h', - 'system/data_pipe_consumer_dispatcher.cc', - 'system/data_pipe_consumer_dispatcher.h', - 'system/data_pipe_producer_dispatcher.cc', - 'system/data_pipe_producer_dispatcher.h', - 'system/dispatcher.cc', - 'system/dispatcher.h', - 'system/handle_signals_state.h', - 'system/handle_table.cc', - 'system/handle_table.h', - 'system/local_data_pipe.cc', - 'system/local_data_pipe.h', - 'system/local_message_pipe_endpoint.cc', - 'system/local_message_pipe_endpoint.h', - 'system/mapping_table.cc', - 'system/mapping_table.h', - 'system/memory.cc', - 'system/memory.h', - 'system/message_in_transit.cc', - 'system/message_in_transit.h', - 'system/message_in_transit_queue.cc', - 'system/message_in_transit_queue.h', - 'system/message_pipe.cc', - 'system/message_pipe.h', - 'system/message_pipe_dispatcher.cc', - 'system/message_pipe_dispatcher.h', - 'system/message_pipe_endpoint.cc', - 'system/message_pipe_endpoint.h', - 'system/options_validation.h', - 'system/platform_handle_dispatcher.cc', - 'system/platform_handle_dispatcher.h', - 'system/proxy_message_pipe_endpoint.cc', - 'system/proxy_message_pipe_endpoint.h', - 'system/raw_channel.cc', - 'system/raw_channel.h', - 'system/raw_channel_posix.cc', - 'system/raw_channel_win.cc', - 'system/shared_buffer_dispatcher.cc', - 'system/shared_buffer_dispatcher.h', - 'system/simple_dispatcher.cc', - 'system/simple_dispatcher.h', - 'system/transport_data.cc', - 'system/transport_data.h', - 'system/waiter.cc', - 'system/waiter.h', - 'system/waiter_list.cc', - 'system/waiter_list.h', - # Test-only code: - # TODO(vtl): It's a little unfortunate that these end up in the same - # component as non-test-only code. In the static build, this code should - # hopefully be dead-stripped. - 'embedder/test_embedder.cc', - 'embedder/test_embedder.h', - ], - 'all_dependent_settings': { - # Ensures that dependent projects import the core functions on Windows. - 'defines': ['MOJO_USE_SYSTEM_IMPL'], - } }, { # GN version: //mojo/edk/js @@ -225,4 +119,26 @@ ], }, ], + 'conditions': [ + ['OS=="win" and target_arch=="ia32"', { + 'targets': [ + { + 'target_name': 'mojo_system_impl_win64', + 'type': '<(component)', + 'dependencies': [ + '../../base/base.gyp:base_win64', + '../../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations_win64', + ], + 'includes': [ + 'mojo_edk_system_impl.gypi', + ], + 'configurations': { + 'Common_Base': { + 'msvs_target_platform': 'x64', + }, + }, + }, + ], + }], + ], }
diff --git a/mojo/edk/mojo_edk_system_impl.gypi b/mojo/edk/mojo_edk_system_impl.gypi new file mode 100644 index 0000000..a0af387 --- /dev/null +++ b/mojo/edk/mojo_edk_system_impl.gypi
@@ -0,0 +1,118 @@ +# 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. + +# The dictionary here is defined for use by the "mojo_system_impl" and +# "mojo_system_impl_win64" targets in mojo/edk/mojo_edk.gyp. It's defined in +# this .gypi file so the sections aren't duplicated. +{ + 'defines': [ + 'MOJO_SYSTEM_IMPL_IMPLEMENTATION', + 'MOJO_SYSTEM_IMPLEMENTATION', + 'MOJO_USE_SYSTEM_IMPL', + ], + 'sources': [ + 'embedder/configuration.h', + 'embedder/channel_info_forward.h', + 'embedder/channel_init.cc', + 'embedder/channel_init.h', + 'embedder/embedder.cc', + 'embedder/embedder.h', + 'embedder/embedder_internal.h', + 'embedder/entrypoints.cc', + 'embedder/platform_channel_pair.cc', + 'embedder/platform_channel_pair.h', + 'embedder/platform_channel_pair_posix.cc', + 'embedder/platform_channel_pair_win.cc', + 'embedder/platform_channel_utils_posix.cc', + 'embedder/platform_channel_utils_posix.h', + 'embedder/platform_handle.cc', + 'embedder/platform_handle.h', + 'embedder/platform_handle_utils.h', + 'embedder/platform_handle_utils_posix.cc', + 'embedder/platform_handle_utils_win.cc', + 'embedder/platform_handle_vector.h', + 'embedder/platform_shared_buffer.h', + 'embedder/platform_support.h', + 'embedder/scoped_platform_handle.h', + 'embedder/simple_platform_shared_buffer.cc', + 'embedder/simple_platform_shared_buffer.h', + 'embedder/simple_platform_shared_buffer_posix.cc', + 'embedder/simple_platform_shared_buffer_win.cc', + 'embedder/simple_platform_support.cc', + 'embedder/simple_platform_support.h', + 'system/channel.cc', + 'system/channel.h', + 'system/channel_endpoint.cc', + 'system/channel_endpoint.h', + 'system/channel_endpoint_client.h', + 'system/channel_endpoint_id.cc', + 'system/channel_endpoint_id.h', + 'system/channel_info.cc', + 'system/channel_info.h', + 'system/channel_manager.cc', + 'system/channel_manager.h', + 'system/configuration.cc', + 'system/configuration.h', + 'system/core.cc', + 'system/core.h', + 'system/data_pipe.cc', + 'system/data_pipe.h', + 'system/data_pipe_consumer_dispatcher.cc', + 'system/data_pipe_consumer_dispatcher.h', + 'system/data_pipe_producer_dispatcher.cc', + 'system/data_pipe_producer_dispatcher.h', + 'system/dispatcher.cc', + 'system/dispatcher.h', + 'system/handle_signals_state.h', + 'system/handle_table.cc', + 'system/handle_table.h', + 'system/local_data_pipe.cc', + 'system/local_data_pipe.h', + 'system/local_message_pipe_endpoint.cc', + 'system/local_message_pipe_endpoint.h', + 'system/mapping_table.cc', + 'system/mapping_table.h', + 'system/memory.cc', + 'system/memory.h', + 'system/message_in_transit.cc', + 'system/message_in_transit.h', + 'system/message_in_transit_queue.cc', + 'system/message_in_transit_queue.h', + 'system/message_pipe.cc', + 'system/message_pipe.h', + 'system/message_pipe_dispatcher.cc', + 'system/message_pipe_dispatcher.h', + 'system/message_pipe_endpoint.cc', + 'system/message_pipe_endpoint.h', + 'system/options_validation.h', + 'system/platform_handle_dispatcher.cc', + 'system/platform_handle_dispatcher.h', + 'system/proxy_message_pipe_endpoint.cc', + 'system/proxy_message_pipe_endpoint.h', + 'system/raw_channel.cc', + 'system/raw_channel.h', + 'system/raw_channel_posix.cc', + 'system/raw_channel_win.cc', + 'system/shared_buffer_dispatcher.cc', + 'system/shared_buffer_dispatcher.h', + 'system/simple_dispatcher.cc', + 'system/simple_dispatcher.h', + 'system/transport_data.cc', + 'system/transport_data.h', + 'system/waiter.cc', + 'system/waiter.h', + 'system/waiter_list.cc', + 'system/waiter_list.h', + # Test-only code: + # TODO(vtl): It's a little unfortunate that these end up in the same + # component as non-test-only code. In the static build, this code + # should hopefully be dead-stripped. + 'embedder/test_embedder.cc', + 'embedder/test_embedder.h', + ], + 'all_dependent_settings': { + # Ensures that dependent projects import the core functions on Windows. + 'defines': ['MOJO_USE_SYSTEM_IMPL'], + }, +}
diff --git a/mojo/edk/system/BUILD.gn b/mojo/edk/system/BUILD.gn index b87c76ad..0701484b 100644 --- a/mojo/edk/system/BUILD.gn +++ b/mojo/edk/system/BUILD.gn
@@ -2,6 +2,11 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +if (is_android) { + import("//build/config/android/config.gni") + import("//build/config/android/rules.gni") +} + config("system_config") { defines = [ # Ensures that dependent projects import the core functions on Windows. @@ -143,6 +148,12 @@ "//testing/gtest", ] + if (is_android) { + deps += [ + "//testing/android:native_test_native_code", + ] + } + allow_circular_includes_from = [ "//mojo/edk/embedder:embedder_unittests" ] } @@ -165,3 +176,12 @@ "//testing/gtest", ] } + +if (is_android) { + unittest_apk("mojo_system_unittests_apk") { + deps = [ + ":mojo_system_unittests", + ] + unittests_dep = ":mojo_system_unittests" + } +}
diff --git a/mojo/edk/system/channel.cc b/mojo/edk/system/channel.cc index 50d4b65..3d6c54f 100644 --- a/mojo/edk/system/channel.cc +++ b/mojo/edk/system/channel.cc
@@ -7,7 +7,6 @@ #include <algorithm> #include "base/bind.h" -#include "base/compiler_specific.h" #include "base/logging.h" #include "base/macros.h" #include "base/strings/stringprintf.h" @@ -237,9 +236,8 @@ DCHECK(creation_thread_checker_.CalledOnValidThread()); switch (message_view.type()) { - case MessageInTransit::kTypeMessagePipeEndpoint: - case MessageInTransit::kTypeMessagePipe: - OnReadMessageForDownstream(message_view, platform_handles.Pass()); + case MessageInTransit::kTypeEndpoint: + OnReadMessageForEndpoint(message_view, platform_handles.Pass()); break; case MessageInTransit::kTypeChannel: OnReadMessageForChannel(message_view, platform_handles.Pass()); @@ -283,12 +281,11 @@ Shutdown(); } -void Channel::OnReadMessageForDownstream( +void Channel::OnReadMessageForEndpoint( const MessageInTransit::View& message_view, embedder::ScopedPlatformHandleVectorPtr platform_handles) { DCHECK(creation_thread_checker_.CalledOnValidThread()); - DCHECK(message_view.type() == MessageInTransit::kTypeMessagePipeEndpoint || - message_view.type() == MessageInTransit::kTypeMessagePipe); + DCHECK(message_view.type() == MessageInTransit::kTypeEndpoint); ChannelEndpointId local_id = message_view.destination_id(); if (!local_id.is_valid()) { @@ -331,12 +328,16 @@ return; } - if (!endpoint->OnReadMessage(message_view, platform_handles.Pass())) { - HandleLocalError( - base::StringPrintf("Failed to enqueue message to local ID %u", - static_cast<unsigned>(local_id.value()))); - return; + scoped_ptr<MessageInTransit> message(new MessageInTransit(message_view)); + if (message_view.transport_data_buffer_size() > 0) { + DCHECK(message_view.transport_data_buffer()); + message->SetDispatchers(TransportData::DeserializeDispatchers( + message_view.transport_data_buffer(), + message_view.transport_data_buffer_size(), platform_handles.Pass(), + this)); } + + endpoint->OnReadMessage(message.Pass()); } void Channel::OnReadMessageForChannel(
diff --git a/mojo/edk/system/channel.h b/mojo/edk/system/channel.h index e0ecc3b..227d202 100644 --- a/mojo/edk/system/channel.h +++ b/mojo/edk/system/channel.h
@@ -139,7 +139,7 @@ void OnError(Error error) override; // Helpers for |OnReadMessage| (only called on the creation thread): - void OnReadMessageForDownstream( + void OnReadMessageForEndpoint( const MessageInTransit::View& message_view, embedder::ScopedPlatformHandleVectorPtr platform_handles); void OnReadMessageForChannel(
diff --git a/mojo/edk/system/channel_endpoint.cc b/mojo/edk/system/channel_endpoint.cc index ca86b5f..a8bbbb2 100644 --- a/mojo/edk/system/channel_endpoint.cc +++ b/mojo/edk/system/channel_endpoint.cc
@@ -7,7 +7,6 @@ #include "base/logging.h" #include "mojo/edk/system/channel.h" #include "mojo/edk/system/channel_endpoint_client.h" -#include "mojo/edk/system/transport_data.h" namespace mojo { namespace system { @@ -19,7 +18,7 @@ DCHECK(client_.get() || message_queue); if (message_queue) - paused_message_queue_.Swap(message_queue); + channel_message_queue_.Swap(message_queue); } bool ChannelEndpoint::EnqueueMessage(scoped_ptr<MessageInTransit> message) { @@ -33,7 +32,7 @@ // some reason (with live message pipes on it). Ideally, we'd return false // (and not enqueue the message), but we currently don't have a way to check // this. - paused_message_queue_.AddMessage(message.Pass()); + channel_message_queue_.AddMessage(message.Pass()); return true; } @@ -72,8 +71,8 @@ local_id_ = local_id; remote_id_ = remote_id; - while (!paused_message_queue_.IsEmpty()) { - LOG_IF(WARNING, !WriteMessageNoLock(paused_message_queue_.GetMessage())) + while (!channel_message_queue_.IsEmpty()) { + LOG_IF(WARNING, !WriteMessageNoLock(channel_message_queue_.GetMessage())) << "Failed to write enqueue message to channel"; } @@ -85,10 +84,7 @@ } } -bool ChannelEndpoint::OnReadMessage( - const MessageInTransit::View& message_view, - embedder::ScopedPlatformHandleVectorPtr platform_handles) { - scoped_ptr<MessageInTransit> message(new MessageInTransit(message_view)); +void ChannelEndpoint::OnReadMessage(scoped_ptr<MessageInTransit> message) { scoped_refptr<ChannelEndpointClient> client; unsigned client_port; { @@ -97,15 +93,7 @@ if (!client_.get()) { // This isn't a failure per se. (It just means that, e.g., the other end // of the message point closed first.) - return true; - } - - if (message_view.transport_data_buffer_size() > 0) { - DCHECK(message_view.transport_data_buffer()); - message->SetDispatchers(TransportData::DeserializeDispatchers( - message_view.transport_data_buffer(), - message_view.transport_data_buffer_size(), platform_handles.Pass(), - channel_)); + return; } // Take a ref, and call |OnReadMessage()| outside the lock. @@ -113,7 +101,7 @@ client_port = client_port_; } - return client->OnReadMessage(client_port, message.Pass()); + client->OnReadMessage(client_port, message.Pass()); } void ChannelEndpoint::DetachFromChannel() {
diff --git a/mojo/edk/system/channel_endpoint.h b/mojo/edk/system/channel_endpoint.h index 8de169b..71b6f9b 100644 --- a/mojo/edk/system/channel_endpoint.h +++ b/mojo/edk/system/channel_endpoint.h
@@ -9,9 +9,7 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/synchronization/lock.h" -#include "mojo/edk/embedder/platform_handle_vector.h" #include "mojo/edk/system/channel_endpoint_id.h" -#include "mojo/edk/system/message_in_transit.h" #include "mojo/edk/system/message_in_transit_queue.h" #include "mojo/edk/system/system_impl_export.h" @@ -139,15 +137,14 @@ // Methods called by |Channel|: // Called when the |Channel| takes a reference to this object. This will send - // all queue messages (in |paused_message_queue_|). + // all queue messages (in |channel_message_queue_|). // TODO(vtl): Maybe rename this "OnAttach"? void AttachAndRun(Channel* channel, ChannelEndpointId local_id, ChannelEndpointId remote_id); // Called when the |Channel| receives a message for the |ChannelEndpoint|. - bool OnReadMessage(const MessageInTransit::View& message_view, - embedder::ScopedPlatformHandleVectorPtr platform_handles); + void OnReadMessage(scoped_ptr<MessageInTransit> message); // Called before the |Channel| gives up its reference to this object. void DetachFromChannel(); @@ -182,8 +179,8 @@ ChannelEndpointId remote_id_; // This queue is used before we're running on a channel and ready to send - // messages. - MessageInTransitQueue paused_message_queue_; + // messages to the channel. + MessageInTransitQueue channel_message_queue_; DISALLOW_COPY_AND_ASSIGN(ChannelEndpoint); };
diff --git a/mojo/edk/system/channel_endpoint_client.h b/mojo/edk/system/channel_endpoint_client.h index e14326f..7a7d5b8 100644 --- a/mojo/edk/system/channel_endpoint_client.h +++ b/mojo/edk/system/channel_endpoint_client.h
@@ -38,7 +38,7 @@ // called by |Channel| when it receives a message for the |ChannelEndpoint|. // (|port| is the value passed to |ChannelEndpoint|'s constructor as // |client_port|.) - virtual bool OnReadMessage(unsigned port, + virtual void OnReadMessage(unsigned port, scoped_ptr<MessageInTransit> message) = 0; // Called by |ChannelEndpoint| when the |Channel| is relinquishing its pointer
diff --git a/mojo/edk/system/channel_unittest.cc b/mojo/edk/system/channel_unittest.cc index 68b1315a..e84ab5b 100644 --- a/mojo/edk/system/channel_unittest.cc +++ b/mojo/edk/system/channel_unittest.cc
@@ -243,8 +243,8 @@ waiter.Wait(MOJO_DEADLINE_INDEFINITE, nullptr)); HandleSignalsState hss; mp->RemoveWaiter(0, &waiter, &hss); - EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(0u, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); mp->Close(0); @@ -279,8 +279,8 @@ HandleSignalsState hss; EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, mp->AddWaiter(0, &waiter, MOJO_HANDLE_SIGNAL_READABLE, 123, &hss)); - EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(0u, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); mp->Close(0);
diff --git a/mojo/edk/system/core_unittest.cc b/mojo/edk/system/core_unittest.cc index 96780f7..51a4022c 100644 --- a/mojo/edk/system/core_unittest.cc +++ b/mojo/edk/system/core_unittest.cc
@@ -18,6 +18,9 @@ const MojoHandleSignalsState kEmptyMojoHandleSignalsState = {0u, 0u}; const MojoHandleSignalsState kFullMojoHandleSignalsState = {~0u, ~0u}; +const MojoHandleSignals kAllSignals = MOJO_HANDLE_SIGNAL_READABLE | + MOJO_HANDLE_SIGNAL_WRITABLE | + MOJO_HANDLE_SIGNAL_PEER_CLOSED; typedef test::CoreTestBase CoreTest; @@ -545,11 +548,9 @@ MakeUserPointer(&result_index), MakeUserPointer(hss))); EXPECT_EQ(static_cast<uint32_t>(-1), result_index); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss[0].satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss[0].satisfiable_signals); + EXPECT_EQ(kAllSignals, hss[0].satisfiable_signals); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss[1].satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss[1].satisfiable_signals); + EXPECT_EQ(kAllSignals, hss[1].satisfiable_signals); // Try to read anyway. char buffer[1] = {'a'}; @@ -568,14 +569,12 @@ EXPECT_EQ(MOJO_RESULT_OK, core()->Wait(h[0], MOJO_HANDLE_SIGNAL_WRITABLE, 1000000000, MakeUserPointer(&hss[0]))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss[0].satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss[0].satisfiable_signals); + EXPECT_EQ(kAllSignals, hss[0].satisfiable_signals); hss[0] = kEmptyMojoHandleSignalsState; EXPECT_EQ(MOJO_RESULT_OK, core()->Wait(h[1], MOJO_HANDLE_SIGNAL_WRITABLE, 1000000000, MakeUserPointer(&hss[0]))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss[0].satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss[0].satisfiable_signals); + EXPECT_EQ(kAllSignals, hss[0].satisfiable_signals); // Also check that |h[1]| is writable using |WaitMany()|. signals[0] = MOJO_HANDLE_SIGNAL_READABLE; @@ -590,11 +589,9 @@ MakeUserPointer(hss))); EXPECT_EQ(1u, result_index); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss[0].satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss[0].satisfiable_signals); + EXPECT_EQ(kAllSignals, hss[0].satisfiable_signals); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss[1].satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss[1].satisfiable_signals); + EXPECT_EQ(kAllSignals, hss[1].satisfiable_signals); // Write to |h[1]|. buffer[0] = 'b'; @@ -617,11 +614,9 @@ EXPECT_EQ(0u, result_index); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss[0].satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss[0].satisfiable_signals); + EXPECT_EQ(kAllSignals, hss[0].satisfiable_signals); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss[1].satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss[1].satisfiable_signals); + EXPECT_EQ(kAllSignals, hss[1].satisfiable_signals); // Read from |h[0]|. // First, get only the size. @@ -649,8 +644,7 @@ core()->Wait(h[0], MOJO_HANDLE_SIGNAL_READABLE, 0, MakeUserPointer(&hss[0]))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss[0].satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss[0].satisfiable_signals); + EXPECT_EQ(kAllSignals, hss[0].satisfiable_signals); // Write to |h[0]|. buffer[0] = 'd'; @@ -667,15 +661,19 @@ EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, core()->Wait(h[1], MOJO_HANDLE_SIGNAL_WRITABLE, 1000000000, MakeUserPointer(&hss[0]))); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss[0].satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss[0].satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss[0].satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss[0].satisfiable_signals); // Check that |h[1]| is still readable (for the moment). hss[0] = kEmptyMojoHandleSignalsState; EXPECT_EQ(MOJO_RESULT_OK, core()->Wait(h[1], MOJO_HANDLE_SIGNAL_READABLE, 1000000000, MakeUserPointer(&hss[0]))); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss[0].satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss[0].satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss[0].satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss[0].satisfiable_signals); // Discard a message from |h[1]|. EXPECT_EQ(MOJO_RESULT_RESOURCE_EXHAUSTED, @@ -688,8 +686,8 @@ EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, core()->Wait(h[1], MOJO_HANDLE_SIGNAL_READABLE, 1000000000, MakeUserPointer(&hss[0]))); - EXPECT_EQ(0u, hss[0].satisfied_signals); - EXPECT_EQ(0u, hss[0].satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss[0].satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss[0].satisfiable_signals); // Try writing to |h[1]|. buffer[0] = 'e'; @@ -732,8 +730,7 @@ MakeUserPointer(&hss))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); num_bytes = kBufferSize; num_handles = arraysize(handles); EXPECT_EQ(MOJO_RESULT_OK, @@ -773,8 +770,7 @@ MakeUserPointer(&hss))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); num_bytes = kBufferSize; num_handles = arraysize(handles); EXPECT_EQ(MOJO_RESULT_OK, @@ -797,8 +793,7 @@ MakeUserPointer(&hss))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); num_bytes = kBufferSize; num_handles = arraysize(handles); EXPECT_EQ(MOJO_RESULT_OK, @@ -833,8 +828,7 @@ MakeUserPointer(&hss))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); num_bytes = kBufferSize; num_handles = arraysize(handles); EXPECT_EQ(MOJO_RESULT_OK, @@ -870,12 +864,14 @@ MOJO_RESULT_FAILED_PRECONDITION, core()->Wait(ph, MOJO_HANDLE_SIGNAL_READABLE, 0, MakeUserPointer(&hss))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); hss = kEmptyMojoHandleSignalsState; EXPECT_EQ(MOJO_RESULT_OK, core()->Wait(ph, MOJO_HANDLE_SIGNAL_WRITABLE, 0, MakeUserPointer(&hss))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Consumer should be never-writable, and not yet readable. hss = kFullMojoHandleSignalsState; @@ -883,16 +879,18 @@ MOJO_RESULT_FAILED_PRECONDITION, core()->Wait(ch, MOJO_HANDLE_SIGNAL_WRITABLE, 0, MakeUserPointer(&hss))); EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); hss = kFullMojoHandleSignalsState; EXPECT_EQ( MOJO_RESULT_DEADLINE_EXCEEDED, core()->Wait(ch, MOJO_HANDLE_SIGNAL_READABLE, 0, MakeUserPointer(&hss))); EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Write. - char elements[2] = {'A', 'B'}; + signed char elements[2] = {'A', 'B'}; uint32_t num_bytes = 2u; EXPECT_EQ(MOJO_RESULT_OK, core()->WriteData(ph, UserPointer<const void>(elements), @@ -905,7 +903,8 @@ EXPECT_EQ(MOJO_RESULT_OK, core()->Wait(ch, MOJO_HANDLE_SIGNAL_READABLE, 0, MakeUserPointer(&hss))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Peek one character. elements[0] = -1; @@ -1022,7 +1021,8 @@ MOJO_RESULT_DEADLINE_EXCEEDED, core()->Wait(ch, MOJO_HANDLE_SIGNAL_READABLE, 0, MakeUserPointer(&hss))); EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // TODO(vtl): More. @@ -1034,8 +1034,8 @@ EXPECT_EQ( MOJO_RESULT_FAILED_PRECONDITION, core()->Wait(ch, MOJO_HANDLE_SIGNAL_READABLE, 0, MakeUserPointer(&hss))); - EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(0u, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); EXPECT_EQ(MOJO_RESULT_OK, core()->Close(ch)); } @@ -1075,8 +1075,7 @@ MakeUserPointer(&hss))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); num_bytes = kBufferSize; num_handles = arraysize(handles); EXPECT_EQ(MOJO_RESULT_OK, @@ -1111,7 +1110,8 @@ core()->Wait(ch_received, MOJO_HANDLE_SIGNAL_READABLE, 1000000000, MakeUserPointer(&hss))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); num_bytes = kBufferSize; EXPECT_EQ(MOJO_RESULT_OK, core()->ReadData(ch_received, UserPointer<void>(buffer), @@ -1131,8 +1131,7 @@ MakeUserPointer(&hss))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); num_bytes = kBufferSize; num_handles = arraysize(handles); EXPECT_EQ(MOJO_RESULT_OK, @@ -1167,7 +1166,8 @@ core()->Wait(ch_received, MOJO_HANDLE_SIGNAL_READABLE, 1000000000, MakeUserPointer(&hss))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); num_bytes = kBufferSize; EXPECT_EQ(MOJO_RESULT_OK, core()->ReadData(ch_received, UserPointer<void>(buffer), @@ -1225,7 +1225,8 @@ EXPECT_EQ(MOJO_RESULT_OK, core()->Wait(ch, MOJO_HANDLE_SIGNAL_READABLE, 1000000000, MakeUserPointer(&hss))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Make sure that |ch| can't be sent if it's in a two-phase read. const void* read_ptr = nullptr; @@ -1251,8 +1252,7 @@ MakeUserPointer(&hss))); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); num_bytes = kBufferSize; num_handles = arraysize(handles); EXPECT_EQ(MOJO_RESULT_OK,
diff --git a/mojo/edk/system/local_data_pipe.cc b/mojo/edk/system/local_data_pipe.cc index 177b238..8b9f673 100644 --- a/mojo/edk/system/local_data_pipe.cc +++ b/mojo/edk/system/local_data_pipe.cc
@@ -160,7 +160,10 @@ !producer_in_two_phase_write_no_lock()) rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_WRITABLE; rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_WRITABLE; + } else { + rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED; } + rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED; return rv; } @@ -293,6 +296,9 @@ } else if (producer_open_no_lock()) { rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_READABLE; } + if (!producer_open_no_lock()) + rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED; + rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED; return rv; }
diff --git a/mojo/edk/system/local_data_pipe_unittest.cc b/mojo/edk/system/local_data_pipe_unittest.cc index 9ba6b21..cea50a0 100644 --- a/mojo/edk/system/local_data_pipe_unittest.cc +++ b/mojo/edk/system/local_data_pipe_unittest.cc
@@ -239,7 +239,8 @@ MOJO_RESULT_FAILED_PRECONDITION, dp->ProducerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 12, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Already writable. waiter.Init(); @@ -266,7 +267,8 @@ hss = HandleSignalsState(); dp->ProducerRemoveWaiter(&waiter, &hss); EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Peek one element. elements[0] = -1; @@ -289,7 +291,8 @@ hss = HandleSignalsState(); dp->ProducerRemoveWaiter(&waiter, &hss); EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Do it again. waiter.Init(); @@ -314,7 +317,8 @@ hss = HandleSignalsState(); dp->ProducerRemoveWaiter(&waiter, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Try writing, using a two-phase write. void* buffer = nullptr; @@ -357,7 +361,8 @@ hss = HandleSignalsState(); dp->ProducerRemoveWaiter(&waiter, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Write one element. elements[0] = 123; @@ -381,12 +386,75 @@ EXPECT_EQ(12u, context); hss = HandleSignalsState(); dp->ProducerRemoveWaiter(&waiter, &hss); - EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(0u, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); dp->ProducerClose(); } +TEST(LocalDataPipeTest, PeerClosedWaiting) { + const MojoCreateDataPipeOptions options = { + kSizeOfOptions, // |struct_size|. + MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, // |flags|. + static_cast<uint32_t>(sizeof(int32_t)), // |element_num_bytes|. + 2 * sizeof(int32_t) // |capacity_num_bytes|. + }; + MojoCreateDataPipeOptions validated_options = {0}; + EXPECT_EQ(MOJO_RESULT_OK, DataPipe::ValidateCreateOptions( + MakeUserPointer(&options), &validated_options)); + + Waiter waiter; + HandleSignalsState hss; + + // Check MOJO_HANDLE_SIGNAL_PEER_CLOSED on producer. + { + scoped_refptr<LocalDataPipe> dp(new LocalDataPipe(validated_options)); + // Add a waiter. + waiter.Init(); + ASSERT_EQ(MOJO_RESULT_OK, + dp->ProducerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_PEER_CLOSED, 12, + nullptr)); + + // Close the consumer. + dp->ConsumerClose(); + + // It should be signaled. + uint32_t context = 0; + EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(1000, &context)); + EXPECT_EQ(12u, context); + hss = HandleSignalsState(); + dp->ProducerRemoveWaiter(&waiter, &hss); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); + + dp->ProducerClose(); + } + + // Check MOJO_HANDLE_SIGNAL_PEER_CLOSED on consumer. + { + scoped_refptr<LocalDataPipe> dp(new LocalDataPipe(validated_options)); + // Add a waiter. + waiter.Init(); + ASSERT_EQ(MOJO_RESULT_OK, + dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_PEER_CLOSED, 12, + nullptr)); + + // Close the producer. + dp->ProducerClose(); + + // It should be signaled. + uint32_t context = 0; + EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(1000, &context)); + EXPECT_EQ(12u, context); + hss = HandleSignalsState(); + dp->ConsumerRemoveWaiter(&waiter, &hss); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); + + dp->ConsumerClose(); + } +} + TEST(LocalDataPipeTest, BasicConsumerWaiting) { const MojoCreateDataPipeOptions options = { kSizeOfOptions, // |struct_size|. @@ -411,7 +479,8 @@ MOJO_RESULT_FAILED_PRECONDITION, dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 12, &hss)); EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Not yet readable. waiter.Init(); @@ -422,7 +491,8 @@ hss = HandleSignalsState(); dp->ConsumerRemoveWaiter(&waiter, &hss); EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Write two elements. int32_t elements[2] = {123, 456}; @@ -438,7 +508,8 @@ MOJO_RESULT_ALREADY_EXISTS, dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 56, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Discard one element. num_bytes = static_cast<uint32_t>(1u * sizeof(elements[0])); @@ -453,7 +524,8 @@ MOJO_RESULT_ALREADY_EXISTS, dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 78, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Peek one element. elements[0] = -1; @@ -473,7 +545,8 @@ MOJO_RESULT_ALREADY_EXISTS, dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 78, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Read one element. elements[0] = -1; @@ -506,7 +579,8 @@ hss = HandleSignalsState(); dp->ConsumerRemoveWaiter(&waiter, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Close the producer. dp->ProducerClose(); @@ -517,8 +591,10 @@ EXPECT_EQ( MOJO_RESULT_ALREADY_EXISTS, dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 12, &hss)); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Read one element. elements[0] = -1; @@ -537,8 +613,8 @@ EXPECT_EQ( MOJO_RESULT_FAILED_PRECONDITION, dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 34, &hss)); - EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(0u, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); dp->ConsumerClose(); } @@ -574,7 +650,8 @@ MOJO_RESULT_ALREADY_EXISTS, dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 12, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Read one element. // Request two in all-or-none mode, but only read one. @@ -597,7 +674,8 @@ MOJO_RESULT_ALREADY_EXISTS, dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 34, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Read one element. // Request three, but not in all-or-none mode. @@ -627,8 +705,8 @@ EXPECT_EQ(56u, context); hss = HandleSignalsState(); dp->ConsumerRemoveWaiter(&waiter, &hss); - EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(0u, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); dp->ConsumerClose(); } @@ -657,7 +735,8 @@ MOJO_RESULT_ALREADY_EXISTS, dp->ProducerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 0, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); uint32_t num_bytes = static_cast<uint32_t>(1u * sizeof(int32_t)); void* write_ptr = nullptr; @@ -676,7 +755,8 @@ hss = HandleSignalsState(); dp->ProducerRemoveWaiter(&waiter, &hss); EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // It shouldn't be readable yet either. waiter.Init(); @@ -687,7 +767,8 @@ hss = HandleSignalsState(); dp->ConsumerRemoveWaiter(&waiter, &hss); EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); static_cast<int32_t*>(write_ptr)[0] = 123; EXPECT_EQ(MOJO_RESULT_OK, dp->ProducerEndWriteData( @@ -700,7 +781,8 @@ MOJO_RESULT_ALREADY_EXISTS, dp->ProducerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 3, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // And readable. waiter.Init(); @@ -709,7 +791,8 @@ MOJO_RESULT_ALREADY_EXISTS, dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 4, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Start another two-phase write and check that it's readable even in the // middle of it. @@ -728,7 +811,8 @@ MOJO_RESULT_ALREADY_EXISTS, dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 5, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // End the two-phase write without writing anything. EXPECT_EQ(MOJO_RESULT_OK, dp->ProducerEndWriteData(0u)); @@ -749,7 +833,8 @@ MOJO_RESULT_ALREADY_EXISTS, dp->ProducerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 6, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // But not readable. waiter.Init(); @@ -760,7 +845,8 @@ hss = HandleSignalsState(); dp->ConsumerRemoveWaiter(&waiter, &hss); EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // End the two-phase read without reading anything. EXPECT_EQ(MOJO_RESULT_OK, dp->ConsumerEndReadData(0u)); @@ -772,7 +858,8 @@ MOJO_RESULT_ALREADY_EXISTS, dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 8, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); dp->ProducerClose(); dp->ConsumerClose(); @@ -801,7 +888,8 @@ MOJO_RESULT_ALREADY_EXISTS, dp->ProducerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 0, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Not readable. waiter.Init(); @@ -812,7 +900,8 @@ hss = HandleSignalsState(); dp->ConsumerRemoveWaiter(&waiter, &hss); EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); uint32_t num_bytes = static_cast<uint32_t>(sizeof(int32_t)); int32_t element = 123; @@ -828,7 +917,8 @@ MOJO_RESULT_ALREADY_EXISTS, dp->ProducerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 2, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Now readable. waiter.Init(); @@ -837,7 +927,8 @@ MOJO_RESULT_ALREADY_EXISTS, dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 3, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Overwrite that element. num_bytes = static_cast<uint32_t>(sizeof(int32_t)); @@ -854,7 +945,8 @@ MOJO_RESULT_ALREADY_EXISTS, dp->ProducerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 4, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // And still readable. waiter.Init(); @@ -863,7 +955,8 @@ MOJO_RESULT_ALREADY_EXISTS, dp->ConsumerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_READABLE, 5, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Read that element. num_bytes = static_cast<uint32_t>(sizeof(int32_t)); @@ -881,7 +974,8 @@ MOJO_RESULT_ALREADY_EXISTS, dp->ProducerAddWaiter(&waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 6, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // No longer readable. waiter.Init(); @@ -892,7 +986,8 @@ hss = HandleSignalsState(); dp->ConsumerRemoveWaiter(&waiter, &hss); EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); dp->ProducerClose(); dp->ConsumerClose();
diff --git a/mojo/edk/system/local_message_pipe_endpoint.cc b/mojo/edk/system/local_message_pipe_endpoint.cc index 124241e..86d241c 100644 --- a/mojo/edk/system/local_message_pipe_endpoint.cc +++ b/mojo/edk/system/local_message_pipe_endpoint.cc
@@ -137,7 +137,10 @@ rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_WRITABLE; rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE; + } else { + rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED; } + rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED; return rv; }
diff --git a/mojo/edk/system/message_in_transit.cc b/mojo/edk/system/message_in_transit.cc index 0f2ff5e6..624a546 100644 --- a/mojo/edk/system/message_in_transit.cc +++ b/mojo/edk/system/message_in_transit.cc
@@ -15,15 +15,13 @@ namespace system { STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Type - MessageInTransit::kTypeMessagePipeEndpoint; -STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Type - MessageInTransit::kTypeMessagePipe; + MessageInTransit::kTypeEndpoint; STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Type MessageInTransit::kTypeChannel; STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Type MessageInTransit::kTypeRawChannel; STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype - MessageInTransit::kSubtypeMessagePipeEndpointData; + MessageInTransit::kSubtypeEndpointData; STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype MessageInTransit::kSubtypeChannelAttachAndRunEndpoint; STATIC_CONST_MEMBER_DEFINITION const MessageInTransit::Subtype @@ -110,6 +108,8 @@ base::AlignedAlloc(main_buffer_size_, kMessageAlignment))) { ConstructorHelper(type, subtype, num_bytes); bytes.GetArray(MessageInTransit::bytes(), num_bytes); + memset(static_cast<char*>(MessageInTransit::bytes()) + num_bytes, 0, + main_buffer_size_ - sizeof(Header) - num_bytes); } MessageInTransit::MessageInTransit(const View& message_view)
diff --git a/mojo/edk/system/message_in_transit.h b/mojo/edk/system/message_in_transit.h index 2b9da6d0..0f92b05 100644 --- a/mojo/edk/system/message_in_transit.h +++ b/mojo/edk/system/message_in_transit.h
@@ -44,20 +44,16 @@ class MOJO_SYSTEM_IMPL_EXPORT MessageInTransit { public: typedef uint16_t Type; - // Messages that are forwarded to |MessagePipeEndpoint|s. - static const Type kTypeMessagePipeEndpoint = 0; - // Messages that are forwarded to |MessagePipe|s. - static const Type kTypeMessagePipe = 1; + // Messages that are forwarded to endpoints. + static const Type kTypeEndpoint = 0; // Messages that are consumed by the |Channel|. - static const Type kTypeChannel = 2; + static const Type kTypeChannel = 1; // Messages that are consumed by the |RawChannel| (implementation). - static const Type kTypeRawChannel = 3; + static const Type kTypeRawChannel = 2; typedef uint16_t Subtype; - // Subtypes for type |kTypeMessagePipeEndpoint|: - static const Subtype kSubtypeMessagePipeEndpointData = 0; - // Subtypes for type |kTypeMessagePipe|: - // Nothing currently. + // Subtypes for type |kTypeEndpoint|: + static const Subtype kSubtypeEndpointData = 0; // Subtypes for type |kTypeChannel|: static const Subtype kSubtypeChannelAttachAndRunEndpoint = 0; static const Subtype kSubtypeChannelRemoveMessagePipeEndpoint = 1;
diff --git a/mojo/edk/system/message_pipe.cc b/mojo/edk/system/message_pipe.cc index 8e1be57f..ee5036f 100644 --- a/mojo/edk/system/message_pipe.cc +++ b/mojo/edk/system/message_pipe.cc
@@ -142,8 +142,8 @@ return EnqueueMessage( GetPeerPort(port), make_scoped_ptr(new MessageInTransit( - MessageInTransit::kTypeMessagePipeEndpoint, - MessageInTransit::kSubtypeMessagePipeEndpointData, num_bytes, bytes)), + MessageInTransit::kTypeEndpoint, + MessageInTransit::kSubtypeEndpointData, num_bytes, bytes)), transports); } @@ -287,14 +287,16 @@ return true; } -bool MessagePipe::OnReadMessage(unsigned port, +void MessagePipe::OnReadMessage(unsigned port, scoped_ptr<MessageInTransit> message) { // This is called when the |ChannelEndpoint| for the // |ProxyMessagePipeEndpoint| |port| receives a message (from the |Channel|). // We need to pass this message on to its peer port (typically a // |LocalMessagePipeEndpoint|). - return EnqueueMessage(GetPeerPort(port), message.Pass(), nullptr) == - MOJO_RESULT_OK; + MojoResult result = + EnqueueMessage(GetPeerPort(port), message.Pass(), nullptr); + DLOG_IF(WARNING, result != MOJO_RESULT_OK) + << "EnqueueMessage() failed (result = " << result << ")"; } void MessagePipe::OnDetachFromChannel(unsigned port) { @@ -319,12 +321,7 @@ DCHECK(port == 0 || port == 1); DCHECK(message); - if (message->type() == MessageInTransit::kTypeMessagePipe) { - DCHECK(!transports); - return HandleControlMessage(port, message.Pass()); - } - - DCHECK_EQ(message->type(), MessageInTransit::kTypeMessagePipeEndpoint); + DCHECK_EQ(message->type(), MessageInTransit::kTypeEndpoint); base::AutoLock locker(lock_); DCHECK(endpoints_[GetPeerPort(port)]); @@ -388,13 +385,5 @@ return MOJO_RESULT_OK; } -MojoResult MessagePipe::HandleControlMessage( - unsigned /*port*/, - scoped_ptr<MessageInTransit> message) { - LOG(WARNING) << "Unrecognized MessagePipe control message subtype " - << message->subtype(); - return MOJO_RESULT_UNKNOWN; -} - } // namespace system } // namespace mojo
diff --git a/mojo/edk/system/message_pipe.h b/mojo/edk/system/message_pipe.h index 1c1af1e..e8f97d0 100644 --- a/mojo/edk/system/message_pipe.h +++ b/mojo/edk/system/message_pipe.h
@@ -107,7 +107,7 @@ embedder::PlatformHandleVector* platform_handles); // |ChannelEndpointClient| methods: - bool OnReadMessage(unsigned port, + void OnReadMessage(unsigned port, scoped_ptr<MessageInTransit> message) override; void OnDetachFromChannel(unsigned port) override; @@ -128,11 +128,6 @@ MessageInTransit* message, std::vector<DispatcherTransport>* transports); - // Used by |EnqueueMessage()| to handle control messages that are actually - // meant for us. - MojoResult HandleControlMessage(unsigned port, - scoped_ptr<MessageInTransit> message); - base::Lock lock_; // Protects the following members. scoped_ptr<MessagePipeEndpoint> endpoints_[2];
diff --git a/mojo/edk/system/message_pipe_dispatcher_unittest.cc b/mojo/edk/system/message_pipe_dispatcher_unittest.cc index 8076a994..303ae6a 100644 --- a/mojo/edk/system/message_pipe_dispatcher_unittest.cc +++ b/mojo/edk/system/message_pipe_dispatcher_unittest.cc
@@ -29,6 +29,10 @@ namespace system { namespace { +const MojoHandleSignals kAllSignals = MOJO_HANDLE_SIGNAL_READABLE | + MOJO_HANDLE_SIGNAL_WRITABLE | + MOJO_HANDLE_SIGNAL_PEER_CLOSED; + TEST(MessagePipeDispatcherTest, Basic) { test::Stopwatch stopwatch; int32_t buffer[1]; @@ -57,8 +61,7 @@ EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, d0->AddWaiter(&w, MOJO_HANDLE_SIGNAL_WRITABLE, 0, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Shouldn't need to remove the waiter (it was not added). // Add a readable waiter to |d0|, then make it readable (by writing to @@ -78,8 +81,7 @@ d0->RemoveWaiter(&w, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Try adding a readable waiter when already readable (from above). w.Init(); @@ -88,8 +90,7 @@ d0->AddWaiter(&w, MOJO_HANDLE_SIGNAL_READABLE, 2, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Shouldn't need to remove the waiter (it was not added). // Make |d0| no longer readable (by reading from it). @@ -112,8 +113,7 @@ hss = HandleSignalsState(); d0->RemoveWaiter(&w, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Wait for non-zero, finite time for readability on |d0| (will time out). w.Init(); @@ -128,11 +128,25 @@ hss = HandleSignalsState(); d0->RemoveWaiter(&w, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); + + // Check the peer closed signal. + w.Init(); + ASSERT_EQ(MOJO_RESULT_OK, + d0->AddWaiter(&w, MOJO_HANDLE_SIGNAL_PEER_CLOSED, 12, nullptr)); + + // Close the peer. + EXPECT_EQ(MOJO_RESULT_OK, d1->Close()); + + // It should be signaled. + EXPECT_EQ(MOJO_RESULT_OK, w.Wait(1000, &context)); + EXPECT_EQ(12u, context); + hss = HandleSignalsState(); + d0->RemoveWaiter(&w, &hss); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); EXPECT_EQ(MOJO_RESULT_OK, d0->Close()); - EXPECT_EQ(MOJO_RESULT_OK, d1->Close()); } } @@ -238,8 +252,7 @@ d0->AddWaiter(&w, MOJO_HANDLE_SIGNAL_READABLE, 0, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Try reading from |d1|; should fail (nothing to read). buffer[0] = 0; @@ -257,8 +270,10 @@ hss = HandleSignalsState(); EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, d0->AddWaiter(&w, MOJO_HANDLE_SIGNAL_READABLE, 1, &hss)); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Read from |d0|. buffer[0] = 0; @@ -275,8 +290,10 @@ hss = HandleSignalsState(); EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, d0->AddWaiter(&w, MOJO_HANDLE_SIGNAL_READABLE, 2, &hss)); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Read again from |d0|. buffer[0] = 0; @@ -293,16 +310,16 @@ hss = HandleSignalsState(); EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, d0->AddWaiter(&w, MOJO_HANDLE_SIGNAL_READABLE, 3, &hss)); - EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(0u, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); // Try waiting for writable on |d0|; should fail (unsatisfiable). w.Init(); hss = HandleSignalsState(); EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, d0->AddWaiter(&w, MOJO_HANDLE_SIGNAL_WRITABLE, 4, &hss)); - EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(0u, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); // Try reading from |d0|; should fail (nothing to read and other end // closed). @@ -374,8 +391,7 @@ EXPECT_EQ(1u, context); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Now |d1| is already readable. Try waiting for it again. { @@ -390,8 +406,7 @@ EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, result); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Consume what we wrote to |d0|. buffer[0] = 0; @@ -420,8 +435,8 @@ EXPECT_TRUE(did_wait); EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); EXPECT_EQ(3u, context); - EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(0u, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); EXPECT_EQ(MOJO_RESULT_OK, d1->Close()); }
diff --git a/mojo/edk/system/message_pipe_perftest.cc b/mojo/edk/system/message_pipe_perftest.cc index 9f1ac5d..2387782 100644 --- a/mojo/edk/system/message_pipe_perftest.cc +++ b/mojo/edk/system/message_pipe_perftest.cc
@@ -140,7 +140,13 @@ // Repeatedly sends messages as previous one got replied by the child. // Waits for the child to close its end before quitting once specified // number of messages has been sent. -TEST_F(MultiprocessMessagePipePerfTest, PingPong) { +#if defined(OS_ANDROID) +// Android multi-process tests are not executing the new process. This is flaky. +#define MAYBE_PingPong DISABLED_PingPong +#else +#define MAYBE_PingPong PingPong +#endif // defined(OS_ANDROID) +TEST_F(MultiprocessMessagePipePerfTest, MAYBE_PingPong) { helper()->StartChild("PingPongClient"); scoped_refptr<ChannelEndpoint> ep;
diff --git a/mojo/edk/system/message_pipe_unittest.cc b/mojo/edk/system/message_pipe_unittest.cc index 030084b6..c700891 100644 --- a/mojo/edk/system/message_pipe_unittest.cc +++ b/mojo/edk/system/message_pipe_unittest.cc
@@ -15,6 +15,10 @@ namespace system { namespace { +const MojoHandleSignals kAllSignals = MOJO_HANDLE_SIGNAL_READABLE | + MOJO_HANDLE_SIGNAL_WRITABLE | + MOJO_HANDLE_SIGNAL_PEER_CLOSED; + // Tests: // - only default flags // - reading messages from a port @@ -335,8 +339,7 @@ EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, mp->AddWaiter(0, &waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 0, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); waiter.Init(); hss = HandleSignalsState(); EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, @@ -344,8 +347,7 @@ MOJO_HANDLE_SIGNAL_WRITABLE, 0, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Not yet readable. waiter.Init(); @@ -355,8 +357,18 @@ hss = HandleSignalsState(); mp->RemoveWaiter(0, &waiter, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); + + // The peer is not closed. + waiter.Init(); + ASSERT_EQ( + MOJO_RESULT_OK, + mp->AddWaiter(0, &waiter, MOJO_HANDLE_SIGNAL_PEER_CLOSED, 2, nullptr)); + EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED, waiter.Wait(0, nullptr)); + hss = HandleSignalsState(); + mp->RemoveWaiter(0, &waiter, &hss); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Write from port 0 (to port 1), to make port 1 readable. buffer[0] = 123456789; @@ -368,11 +380,10 @@ waiter.Init(); hss = HandleSignalsState(); EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, - mp->AddWaiter(1, &waiter, MOJO_HANDLE_SIGNAL_READABLE, 2, &hss)); + mp->AddWaiter(1, &waiter, MOJO_HANDLE_SIGNAL_READABLE, 3, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); waiter.Init(); hss = HandleSignalsState(); EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, @@ -381,36 +392,48 @@ 0, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // ... and still writable. waiter.Init(); hss = HandleSignalsState(); EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, - mp->AddWaiter(1, &waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 3, &hss)); + mp->AddWaiter(1, &waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 4, &hss)); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Close port 0. mp->Close(0); - // Now port 1 should not be writable. + // Port 1 should be signaled with peer closed. + waiter.Init(); + hss = HandleSignalsState(); + EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, + mp->AddWaiter(1, &waiter, MOJO_HANDLE_SIGNAL_PEER_CLOSED, 5, &hss)); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); + + // Port 1 should not be writable. waiter.Init(); hss = HandleSignalsState(); EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - mp->AddWaiter(1, &waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 4, &hss)); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + mp->AddWaiter(1, &waiter, MOJO_HANDLE_SIGNAL_WRITABLE, 6, &hss)); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // But it should still be readable. waiter.Init(); hss = HandleSignalsState(); EXPECT_EQ(MOJO_RESULT_ALREADY_EXISTS, - mp->AddWaiter(1, &waiter, MOJO_HANDLE_SIGNAL_READABLE, 5, &hss)); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + mp->AddWaiter(1, &waiter, MOJO_HANDLE_SIGNAL_READABLE, 7, &hss)); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // Read from port 1. buffer[0] = 0; @@ -425,7 +448,7 @@ waiter.Init(); hss = HandleSignalsState(); EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, - mp->AddWaiter(1, &waiter, MOJO_HANDLE_SIGNAL_READABLE, 6, nullptr)); + mp->AddWaiter(1, &waiter, MOJO_HANDLE_SIGNAL_READABLE, 8, nullptr)); EXPECT_EQ(0u, hss.satisfied_signals); EXPECT_EQ(0u, hss.satisfiable_signals); @@ -460,8 +483,7 @@ mp->RemoveWaiter(1, thread.waiter(), &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); mp->Close(0); mp->Close(1); @@ -493,6 +515,29 @@ EXPECT_EQ(MOJO_RESULT_CANCELLED, result); EXPECT_EQ(2u, context); + // Close to cancel waiter using peer closed signal. + { + scoped_refptr<MessagePipe> mp(MessagePipe::CreateLocalLocal()); + test::SimpleWaiterThread thread(&result, &context); + + thread.waiter()->Init(); + ASSERT_EQ(MOJO_RESULT_OK, + mp->AddWaiter(1, thread.waiter(), MOJO_HANDLE_SIGNAL_PEER_CLOSED, + 3, nullptr)); + thread.Start(); + + // Close port 1 first -- this should result in the waiter being cancelled. + mp->CancelAllWaiters(1); + mp->Close(1); + + // Port 1 is closed, so |Dispatcher::RemoveWaiter()| wouldn't call into the + // |MessagePipe| to remove any waiter. + + mp->Close(0); + } // Joins |thread|. + EXPECT_EQ(MOJO_RESULT_CANCELLED, result); + EXPECT_EQ(3u, context); + // Close to make waiter un-wake-up-able. { scoped_refptr<MessagePipe> mp(MessagePipe::CreateLocalLocal()); @@ -500,7 +545,7 @@ thread.waiter()->Init(); ASSERT_EQ(MOJO_RESULT_OK, - mp->AddWaiter(1, thread.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 3, + mp->AddWaiter(1, thread.waiter(), MOJO_HANDLE_SIGNAL_READABLE, 4, nullptr)); thread.Start(); @@ -511,14 +556,14 @@ HandleSignalsState hss; mp->RemoveWaiter(1, thread.waiter(), &hss); - EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(0u, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); mp->CancelAllWaiters(1); mp->Close(1); } // Joins |thread|. EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, result); - EXPECT_EQ(3u, context); + EXPECT_EQ(4u, context); } } // namespace
diff --git a/mojo/edk/system/multiprocess_message_pipe_unittest.cc b/mojo/edk/system/multiprocess_message_pipe_unittest.cc index ab2e75ce..f486152e 100644 --- a/mojo/edk/system/multiprocess_message_pipe_unittest.cc +++ b/mojo/edk/system/multiprocess_message_pipe_unittest.cc
@@ -62,8 +62,8 @@ if (result != MOJO_RESULT_OK) { // It was closed, probably. CHECK_EQ(result, MOJO_RESULT_FAILED_PRECONDITION); - CHECK_EQ(hss.satisfied_signals, 0u); - CHECK_EQ(hss.satisfiable_signals, 0u); + CHECK_EQ(hss.satisfied_signals, MOJO_HANDLE_SIGNAL_PEER_CLOSED); + CHECK_EQ(hss.satisfiable_signals, MOJO_HANDLE_SIGNAL_PEER_CLOSED); break; } else { CHECK((hss.satisfied_signals & MOJO_HANDLE_SIGNAL_READABLE)); @@ -96,7 +96,13 @@ } // Sends "hello" to child, and expects "hellohello" back. -TEST_F(MultiprocessMessagePipeTest, Basic) { +#if defined(OS_ANDROID) +// Android multi-process tests are not executing the new process. This is flaky. +#define MAYBE_Basic DISABLED_Basic +#else +#define MAYBE_Basic Basic +#endif // defined(OS_ANDROID) +TEST_F(MultiprocessMessagePipeTest, MAYBE_Basic) { helper()->StartChild("EchoEcho"); scoped_refptr<ChannelEndpoint> ep; @@ -136,7 +142,13 @@ // Sends a bunch of messages to the child. Expects them "repeated" back. Waits // for the child to close its end before quitting. -TEST_F(MultiprocessMessagePipeTest, QueueMessages) { +#if defined(OS_ANDROID) +// Android multi-process tests are not executing the new process. This is flaky. +#define MAYBE_QueueMessages DISABLED_QueueMessages +#else +#define MAYBE_QueueMessages QueueMessages +#endif // defined(OS_ANDROID) +TEST_F(MultiprocessMessagePipeTest, DISABLED_QueueMessages) { helper()->StartChild("EchoEcho"); scoped_refptr<ChannelEndpoint> ep; @@ -184,8 +196,8 @@ HandleSignalsState hss; EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, test::WaitIfNecessary(mp, MOJO_HANDLE_SIGNAL_READABLE, &hss)); - EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(0u, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); mp->Close(0); @@ -211,8 +223,9 @@ // pipe before we do. CHECK_EQ(hss.satisfied_signals, MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE); - CHECK_EQ(hss.satisfiable_signals, - MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE); + CHECK_EQ(hss.satisfiable_signals, MOJO_HANDLE_SIGNAL_READABLE | + MOJO_HANDLE_SIGNAL_WRITABLE | + MOJO_HANDLE_SIGNAL_PEER_CLOSED); // It should have a shared buffer. std::string read_buffer(100, '\0'); @@ -260,8 +273,9 @@ MOJO_RESULT_OK); CHECK_EQ(hss.satisfied_signals, MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE); - CHECK_EQ(hss.satisfiable_signals, - MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE); + CHECK_EQ(hss.satisfiable_signals, MOJO_HANDLE_SIGNAL_READABLE | + MOJO_HANDLE_SIGNAL_WRITABLE | + MOJO_HANDLE_SIGNAL_PEER_CLOSED); read_buffer = std::string(100, '\0'); num_bytes = static_cast<uint32_t>(read_buffer.size()); @@ -282,10 +296,11 @@ return 0; } -#if defined(OS_POSIX) +#if defined(OS_POSIX) && !defined(OS_ANDROID) #define MAYBE_SharedBufferPassing SharedBufferPassing #else // Not yet implemented (on Windows). +// Android multi-process tests are not executing the new process. This is flaky. #define MAYBE_SharedBufferPassing DISABLED_SharedBufferPassing #endif TEST_F(MultiprocessMessagePipeTest, MAYBE_SharedBufferPassing) { @@ -364,8 +379,8 @@ hss = HandleSignalsState(); EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, test::WaitIfNecessary(mp, MOJO_HANDLE_SIGNAL_READABLE, &hss)); - EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(0u, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); mp->Close(0); @@ -387,8 +402,9 @@ MOJO_RESULT_OK); CHECK_EQ(hss.satisfied_signals, MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE); - CHECK_EQ(hss.satisfiable_signals, - MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE); + CHECK_EQ(hss.satisfiable_signals, MOJO_HANDLE_SIGNAL_READABLE | + MOJO_HANDLE_SIGNAL_WRITABLE | + MOJO_HANDLE_SIGNAL_PEER_CLOSED); std::string read_buffer(100, '\0'); uint32_t num_bytes = static_cast<uint32_t>(read_buffer.size()); @@ -422,10 +438,11 @@ return 0; } -#if defined(OS_POSIX) +#if defined(OS_POSIX) && !defined(OS_ANDROID) #define MAYBE_PlatformHandlePassing PlatformHandlePassing #else // Not yet implemented (on Windows). +// Android multi-process tests are not executing the new process. This is flaky. #define MAYBE_PlatformHandlePassing DISABLED_PlatformHandlePassing #endif TEST_F(MultiprocessMessagePipeTest, MAYBE_PlatformHandlePassing) { @@ -471,8 +488,8 @@ HandleSignalsState hss; EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION, test::WaitIfNecessary(mp, MOJO_HANDLE_SIGNAL_READABLE, &hss)); - EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(0u, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); mp->Close(0);
diff --git a/mojo/edk/system/raw_channel_unittest.cc b/mojo/edk/system/raw_channel_unittest.cc index 7717f49..1c390108 100644 --- a/mojo/edk/system/raw_channel_unittest.cc +++ b/mojo/edk/system/raw_channel_unittest.cc
@@ -38,10 +38,9 @@ std::vector<unsigned char> bytes(num_bytes, 0); for (size_t i = 0; i < num_bytes; i++) bytes[i] = static_cast<unsigned char>(i + num_bytes); - return make_scoped_ptr( - new MessageInTransit(MessageInTransit::kTypeMessagePipeEndpoint, - MessageInTransit::kSubtypeMessagePipeEndpointData, - num_bytes, bytes.empty() ? nullptr : &bytes[0])); + return make_scoped_ptr(new MessageInTransit( + MessageInTransit::kTypeEndpoint, MessageInTransit::kSubtypeEndpointData, + num_bytes, bytes.empty() ? nullptr : &bytes[0])); } bool CheckMessageData(const void* bytes, uint32_t num_bytes) {
diff --git a/mojo/edk/system/remote_message_pipe_unittest.cc b/mojo/edk/system/remote_message_pipe_unittest.cc index e3a320e..926ca0b 100644 --- a/mojo/edk/system/remote_message_pipe_unittest.cc +++ b/mojo/edk/system/remote_message_pipe_unittest.cc
@@ -41,6 +41,10 @@ namespace system { namespace { +const MojoHandleSignals kAllSignals = MOJO_HANDLE_SIGNAL_READABLE | + MOJO_HANDLE_SIGNAL_WRITABLE | + MOJO_HANDLE_SIGNAL_PEER_CLOSED; + class RemoteMessagePipeTest : public testing::Test { public: RemoteMessagePipeTest() : io_thread_(base::TestIOThread::kAutoStart) {} @@ -204,8 +208,7 @@ mp1->RemoveWaiter(1, &waiter, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Read from MP 1, port 1. EXPECT_EQ(MOJO_RESULT_OK, @@ -233,8 +236,7 @@ mp0->RemoveWaiter(0, &waiter, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); buffer_size = static_cast<uint32_t>(sizeof(buffer)); EXPECT_EQ(MOJO_RESULT_OK, @@ -261,8 +263,44 @@ hss = HandleSignalsState(); mp1->RemoveWaiter(1, &waiter, &hss); } - EXPECT_EQ(0u, hss.satisfied_signals); - EXPECT_EQ(0u, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); + + // And MP 1, port 1. + mp1->Close(1); +} + +TEST_F(RemoteMessagePipeTest, PeerClosed) { + Waiter waiter; + HandleSignalsState hss; + uint32_t context = 0; + + // Connect message pipes. MP 0, port 1 will be attached to channel 0 and + // connected to MP 1, port 0, which will be attached to channel 1. This leaves + // MP 0, port 0 and MP 1, port 1 as the "user-facing" endpoints. + + scoped_refptr<ChannelEndpoint> ep0; + scoped_refptr<MessagePipe> mp0(MessagePipe::CreateLocalProxy(&ep0)); + scoped_refptr<ChannelEndpoint> ep1; + scoped_refptr<MessagePipe> mp1(MessagePipe::CreateProxyLocal(&ep1)); + BootstrapChannelEndpoints(ep0, ep1); + + // Close MP 0, port 0. + mp0->Close(0); + + // Try to wait for MP 1, port 1 to be signaled with peer closed. + waiter.Init(); + hss = HandleSignalsState(); + MojoResult result = + mp1->AddWaiter(1, &waiter, MOJO_HANDLE_SIGNAL_PEER_CLOSED, 101, &hss); + if (result == MOJO_RESULT_OK) { + EXPECT_EQ(MOJO_RESULT_OK, waiter.Wait(MOJO_DEADLINE_INDEFINITE, &context)); + EXPECT_EQ(101u, context); + hss = HandleSignalsState(); + mp1->RemoveWaiter(1, &waiter, &hss); + } + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); // And MP 1, port 1. mp1->Close(1); @@ -314,8 +352,7 @@ mp1->RemoveWaiter(1, &waiter, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); ChannelEndpointId received_id; buffer_size = static_cast<uint32_t>(sizeof(received_id)); @@ -349,8 +386,7 @@ mp3->RemoveWaiter(0, &waiter, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Make sure there's nothing on MP 0, port 0 or MP 1, port 1 or MP 2, port 0. buffer_size = static_cast<uint32_t>(sizeof(buffer)); @@ -396,7 +432,7 @@ mp1->RemoveWaiter(1, &waiter, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, + EXPECT_EQ(kAllSignals | MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); // Make sure there's nothing on the other ports. @@ -606,8 +642,7 @@ mp1->RemoveWaiter(1, &waiter, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Read from MP 1, port 1. char read_buffer[100] = {0}; @@ -651,8 +686,7 @@ dispatcher->RemoveWaiter(&waiter, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Read from the dispatcher. memset(read_buffer, 0, sizeof(read_buffer)); @@ -682,8 +716,7 @@ local_mp->RemoveWaiter(1, &waiter, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Read from "local_mp", port 1. memset(read_buffer, 0, sizeof(read_buffer)); @@ -721,8 +754,7 @@ hss = local_mp->GetHandleSignalsState(0); EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Write to the other end (|local_mp|, port 1), and then close it. EXPECT_EQ( MOJO_RESULT_OK, @@ -731,8 +763,7 @@ hss = local_mp->GetHandleSignalsState(0); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Then the second message.... EXPECT_EQ( MOJO_RESULT_OK, @@ -741,8 +772,7 @@ hss = local_mp->GetHandleSignalsState(0); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Then close it. local_mp->Close(1); @@ -786,8 +816,7 @@ mp1->RemoveWaiter(1, &waiter, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Read from MP 1, port 1. char read_buffer[100] = {0}; @@ -811,8 +840,10 @@ // |dispatcher| should already be readable and not writable. hss = dispatcher->GetHandleSignalsState(); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // So read from it. memset(read_buffer, 0, sizeof(read_buffer)); read_buffer_size = static_cast<uint32_t>(sizeof(read_buffer)); @@ -824,8 +855,10 @@ EXPECT_STREQ(kHello, read_buffer); // It should still be readable. hss = dispatcher->GetHandleSignalsState(); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED, + hss.satisfiable_signals); // So read from it. memset(read_buffer, 0, sizeof(read_buffer)); read_buffer_size = static_cast<uint32_t>(sizeof(read_buffer)); @@ -837,8 +870,8 @@ EXPECT_STREQ(kWorld, read_buffer); // Now it should no longer be readable. hss = dispatcher->GetHandleSignalsState(); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_NONE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_NONE, hss.satisfiable_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfied_signals); + EXPECT_EQ(MOJO_HANDLE_SIGNAL_PEER_CLOSED, hss.satisfiable_signals); // Close everything that belongs to us. mp0->Close(0); @@ -917,8 +950,7 @@ mp1->RemoveWaiter(1, &waiter, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Read from MP 1, port 1. char read_buffer[100] = {0}; @@ -1037,8 +1069,7 @@ mp1->RemoveWaiter(1, &waiter, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Read from MP 1, port 1. char read_buffer[100] = {0}; @@ -1175,8 +1206,7 @@ mp1->RemoveWaiter(1, &waiter, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Read from MP 1, port 1. char read_buffer[100] = {0}; @@ -1235,8 +1265,7 @@ mp0->RemoveWaiter(0, &waiter, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Read from MP 0, port 0. read_buffer_size = static_cast<uint32_t>(sizeof(read_buffer)); @@ -1276,8 +1305,7 @@ dispatcher->RemoveWaiter(&waiter, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Read from the dispatcher. memset(read_buffer, 0, sizeof(read_buffer)); @@ -1307,8 +1335,7 @@ local_mp->RemoveWaiter(1, &waiter, &hss); EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals); - EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE, - hss.satisfiable_signals); + EXPECT_EQ(kAllSignals, hss.satisfiable_signals); // Read from "local_mp", port 1. memset(read_buffer, 0, sizeof(read_buffer));
diff --git a/mojo/edk/system/run_all_unittests.cc b/mojo/edk/system/run_all_unittests.cc index 3ea1682..cd613374 100644 --- a/mojo/edk/system/run_all_unittests.cc +++ b/mojo/edk/system/run_all_unittests.cc
@@ -8,9 +8,13 @@ #include "testing/gtest/include/gtest/gtest.h" int main(int argc, char** argv) { - // Silence death test thread warnings on Linux. We can afford to run our death - // tests a little more slowly (< 10 ms per death test on a Z620). +// Silence death test thread warnings on Linux. We can afford to run our death +// tests a little more slowly (< 10 ms per death test on a Z620). +// On android, we need to run in the default mode, as the threadsafe mode +// relies on execve which is not available. +#if !defined(OS_ANDROID) testing::GTEST_FLAG(death_test_style) = "threadsafe"; +#endif base::TestSuite test_suite(argc, argv);
diff --git a/mojo/edk/test/multiprocess_test_helper_unittest.cc b/mojo/edk/test/multiprocess_test_helper_unittest.cc index 2961a74f..93496fb 100644 --- a/mojo/edk/test/multiprocess_test_helper_unittest.cc +++ b/mojo/edk/test/multiprocess_test_helper_unittest.cc
@@ -42,7 +42,13 @@ typedef testing::Test MultiprocessTestHelperTest; -TEST_F(MultiprocessTestHelperTest, RunChild) { +#if defined(OS_ANDROID) +// Android multi-process tests are not executing the new process. This is flaky. +#define MAYBE_RunChild DISABLED_RunChild +#else +#define MAYBE_RunChild RunChild +#endif // defined(OS_ANDROID) +TEST_F(MultiprocessTestHelperTest, MAYBE_RunChild) { MultiprocessTestHelper helper; EXPECT_TRUE(helper.server_platform_handle.is_valid()); @@ -55,14 +61,26 @@ return 123; } -TEST_F(MultiprocessTestHelperTest, TestChildMainNotFound) { +#if defined(OS_ANDROID) +// Android multi-process tests are not executing the new process. This is flaky. +#define MAYBE_TestChildMainNotFound DISABLED_TestChildMainNotFound +#else +#define MAYBE_TestChildMainNotFound TestChildMainNotFound +#endif // defined(OS_ANDROID) +TEST_F(MultiprocessTestHelperTest, MAYBE_TestChildMainNotFound) { MultiprocessTestHelper helper; helper.StartChild("NoSuchTestChildMain"); int result = helper.WaitForChildShutdown(); EXPECT_FALSE(result >= 0 && result <= 127); } -TEST_F(MultiprocessTestHelperTest, PassedChannel) { +#if defined(OS_ANDROID) +// Android multi-process tests are not executing the new process. This is flaky. +#define MAYBE_PassedChannel DISABLED_PassedChannel +#else +#define MAYBE_PassedChannel PassedChannel +#endif // defined(OS_ANDROID) +TEST_F(MultiprocessTestHelperTest, MAYBE_PassedChannel) { MultiprocessTestHelper helper; EXPECT_TRUE(helper.server_platform_handle.is_valid()); helper.StartChild("PassedChannel"); @@ -109,7 +127,13 @@ return static_cast<int>(c); } -TEST_F(MultiprocessTestHelperTest, ChildTestPasses) { +#if defined(OS_ANDROID) +// Android multi-process tests are not executing the new process. This is flaky. +#define MAYBE_ChildTestPasses DISABLED_ChildTestPasses +#else +#define MAYBE_ChildTestPasses ChildTestPasses +#endif // defined(OS_ANDROID) +TEST_F(MultiprocessTestHelperTest, MAYBE_ChildTestPasses) { MultiprocessTestHelper helper; EXPECT_TRUE(helper.server_platform_handle.is_valid()); helper.StartChild("ChildTestPasses"); @@ -122,7 +146,13 @@ IsNonBlocking(MultiprocessTestHelper::client_platform_handle.get())); } -TEST_F(MultiprocessTestHelperTest, ChildTestFailsAssert) { +#if defined(OS_ANDROID) +// Android multi-process tests are not executing the new process. This is flaky. +#define MAYBE_ChildTestFailsAssert DISABLED_ChildTestFailsAssert +#else +#define MAYBE_ChildTestFailsAssert ChildTestFailsAssert +#endif // defined(OS_ANDROID) +TEST_F(MultiprocessTestHelperTest, MAYBE_ChildTestFailsAssert) { MultiprocessTestHelper helper; EXPECT_TRUE(helper.server_platform_handle.is_valid()); helper.StartChild("ChildTestFailsAssert"); @@ -138,7 +168,13 @@ CHECK(false) << "Not reached"; } -TEST_F(MultiprocessTestHelperTest, ChildTestFailsExpect) { +#if defined(OS_ANDROID) +// Android multi-process tests are not executing the new process. This is flaky. +#define MAYBE_ChildTestFailsExpect DISABLED_ChildTestFailsExpect +#else +#define MAYBE_ChildTestFailsExpect ChildTestFailsExpect +#endif // defined(OS_ANDROID) +TEST_F(MultiprocessTestHelperTest, MAYBE_ChildTestFailsExpect) { MultiprocessTestHelper helper; EXPECT_TRUE(helper.server_platform_handle.is_valid()); helper.StartChild("ChildTestFailsExpect");
diff --git a/mojo/public/VERSION b/mojo/public/VERSION index 282b862..eca68d9 100644 --- a/mojo/public/VERSION +++ b/mojo/public/VERSION
@@ -1 +1 @@ -5aa6dbdccf1950daf0cd3014bf763f35899bccf9 \ No newline at end of file +98d8236f7eea383e5214254c8d045df6c7a6297a \ No newline at end of file
diff --git a/mojo/public/c/system/types.h b/mojo/public/c/system/types.h index 96441dc..9b1eedc 100644 --- a/mojo/public/c/system/types.h +++ b/mojo/public/c/system/types.h
@@ -149,6 +149,7 @@ // |MOJO_RESULT_FAILED_PRECONDITION| if you attempt to wait on this. // |MOJO_HANDLE_SIGNAL_READABLE| - Can read (e.g., a message) from the handle. // |MOJO_HANDLE_SIGNAL_WRITABLE| - Can write (e.g., a message) to the handle. +// |MOJO_HANDLE_SIGNAL_PEER_CLOSED| - The peer handle is closed. typedef uint32_t MojoHandleSignals; @@ -156,10 +157,12 @@ const MojoHandleSignals MOJO_HANDLE_SIGNAL_NONE = 0; const MojoHandleSignals MOJO_HANDLE_SIGNAL_READABLE = 1 << 0; const MojoHandleSignals MOJO_HANDLE_SIGNAL_WRITABLE = 1 << 1; +const MojoHandleSignals MOJO_HANDLE_SIGNAL_PEER_CLOSED = 1 << 2; #else #define MOJO_HANDLE_SIGNAL_NONE ((MojoHandleSignals)0) #define MOJO_HANDLE_SIGNAL_READABLE ((MojoHandleSignals)1 << 0) #define MOJO_HANDLE_SIGNAL_WRITABLE ((MojoHandleSignals)1 << 1) +#define MOJO_HANDLE_SIGNAL_PEER_CLOSED ((MojoHandleSignals)1 << 2) #endif // TODO(vtl): Add out parameters with this to MojoWait/MojoWaitMany.
diff --git a/mojo/public/cpp/application/application_test_base.h b/mojo/public/cpp/application/application_test_base.h index 2f400a4..04580c7 100644 --- a/mojo/public/cpp/application/application_test_base.h +++ b/mojo/public/cpp/application/application_test_base.h
@@ -5,6 +5,7 @@ #ifndef MOJO_PUBLIC_CPP_APPLICATION_APPLICATION_TEST_BASE_H_ #define MOJO_PUBLIC_CPP_APPLICATION_APPLICATION_TEST_BASE_H_ +#include "mojo/public/cpp/application/application_delegate.h" #include "mojo/public/cpp/bindings/array.h" #include "mojo/public/cpp/bindings/string.h" #include "mojo/public/cpp/system/macros.h" @@ -12,7 +13,6 @@ namespace mojo { -class ApplicationDelegate; class ApplicationImpl; namespace test { @@ -21,28 +21,35 @@ ScopedMessagePipeHandle PassShellHandle(); void SetShellHandle(ScopedMessagePipeHandle handle); +// Access the command line arguments passed to the application test. +const Array<String>& Args(); +void InitializeArgs(int argc, std::vector<const char*> argv); + // A GTEST base class for application testing executed in mojo_shell. class ApplicationTestBase : public testing::Test { public: - explicit ApplicationTestBase(Array<String> args); + ApplicationTestBase(); ~ApplicationTestBase() override; protected: ApplicationImpl* application_impl() { return application_impl_; } // Get the ApplicationDelegate for the application to be tested. - virtual ApplicationDelegate* GetApplicationDelegate() = 0; + virtual ApplicationDelegate* GetApplicationDelegate(); + + // A testing::Test::SetUp helper to override the application command + // line arguments. + void SetUpWithArgs(const Array<String>& args); // testing::Test: void SetUp() override; void TearDown() override; private: - // The command line arguments supplied to each test application instance. - Array<String> args_; - // The application implementation instance, reconstructed for each test. ApplicationImpl* application_impl_; + // The application delegate used if GetApplicationDelegate is not overridden. + ApplicationDelegate default_application_delegate_; MOJO_DISALLOW_COPY_AND_ASSIGN(ApplicationTestBase); };
diff --git a/mojo/public/cpp/application/lib/application_test_base.cc b/mojo/public/cpp/application/lib/application_test_base.cc index 42dbda5..93eb3d0 100644 --- a/mojo/public/cpp/application/lib/application_test_base.cc +++ b/mojo/public/cpp/application/lib/application_test_base.cc
@@ -7,7 +7,6 @@ #include "mojo/public/cpp/application/application_delegate.h" #include "mojo/public/cpp/application/application_impl.h" #include "mojo/public/cpp/environment/environment.h" -#include "mojo/public/cpp/environment/logging.h" #include "mojo/public/cpp/system/message_pipe.h" namespace mojo { @@ -17,6 +16,8 @@ // This shell handle is shared by multiple test application instances. MessagePipeHandle g_shell_handle; +// Share the application command-line arguments with multiple application tests. +Array<String> g_args; } // namespace @@ -33,14 +34,29 @@ g_shell_handle = handle.release(); } -ApplicationTestBase::ApplicationTestBase(Array<String> args) - : args_(args.Pass()), application_impl_(nullptr) { +const Array<String>& Args() { + return g_args; +} + +void InitializeArgs(int argc, std::vector<const char*> argv) { + MOJO_CHECK(g_args.is_null()); + for (const char* arg : argv) { + if (arg) + g_args.push_back(arg); + } +} + +ApplicationTestBase::ApplicationTestBase() : application_impl_(nullptr) { } ApplicationTestBase::~ApplicationTestBase() { } -void ApplicationTestBase::SetUp() { +ApplicationDelegate* ApplicationTestBase::GetApplicationDelegate() { + return &default_application_delegate_; +} + +void ApplicationTestBase::SetUpWithArgs(const Array<String>& args) { // A run loop is needed for ApplicationImpl initialization and communication. Environment::InstantiateDefaultRunLoop(); @@ -49,7 +65,11 @@ PassShellHandle()); // Fake application initialization with the given command line arguments. - application_impl_->Initialize(args_.Clone()); + application_impl_->Initialize(args.Clone()); +} + +void ApplicationTestBase::SetUp() { + SetUpWithArgs(Args()); } void ApplicationTestBase::TearDown() {
diff --git a/mojo/public/cpp/application/lib/application_test_main.cc b/mojo/public/cpp/application/lib/application_test_main.cc index 6cdfb0d7..1c1395c 100644 --- a/mojo/public/cpp/application/lib/application_test_main.cc +++ b/mojo/public/cpp/application/lib/application_test_main.cc
@@ -21,14 +21,14 @@ // Construct an ApplicationImpl just for the GTEST commandline arguments. // GTEST command line arguments are supported amid application arguments: - // $ mojo_shell 'mojo:example_apptests arg1 --gtest_filter=foo arg2' + // $ mojo_shell mojo:example_apptests + // --args-for='mojo:example_apptests arg1 --gtest_filter=foo arg2' mojo::ApplicationDelegate dummy_application_delegate; mojo::ApplicationImpl app(&dummy_application_delegate, shell_handle); MOJO_CHECK(app.WaitForInitialize()); // InitGoogleTest expects (argc + 1) elements, including a terminating NULL. // It also removes GTEST arguments from |argv| and updates the |argc| count. - // TODO(msw): Provide tests access to these actual command line arguments. const std::vector<std::string>& args = app.args(); MOJO_CHECK(args.size() < static_cast<size_t>(std::numeric_limits<int>::max())); @@ -40,6 +40,7 @@ testing::InitGoogleTest(&argc, const_cast<char**>(&(argv[0]))); mojo::test::SetShellHandle(app.UnbindShell()); + mojo::test::InitializeArgs(argc, argv); } int result = RUN_ALL_TESTS();
diff --git a/mojo/public/dart/src/types.dart b/mojo/public/dart/src/types.dart index 4353d74..1dc3572 100644 --- a/mojo/public/dart/src/types.dart +++ b/mojo/public/dart/src/types.dart
@@ -122,6 +122,7 @@ static const int NONE = 0; static const int READABLE = 1 << 0; static const int WRITABLE = 1 << 1; + static const int PEER_CLOSED = 1 << 2; static const int READWRITE = READABLE | WRITABLE; static bool isNone(int mask) => mask == NONE;
diff --git a/mojo/public/go/system/impl/mojo_types.go b/mojo/public/go/system/impl/mojo_types.go index 01d518e..bd82898 100644 --- a/mojo/public/go/system/impl/mojo_types.go +++ b/mojo/public/go/system/impl/mojo_types.go
@@ -57,6 +57,7 @@ MOJO_HANDLE_SIGNAL_NONE MojoHandleSignals = 0 MOJO_HANDLE_SIGNAL_READABLE = 1 << 0 MOJO_HANDLE_SIGNAL_WRITABLE = 1 << 1 + MOJO_HANDLE_SIGNAL_PEER_CLOSED = 1 << 2 MOJO_WRITE_MESSAGE_FLAG_NONE MojoWriteMessageFlags = 0 MOJO_READ_MESSAGE_FLAG_NONE MojoReadMessageFlags = 0
diff --git a/mojo/public/interfaces/bindings/tests/BUILD.gn b/mojo/public/interfaces/bindings/tests/BUILD.gn index e56f9b5d..70aa60e 100644 --- a/mojo/public/interfaces/bindings/tests/BUILD.gn +++ b/mojo/public/interfaces/bindings/tests/BUILD.gn
@@ -11,6 +11,7 @@ "no_module.mojom", "rect.mojom", "regression_tests.mojom", + "regression_tests_import.mojom", "sample_factory.mojom", "sample_import.mojom", "sample_import2.mojom",
diff --git a/mojo/public/interfaces/bindings/tests/regression_tests.mojom b/mojo/public/interfaces/bindings/tests/regression_tests.mojom index 313f1f4d..4a85b0a 100644 --- a/mojo/public/interfaces/bindings/tests/regression_tests.mojom +++ b/mojo/public/interfaces/bindings/tests/regression_tests.mojom
@@ -7,6 +7,8 @@ [JavaPackage="org.chromium.mojo.bindings.test.mojom.regression_tests"] module regression_tests; +import "regression_tests_import.mojom"; + interface CheckMethodWithEmptyResponse { WithouParameterAndEmptyResponse() => (); WithParameterAndEmptyResponse(bool b) => (); @@ -52,3 +54,7 @@ struct B { A? a; }; + +[Client=InterfaceWithClientImportedClient] +interface InterfaceWithClientImported { +};
diff --git a/mojo/public/interfaces/bindings/tests/regression_tests_import.mojom b/mojo/public/interfaces/bindings/tests/regression_tests_import.mojom new file mode 100644 index 0000000..fbed983 --- /dev/null +++ b/mojo/public/interfaces/bindings/tests/regression_tests_import.mojom
@@ -0,0 +1,11 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Module containing entities for regression tests of the generator. Entities +// must never be modified, instead new entity must be added to add new tests. +[JavaPackage="org.chromium.mojo.bindings.test.mojom.regression_tests_import"] +module regression_tests_import; + +interface InterfaceWithClientImportedClient { +};
diff --git a/mojo/public/java/system/src/org/chromium/mojo/system/Core.java b/mojo/public/java/system/src/org/chromium/mojo/system/Core.java index d6c8e7da8..caf619aa 100644 --- a/mojo/public/java/system/src/org/chromium/mojo/system/Core.java +++ b/mojo/public/java/system/src/org/chromium/mojo/system/Core.java
@@ -33,6 +33,7 @@ private static final int FLAG_NONE = 0; private static final int FLAG_READABLE = 1 << 0; private static final int FLAG_WRITABLE = 1 << 1; + private static final int FLAG_PEER_CLOSED = 1 << 2; /** * Immutable signals. @@ -64,6 +65,16 @@ } /** + * Change the peer closed bit of this signal. + * + * @param peerClosed the new value of the peer closed bit. + * @return this. + */ + public HandleSignals setPeerClosed(boolean peerClosed) { + return setFlag(FLAG_PEER_CLOSED, peerClosed); + } + + /** * @return a signal with no bit set. */ public static HandleSignals none() {
diff --git a/mojo/public/js/core.js b/mojo/public/js/core.js index 9dcb20ff..4a67567 100644 --- a/mojo/public/js/core.js +++ b/mojo/public/js/core.js
@@ -55,6 +55,7 @@ var HANDLE_SIGNAL_NONE; var HANDLE_SIGNAL_READABLE; var HANDLE_SIGNAL_WRITABLE; +var HANDLE_SIGNAL_PEER_CLOSED; /** * MojoCreateDataMessageOptions: Used to specify creation parameters for a data
diff --git a/mojo/public/mojo_application.gni b/mojo/public/mojo_application.gni index 83b96a2..05ec369 100644 --- a/mojo/public/mojo_application.gni +++ b/mojo/public/mojo_application.gni
@@ -125,3 +125,62 @@ outputs = [ "${root_out_dir}/${output}" ] } } + +if (is_android) { + # Declares an Android Mojo application consisting of an .so file and a + # corresponding .dex.jar file. + # + # Variables: + # input_so: the .so file to bundle + # input_dex_jar: the .dex.jar file to bundle + # output_name (optional): override for the output file name + template("mojo_android_application") { + assert(defined(invoker.input_so)) + assert(defined(invoker.input_dex_jar)) + + zip_action_name = "${target_name}_zip" + zip_action_output = "$target_gen_dir/${target_name}.zip" + action(zip_action_name) { + script = "//build/android/gn/zip.py" + + inputs = [ + invoker.input_so, + invoker.input_dex_jar, + ] + + output = zip_action_output + outputs = [ output ] + + rebase_inputs = rebase_path(inputs, root_build_dir) + rebase_output = rebase_path(output, root_build_dir) + args = [ + "--inputs=$rebase_inputs", + "--output=$rebase_output", + ] + } + + if (defined(invoker.output_name)) { + mojo_output = "$target_out_dir/" + invoker.output_name + ".mojo" + } else { + mojo_output = "$target_out_dir/" + target_name + ".mojo" + } + + action(target_name) { + script = "//mojo/public/tools/prepend.py" + + input = zip_action_output + inputs = [ input ] + + output = mojo_output + outputs = [ output ] + + rebase_input = rebase_path(input, root_build_dir) + rebase_output = rebase_path(output, root_build_dir) + args = [ + "--input=$rebase_input", + "--output=$rebase_output", + "--line=#!mojo:android_handler", + ] + } + } +}
diff --git a/mojo/public/mojo_public.gyp b/mojo/public/mojo_public.gyp index f19e263..83e27d8 100644 --- a/mojo/public/mojo_public.gyp +++ b/mojo/public/mojo_public.gyp
@@ -237,11 +237,9 @@ ], 'dependencies': [ 'mojo_application_bindings', - 'mojo_application_bindings_mojom', ], 'export_dependent_settings': [ 'mojo_application_bindings', - 'mojo_application_bindings_mojom', ], }, { @@ -331,6 +329,7 @@ 'interfaces/bindings/tests/no_module.mojom', 'interfaces/bindings/tests/rect.mojom', 'interfaces/bindings/tests/regression_tests.mojom', + 'interfaces/bindings/tests/regression_tests_import.mojom', 'interfaces/bindings/tests/sample_factory.mojom', 'interfaces/bindings/tests/sample_import.mojom', 'interfaces/bindings/tests/sample_import2.mojom',
diff --git a/mojo/public/python/mojo/bindings/descriptor.py b/mojo/public/python/mojo/bindings/descriptor.py index f190d2be..0df0bd60 100644 --- a/mojo/public/python/mojo/bindings/descriptor.py +++ b/mojo/public/python/mojo/bindings/descriptor.py
@@ -72,7 +72,7 @@ """ raise NotImplementedError() - def Deserialize(self, value, data, handles): + def Deserialize(self, value, context): """ Deserialize a value of this type. @@ -106,7 +106,7 @@ def Serialize(self, value, data_offset, data, handle_offset): return (value, []) - def Deserialize(self, value, data, handles): + def Deserialize(self, value, context): return value @@ -161,21 +161,31 @@ return (0, []) return self.SerializePointer(value, data_offset, data, handle_offset) - def Deserialize(self, value, data, handles): + def Deserialize(self, value, context): if value == 0: if not self.nullable: raise serialization.DeserializationException( 'Trying to deserialize null for non nullable type.') return None - pointed_data = buffer(data, value) - (size, nb_elements) = serialization.HEADER_STRUCT.unpack_from(pointed_data) - return self.DeserializePointer(size, nb_elements, pointed_data, handles) + if value % 8 != 0: + raise serialization.DeserializationException( + 'Pointer alignment is incorrect.') + sub_context = context.GetSubContext(value) + if len(sub_context.data) < serialization.HEADER_STRUCT.size: + raise serialization.DeserializationException( + 'Available data too short to contain header.') + (size, nb_elements) = serialization.HEADER_STRUCT.unpack_from( + sub_context.data) + if len(sub_context.data) < size or size < serialization.HEADER_STRUCT.size: + raise serialization.DeserializationException('Header size is incorrect.') + sub_context.ClaimMemory(0, size) + return self.DeserializePointer(size, nb_elements, sub_context) def SerializePointer(self, value, data_offset, data, handle_offset): """Serialize the not null value.""" raise NotImplementedError() - def DeserializePointer(self, size, nb_elements, data, handles): + def DeserializePointer(self, size, nb_elements, context): raise NotImplementedError() @@ -204,9 +214,8 @@ return self._array_type.SerializeArray( string_array, data_offset, data, handle_offset) - def DeserializePointer(self, size, nb_elements, data, handles): - string_array = self._array_type.DeserializeArray( - size, nb_elements, data, handles) + def DeserializePointer(self, size, nb_elements, context): + string_array = self._array_type.DeserializeArray(size, nb_elements, context) return unicode(string_array.tostring(), 'utf8') @@ -226,14 +235,13 @@ return (-1, []) return (handle_offset, [handle]) - def Deserialize(self, value, data, handles): + def Deserialize(self, value, context): if value == -1: if not self.nullable: raise serialization.DeserializationException( 'Trying to deserialize null for non nullable type.') return self.FromHandle(mojo.system.Handle()) - # TODO(qsr) validate handle order - return self.FromHandle(handles[value]) + return self.FromHandle(context.ClaimHandle(value)) def FromHandle(self, handle): raise NotImplementedError() @@ -326,12 +334,18 @@ """Serialize the not null array.""" raise NotImplementedError() - def DeserializePointer(self, size, nb_elements, data, handles): - if self.length != 0 and size != self.length: + def DeserializePointer(self, size, nb_elements, context): + if self.length != 0 and nb_elements != self.length: raise serialization.DeserializationException('Incorrect array size') - return self.DeserializeArray(size, nb_elements, data, handles) + if (size < + serialization.HEADER_STRUCT.size + self.SizeForLength(nb_elements)): + raise serialization.DeserializationException('Incorrect array size') + return self.DeserializeArray(size, nb_elements, context) - def DeserializeArray(self, size, nb_elements, data, handles): + def DeserializeArray(self, size, nb_elements, context): + raise NotImplementedError() + + def SizeForLength(self, nb_elements): raise NotImplementedError() @@ -351,9 +365,8 @@ converted = array.array('B', [_ConvertBooleansToByte(x) for x in groups]) return _SerializeNativeArray(converted, data_offset, data, len(value)) - def DeserializeArray(self, size, nb_elements, data, handles): - converted = self._array_type.DeserializeArray( - size, nb_elements, data, handles) + def DeserializeArray(self, size, nb_elements, context): + converted = self._array_type.DeserializeArray(size, nb_elements, context) elements = list(itertools.islice( itertools.chain.from_iterable( [_ConvertByteToBooleans(x, 8) for x in converted]), @@ -361,6 +374,9 @@ nb_elements)) return elements + def SizeForLength(self, nb_elements): + return (nb_elements + 7) // 8 + class GenericArrayType(BaseArrayType): """Type object for arrays of pointers.""" @@ -400,18 +416,22 @@ *to_pack) return (data_offset, returned_handles) - def DeserializeArray(self, size, nb_elements, data, handles): + def DeserializeArray(self, size, nb_elements, context): values = struct.unpack_from( '%d%s' % (nb_elements, self.sub_type.GetTypeCode()), - buffer(data, serialization.HEADER_STRUCT.size)) + buffer(context.data, serialization.HEADER_STRUCT.size)) result = [] - position = serialization.HEADER_STRUCT.size + sub_context = context.GetSubContext(serialization.HEADER_STRUCT.size) for value in values: - result.append( - self.sub_type.Deserialize(value, buffer(data, position), handles)) - position += self.sub_type.GetByteSize() + result.append(self.sub_type.Deserialize( + value, + sub_context)) + sub_context = sub_context.GetSubContext(self.sub_type.GetByteSize()) return result + def SizeForLength(self, nb_elements): + return nb_elements * self.sub_type.GetByteSize(); + class NativeArrayType(BaseArrayType): """Type object for arrays of native types.""" @@ -419,6 +439,7 @@ def __init__(self, typecode, nullable=False, length=0): BaseArrayType.__init__(self, nullable, length) self.array_typecode = typecode + self.element_size = struct.calcsize('<%s' % self.array_typecode) def Convert(self, value): if value is None: @@ -431,13 +452,16 @@ def SerializeArray(self, value, data_offset, data, handle_offset): return _SerializeNativeArray(value, data_offset, data, len(value)) - def DeserializeArray(self, size, nb_elements, data, handles): + def DeserializeArray(self, size, nb_elements, context): result = array.array(self.array_typecode) - result.fromstring(buffer(data, + result.fromstring(buffer(context.data, serialization.HEADER_STRUCT.size, size - serialization.HEADER_STRUCT.size)) return result + def SizeForLength(self, nb_elements): + return nb_elements * self.element_size + class StructType(PointerType): """Type object for structs.""" @@ -469,8 +493,8 @@ data.extend(new_data) return (data_offset, new_handles) - def DeserializePointer(self, size, nb_elements, data, handles): - return self.struct_type.Deserialize(data, handles) + def DeserializePointer(self, size, nb_elements, context): + return self.struct_type.Deserialize(context) class MapType(SerializableType): @@ -511,8 +535,8 @@ s = self.struct(keys=keys, values=values) return self.struct_type.Serialize(s, data_offset, data, handle_offset) - def Deserialize(self, value, data, handles): - s = self.struct_type.Deserialize(value, data, handles) + def Deserialize(self, value, context): + s = self.struct_type.Deserialize(value, context) if s: if len(s.keys) != len(s.values): raise serialization.DeserializationException( @@ -590,7 +614,7 @@ def Serialize(self, obj, data_offset, data, handle_offset): raise NotImplementedError() - def Deserialize(self, value, data, handles): + def Deserialize(self, value, context): raise NotImplementedError() @@ -615,8 +639,8 @@ value = getattr(obj, self.name) return self.field_type.Serialize(value, data_offset, data, handle_offset) - def Deserialize(self, value, data, handles): - entity = self.field_type.Deserialize(value, data, handles) + def Deserialize(self, value, context): + entity = self.field_type.Deserialize(value, context) return { self.name: entity } @@ -640,7 +664,7 @@ [getattr(obj, field.name) for field in self.GetDescriptors()]) return (value, []) - def Deserialize(self, value, data, handles): + def Deserialize(self, value, context): values = itertools.izip_longest([x.name for x in self.descriptors], _ConvertByteToBooleans(value), fillvalue=False) @@ -663,7 +687,7 @@ def _ConvertByteToBooleans(value, min_size=0): - "Unpack an integer into a list of booleans.""" + """Unpack an integer into a list of booleans.""" res = [] while value: res.append(bool(value&1))
diff --git a/mojo/public/python/mojo/bindings/reflection.py b/mojo/public/python/mojo/bindings/reflection.py index 5ca38bf..9668c2a3 100644 --- a/mojo/public/python/mojo/bindings/reflection.py +++ b/mojo/public/python/mojo/bindings/reflection.py
@@ -117,10 +117,10 @@ return self._fields dictionary['AsDict'] = AsDict - def Deserialize(cls, data, handles): + def Deserialize(cls, context): result = cls.__new__(cls) fields = {} - serialization_object.Deserialize(fields, data, handles) + serialization_object.Deserialize(fields, context) result._fields = fields return result dictionary['Deserialize'] = classmethod(Deserialize) @@ -476,8 +476,9 @@ try: assert message.header.message_type == method.ordinal payload = message.payload - response = method.response_struct.Deserialize(payload.data, - payload.handles) + response = method.response_struct.Deserialize( + serialization.RootDeserializationContext(payload.data, + payload.handles)) as_dict = response.AsDict() if len(as_dict) == 1: value = as_dict.values()[0] @@ -533,7 +534,8 @@ method = methods_by_ordinal[header.message_type] payload = message.payload parameters = method.parameters_struct.Deserialize( - payload.data, payload.handles).AsDict() + serialization.RootDeserializationContext( + payload.data, payload.handles)).AsDict() response = getattr(self.impl, method.name)(**parameters) if header.expects_response: def SendResponse(response):
diff --git a/mojo/public/python/mojo/bindings/serialization.py b/mojo/public/python/mojo/bindings/serialization.py index 2c0478f..b5ea1bd 100644 --- a/mojo/public/python/mojo/bindings/serialization.py +++ b/mojo/public/python/mojo/bindings/serialization.py
@@ -21,6 +21,68 @@ pass +class DeserializationContext(object): + + def ClaimHandle(self, handle): + raise NotImplementedError() + + def ClaimMemory(self, start, size): + raise NotImplementedError() + + def GetSubContext(self, offset): + raise NotImplementedError() + + def IsInitialContext(self): + raise NotImplementedError() + + +class RootDeserializationContext(DeserializationContext): + def __init__(self, data, handles): + if isinstance(data, buffer): + self.data = data + else: + self.data = buffer(data) + self._handles = handles + self._next_handle = 0; + self._next_memory = 0; + + def ClaimHandle(self, handle): + if handle < self._next_handle: + raise DeserializationException('Accessing handles out of order.') + self._next_handle = handle + 1 + return self._handles[handle] + + def ClaimMemory(self, start, size): + if start < self._next_memory: + raise DeserializationException('Accessing buffer out of order.') + self._next_memory = start + size + + def GetSubContext(self, offset): + return _ChildDeserializationContext(self, offset) + + def IsInitialContext(self): + return True + + +class _ChildDeserializationContext(DeserializationContext): + def __init__(self, parent, offset): + self._parent = parent + self._offset = offset + self.data = buffer(parent.data, offset) + + def ClaimHandle(self, handle): + return self._parent.ClaimHandle(handle) + + def ClaimMemory(self, start, size): + return self._parent.ClaimMemory(self._offset + start, size) + + def GetSubContext(self, offset): + return self._parent.GetSubContext(self._offset + offset) + + def IsInitialContext(self): + return False + + class Serialization(object): """ Helper class to serialize/deserialize a struct. @@ -78,18 +140,23 @@ self._GetMainStruct().pack_into(data, HEADER_STRUCT.size, *to_pack) return (data, handles) - def Deserialize(self, fields, data, handles): - if not isinstance(data, buffer): - data = buffer(data) - (_, version) = HEADER_STRUCT.unpack_from(data) + def Deserialize(self, fields, context): + if len(context.data) < HEADER_STRUCT.size: + raise DeserializationException( + 'Available data too short to contain header.') + (size, version) = HEADER_STRUCT.unpack_from(context.data) + if len(context.data) < size or size < HEADER_STRUCT.size: + raise DeserializationException('Header size is incorrect.') + if context.IsInitialContext(): + context.ClaimMemory(0, size) version_struct = self._GetStruct(version) - entitities = version_struct.unpack_from(data, HEADER_STRUCT.size) + entitities = version_struct.unpack_from(context.data, HEADER_STRUCT.size) filtered_groups = self._GetGroups(version) position = HEADER_STRUCT.size for (group, value) in zip(filtered_groups, entitities): position = position + NeededPaddingForAlignment(position, group.GetByteSize()) - fields.update(group.Deserialize(value, buffer(data, position), handles)) + fields.update(group.Deserialize(value, context.GetSubContext(position))) position += group.GetByteSize()
diff --git a/mojo/public/python/mojo/c_core.pxd b/mojo/public/python/mojo/c_core.pxd index 1526dfe..fe10fff4 100644 --- a/mojo/public/python/mojo/c_core.pxd +++ b/mojo/public/python/mojo/c_core.pxd
@@ -56,6 +56,7 @@ const MojoHandleSignals MOJO_HANDLE_SIGNAL_NONE const MojoHandleSignals MOJO_HANDLE_SIGNAL_READABLE const MojoHandleSignals MOJO_HANDLE_SIGNAL_WRITABLE + const MojoHandleSignals MOJO_HANDLE_SIGNAL_PEER_CLOSED # functions.h MojoTimeTicks MojoGetTimeTicksNow()
diff --git a/mojo/public/python/mojo/system.pyx b/mojo/public/python/mojo/system.pyx index 4507d4d..f0a814a 100644 --- a/mojo/public/python/mojo/system.pyx +++ b/mojo/public/python/mojo/system.pyx
@@ -53,6 +53,7 @@ HANDLE_SIGNAL_NONE = c_core.MOJO_HANDLE_SIGNAL_NONE HANDLE_SIGNAL_READABLE = c_core.MOJO_HANDLE_SIGNAL_READABLE HANDLE_SIGNAL_WRITABLE = c_core.MOJO_HANDLE_SIGNAL_WRITABLE +HANDLE_SIGNAL_PEER_CLOSED = c_core.MOJO_HANDLE_SIGNAL_PEER_CLOSED WRITE_MESSAGE_FLAG_NONE = c_core.MOJO_WRITE_MESSAGE_FLAG_NONE READ_MESSAGE_FLAG_NONE = c_core.MOJO_READ_MESSAGE_FLAG_NONE READ_MESSAGE_FLAG_MAY_DISCARD = c_core.MOJO_READ_MESSAGE_FLAG_MAY_DISCARD
diff --git a/mojo/public/tools/bindings/generators/mojom_java_generator.py b/mojo/public/tools/bindings/generators/mojom_java_generator.py index 4bede9a..19f4631 100644 --- a/mojo/public/tools/bindings/generators/mojom_java_generator.py +++ b/mojo/public/tools/bindings/generators/mojom_java_generator.py
@@ -429,9 +429,14 @@ exports = self.GetJinjaExports() exports.update({'interface': interface}) if interface.client: - for client in self.module.interfaces: - if client.name == interface.client: - exports.update({'client': client}) + all_interfaces = [] + self.module.interfaces + for each in self.module.imports: + all_interfaces += each['module'].interfaces + interfaces_by_name = dict((x.name, x) for x in all_interfaces) + assert interface.client in interfaces_by_name, ( + 'Unable to find interface %s declared as client of %s.' % + (interface.client, interface.name)) + exports.update({'client': interfaces_by_name[interface.client]}) return exports @UseJinja('java_templates/enum.java.tmpl', filters=java_filters)
diff --git a/mojo/public/tools/bindings/generators/mojom_python_generator.py b/mojo/public/tools/bindings/generators/mojom_python_generator.py index f93da091..33bfdd57 100644 --- a/mojo/public/tools/bindings/generators/mojom_python_generator.py +++ b/mojo/public/tools/bindings/generators/mojom_python_generator.py
@@ -8,6 +8,7 @@ from itertools import ifilter import mojom.generate.generator as generator +import mojom.generate.data as data import mojom.generate.module as mojom from mojom.generate.template_expander import UseJinja @@ -318,8 +319,9 @@ """ interfaces = self.module.interfaces all_interfaces = [] + interfaces - for each in self.module.imports: - all_interfaces += each['module'].interfaces + for each in self.GetImports(): + all_interfaces += [data.KindFromImport(x, each) for x in + each['module'].interfaces]; interfaces_by_name = dict((x.name, x) for x in all_interfaces) for interface in interfaces: if interface.client:
diff --git a/mojo/public/tools/bindings/mojom_bindings_generator.py b/mojo/public/tools/bindings/mojom_bindings_generator.py index 7dc9067..cb3b1d1 100755 --- a/mojo/public/tools/bindings/mojom_bindings_generator.py +++ b/mojo/public/tools/bindings/mojom_bindings_generator.py
@@ -93,36 +93,19 @@ def __init__(self, should_generate): self._should_generate = should_generate self._processed_files = {} + self._parsed_files = {} - def ProcessFile(self, args, remaining_args, generator_modules, filename, - _imported_filename_stack=None): - # Memoized results. + def ProcessFile(self, args, remaining_args, generator_modules, filename): + self._ParseFileAndImports(filename, args.import_directories, []) + + return self._GenerateModule(args, remaining_args, generator_modules, + filename) + + def _GenerateModule(self, args, remaining_args, generator_modules, filename): + # Return the already-generated module. if filename in self._processed_files: return self._processed_files[filename] - - if _imported_filename_stack is None: - _imported_filename_stack = [] - - # Ensure we only visit each file once. - if filename in _imported_filename_stack: - print "%s: Error: Circular dependency" % filename + \ - MakeImportStackMessage(_imported_filename_stack + [filename]) - sys.exit(1) - - try: - with open(filename) as f: - source = f.read() - except IOError as e: - print "%s: Error: %s" % (e.filename, e.strerror) + \ - MakeImportStackMessage(_imported_filename_stack + [filename]) - sys.exit(1) - - try: - tree = Parse(source, filename) - except Error as e: - full_stack = _imported_filename_stack + [filename] - print str(e) + MakeImportStackMessage(full_stack) - sys.exit(1) + tree = self._parsed_files[filename] dirname, name = os.path.split(filename) mojom = Translate(tree, name) @@ -135,9 +118,8 @@ import_filename = FindImportFile(dirname, import_data['filename'], args.import_directories) - import_data['module'] = self.ProcessFile( - args, remaining_args, generator_modules, import_filename, - _imported_filename_stack=_imported_filename_stack + [filename]) + import_data['module'] = self._GenerateModule( + args, remaining_args, generator_modules, import_filename) module = OrderedModuleFromData(mojom) @@ -162,6 +144,42 @@ self._processed_files[filename] = module return module + def _ParseFileAndImports(self, filename, import_directories, + imported_filename_stack): + # Ignore already-parsed files. + if filename in self._parsed_files: + return + + if filename in imported_filename_stack: + print "%s: Error: Circular dependency" % filename + \ + MakeImportStackMessage(imported_filename_stack + [filename]) + sys.exit(1) + + try: + with open(filename) as f: + source = f.read() + except IOError as e: + print "%s: Error: %s" % (e.filename, e.strerror) + \ + MakeImportStackMessage(imported_filename_stack + [filename]) + sys.exit(1) + + try: + tree = Parse(source, filename) + except Error as e: + full_stack = imported_filename_stack + [filename] + print str(e) + MakeImportStackMessage(full_stack) + sys.exit(1) + + dirname = os.path.split(filename)[0] + for imp_entry in tree.import_list: + import_filename = FindImportFile(dirname, + imp_entry.import_filename, import_directories) + self._ParseFileAndImports(import_filename, import_directories, + imported_filename_stack + [filename]) + + self._parsed_files[filename] = tree + + def main(): parser = argparse.ArgumentParser( description="Generate bindings from mojom files.")
diff --git a/mojo/public/tools/bindings/mojom_bindings_generator_explicit.gypi b/mojo/public/tools/bindings/mojom_bindings_generator_explicit.gypi index 68348fb..512e22f 100644 --- a/mojo/public/tools/bindings/mojom_bindings_generator_explicit.gypi +++ b/mojo/public/tools/bindings/mojom_bindings_generator_explicit.gypi
@@ -13,6 +13,10 @@ '<!@(python <(DEPTH)/mojo/public/tools/bindings/mojom_list_outputs.py --basedir <(mojom_base_output_dir) <@(mojom_files))', ], }, + # Given mojom files as inputs, generate sources. These sources will be + # exported to another target (via dependent_settings) to be compiled. This + # keeps code generation separate from compilation, allowing the same sources + # to be compiled with multiple toolchains - target, NaCl, etc. 'actions': [ { 'action_name': '<(_target_name)_mojom_bindings_generator', @@ -39,10 +43,11 @@ '--java_output_directory=<(java_out_dir)', ], 'message': 'Generating Mojo bindings from <@(mojom_files)', - 'process_outputs_as_sources': 1, } ], 'direct_dependent_settings': { + # A target directly depending on this action will compile the generated + # sources. 'sources': [ '<@(mojom_generated_outputs)', ], @@ -51,6 +56,9 @@ '<(DEPTH)', '<(SHARED_INTERMEDIATE_DIR)', ], + # Make sure the generated header files are available for any static library + # that depends on a static library that depends on this generator. + 'hard_dependency': 1, 'direct_dependent_settings': { # Include paths needed to find the generated header files and their # transitive dependancies when using the library. @@ -59,11 +67,10 @@ '<(SHARED_INTERMEDIATE_DIR)', ], 'variables': { - 'generated_src_dirs': [ - '<(PRODUCT_DIR)/java_mojo/<(_target_name)/src', - ], + 'generated_src_dirs': [ + '<(PRODUCT_DIR)/java_mojo/<(_target_name)/src', + ], }, } }, - 'hard_dependency': 1, }
diff --git a/mojo/public/tools/prepend.py b/mojo/public/tools/prepend.py new file mode 100755 index 0000000..de70a82 --- /dev/null +++ b/mojo/public/tools/prepend.py
@@ -0,0 +1,37 @@ +#!/usr/bin/env python +# +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +""" +Prepends a given file with a given line. This can be used to add a shebang line +to a generated file. +""" + +import optparse +import os +import shutil +import sys + + +def main(): + parser = optparse.OptionParser() + parser.add_option('--input', help='The file to prepend the line to.') + parser.add_option('--line', help='The line to be prepended.') + parser.add_option('--output', help='The output file.') + + options, _ = parser.parse_args() + input_path = options.input + output_path = options.output + line = options.line + + # Warning - this reads all of the input file into memory. + with open(output_path, 'w') as output_file: + output_file.write(line + '\n') + with open(input_path, 'r') as input_file: + shutil.copyfileobj(input_file, output_file) + + +if __name__ == '__main__': + sys.exit(main())
diff --git a/mojo/services/public/cpp/geometry/BUILD.gn b/mojo/services/public/cpp/geometry/BUILD.gn index 1556d06..bf2b577 100644 --- a/mojo/services/public/cpp/geometry/BUILD.gn +++ b/mojo/services/public/cpp/geometry/BUILD.gn
@@ -6,4 +6,6 @@ sources = [ "geometry_util.h", ] + + deps = [ "//mojo/services/public/interfaces/geometry" ] }
diff --git a/mojo/services/public/cpp/network/BUILD.gn b/mojo/services/public/cpp/network/BUILD.gn index 045c0b7..f8db162d 100644 --- a/mojo/services/public/cpp/network/BUILD.gn +++ b/mojo/services/public/cpp/network/BUILD.gn
@@ -3,15 +3,6 @@ # found in the LICENSE file. source_set("network") { - deps = [ - "//base", - "//mojo/application", - "//mojo/common", - "//mojo/environment:chromium", - "//mojo/public/c/system:for_component", - "//mojo/services/public/interfaces/network", - ] - sources = [ "udp_socket_wrapper.cc", "udp_socket_wrapper.h", @@ -20,4 +11,14 @@ "web_socket_write_queue.cc", "web_socket_write_queue.h", ] + + deps = [ + "//base", + "//mojo/application", + "//mojo/common", + "//mojo/environment:chromium", + "//mojo/public/c/system:for_component", + "//mojo/public/cpp/system", + "//mojo/services/public/interfaces/network", + ] }
diff --git a/mojo/services/public/interfaces/gpu/BUILD.gn b/mojo/services/public/interfaces/gpu/BUILD.gn index efb72a5..8fe2f9c 100644 --- a/mojo/services/public/interfaces/gpu/BUILD.gn +++ b/mojo/services/public/interfaces/gpu/BUILD.gn
@@ -9,6 +9,7 @@ "command_buffer.mojom", "gpu.mojom", "gpu_capabilities.mojom", + "viewport_parameter_listener.mojom", ] deps = [
diff --git a/mojo/services/public/interfaces/gpu/gpu.mojom b/mojo/services/public/interfaces/gpu/gpu.mojom index c3d473d1..a765c1c 100644 --- a/mojo/services/public/interfaces/gpu/gpu.mojom +++ b/mojo/services/public/interfaces/gpu/gpu.mojom
@@ -6,8 +6,12 @@ import "mojo/services/public/interfaces/geometry/geometry.mojom"; import "mojo/services/public/interfaces/gpu/command_buffer.mojom"; +import "mojo/services/public/interfaces/gpu/viewport_parameter_listener.mojom"; interface Gpu { - CreateOnscreenGLES2Context(uint64 native_viewport_id, Size? size, CommandBuffer&? gles2_client); + CreateOnscreenGLES2Context(uint64 native_viewport_id, + Size? size, + CommandBuffer&? gles2_client, + ViewportParameterListener? listener); CreateOffscreenGLES2Context(CommandBuffer&? gles2_client); };
diff --git a/mojo/services/public/interfaces/gpu/gpu_capabilities.mojom b/mojo/services/public/interfaces/gpu/gpu_capabilities.mojom index 2450139..ef28389 100644 --- a/mojo/services/public/interfaces/gpu/gpu_capabilities.mojom +++ b/mojo/services/public/interfaces/gpu/gpu_capabilities.mojom
@@ -51,4 +51,5 @@ bool future_sync_points; bool blend_equation_advanced; bool blend_equation_advanced_coherent; + bool texture_rg; };
diff --git a/mojo/services/public/interfaces/gpu/viewport_parameter_listener.mojom b/mojo/services/public/interfaces/gpu/viewport_parameter_listener.mojom new file mode 100644 index 0000000..5afa931 --- /dev/null +++ b/mojo/services/public/interfaces/gpu/viewport_parameter_listener.mojom
@@ -0,0 +1,12 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +module mojo; + +interface ViewportParameterListener { + // These parameters describe the refresh rate of the viewport. The viewport + // refreshes every |interval| time ticks. The phase of the refresh is + // indicated by |timebase|, which is synchronized with MojoGetTimeTicksNow. + OnVSyncParametersUpdated(int64 timebase, int64 interval); +};
diff --git a/mojo/services/public/interfaces/surfaces/surfaces.mojom b/mojo/services/public/interfaces/surfaces/surfaces.mojom index 21149ab..0df7ea4c 100644 --- a/mojo/services/public/interfaces/surfaces/surfaces.mojom +++ b/mojo/services/public/interfaces/surfaces/surfaces.mojom
@@ -6,6 +6,7 @@ import "mojo/services/public/interfaces/geometry/geometry.mojom"; import "mojo/services/public/interfaces/gpu/command_buffer.mojom"; +import "mojo/services/public/interfaces/gpu/viewport_parameter_listener.mojom"; import "mojo/services/public/interfaces/surfaces/quads.mojom"; import "mojo/services/public/interfaces/surfaces/surface_id.mojom"; @@ -61,11 +62,15 @@ // connection's namespace in the upper 32 bits. CreateSurface(SurfaceId id, Size size); - // The client can only submit frames to surfaces created with this connection. - SubmitFrame(SurfaceId id, Frame frame); + // The client can only submit frames to surfaces created with this + // connection. After the submitted frame is drawn for the first time, the + // surface will respond to the SubmitFrame message. Clients should use this + // acknowledgement to ratelimit frame submissions. + SubmitFrame(SurfaceId id, Frame frame) => (); DestroySurface(SurfaceId id); CreateGLES2BoundSurface(CommandBuffer gles2_client, SurfaceId id, - Size size); + Size size, + ViewportParameterListener& listener); };
diff --git a/mojo/services/public/mojo_services_public.gyp b/mojo/services/public/mojo_services_public.gyp index 701d7e5..aab34f97 100644 --- a/mojo/services/public/mojo_services_public.gyp +++ b/mojo/services/public/mojo_services_public.gyp
@@ -83,6 +83,7 @@ 'interfaces/gpu/command_buffer.mojom', 'interfaces/gpu/gpu.mojom', 'interfaces/gpu/gpu_capabilities.mojom', + 'interfaces/gpu/viewport_parameter_listener.mojom', ], 'includes': [ '../../public/tools/bindings/mojom_bindings_generator.gypi' ], 'dependencies': [
diff --git a/native_client_sdk/src/build_tools/build_paths.py b/native_client_sdk/src/build_tools/build_paths.py index f24070b..7b4ccce99 100644 --- a/native_client_sdk/src/build_tools/build_paths.py +++ b/native_client_sdk/src/build_tools/build_paths.py
@@ -15,6 +15,7 @@ NACL_DIR = os.path.join(SRC_DIR, 'native_client') OUT_DIR = os.path.join(SRC_DIR, 'out') BUILD_ARCHIVE_DIR = os.path.join(OUT_DIR, 'nacl_sdk_build') +EXTRACT_ARCHIVE_DIR = os.path.join(OUT_DIR, 'nacl_sdk_extract') PPAPI_DIR = os.path.join(SRC_DIR, 'ppapi') NACLPORTS_DIR = os.path.join(OUT_DIR, 'naclports') GONACL_APPENGINE_DIR = os.path.join(SDK_SRC_DIR, 'gonacl_appengine')
diff --git a/native_client_sdk/src/build_tools/extract_artifacts.py b/native_client_sdk/src/build_tools/extract_artifacts.py new file mode 100755 index 0000000..f1748b4 --- /dev/null +++ b/native_client_sdk/src/build_tools/extract_artifacts.py
@@ -0,0 +1,162 @@ +#!/usr/bin/env python +# 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. + +import argparse +import glob +import os +import sys + +if sys.version_info < (2, 7, 0): + sys.stderr.write("python 2.7 or later is required run this script\n") + sys.exit(1) + +import buildbot_common +import build_paths +from build_paths import NACL_DIR, SDK_SRC_DIR, EXTRACT_ARCHIVE_DIR + +sys.path.append(os.path.join(SDK_SRC_DIR, 'tools')) + +import getos +import oshelpers + +# TODO(binji): The artifacts should be downloaded; until then, point at the +# directory where the artifacts are built. +DOWNLOAD_ARCHIVE_DIR = build_paths.BUILD_ARCHIVE_DIR + +PLATFORM = getos.GetPlatform() +NEWLIB_X86_TC_DIR = os.path.join('toolchain', '%s_x86_newlib' % PLATFORM) +NEWLIB_ARM_TC_DIR = os.path.join('toolchain', '%s_arm_newlib' % PLATFORM) +GLIBC_X86_TC_DIR = os.path.join('toolchain', '%s_x86_glibc' % PLATFORM) +PNACL_TC_DIR = os.path.join('toolchain', '%s_pnacl' % PLATFORM) +PNACL_TRANSLATOR_DIR = os.path.join(PNACL_TC_DIR, 'translator') +BIONIC_TC_DIR = os.path.join('toolchain', '%s_arm_bionic' % PLATFORM) + +CYGTAR = os.path.join(NACL_DIR, 'build', 'cygtar.py') +TAR = oshelpers.FindExeInPath('tar') + +options = None + + +PPAPI_ARCHIVE = os.path.join(DOWNLOAD_ARCHIVE_DIR, + '%s_ppapi.tar.bz2' % PLATFORM) + + +NEWLIB_ARCHIVE_MAP = [ + ('newlib', NEWLIB_X86_TC_DIR), + ('arm', NEWLIB_ARM_TC_DIR), + ('newlib_headers', [ + os.path.join(NEWLIB_X86_TC_DIR, 'x86_64-nacl', 'include'), + os.path.join(NEWLIB_ARM_TC_DIR, 'arm-nacl', 'include')]), + ('newlib_arm_libs', os.path.join(NEWLIB_ARM_TC_DIR, 'arm-nacl', 'lib')), + ('newlib_x86_32_libs', + os.path.join(NEWLIB_X86_TC_DIR, 'x86_64-nacl', 'lib32')), + ('newlib_x86_64_libs', os.path.join(NEWLIB_X86_TC_DIR, 'x86_64-nacl', 'lib'))] + +GLIBC_ARCHIVE_MAP = [ + ('glibc', GLIBC_X86_TC_DIR), + ('glibc_headers', os.path.join(GLIBC_X86_TC_DIR, 'x86_64-nacl', 'include')), + ('glibc_x86_32_libs', os.path.join(GLIBC_X86_TC_DIR, 'x86_64-nacl', 'lib32')), + ('glibc_x86_64_libs', os.path.join(GLIBC_X86_TC_DIR, 'x86_64-nacl', 'lib'))] + +PNACL_ARCHIVE_MAP = [ + ('pnacl', PNACL_TC_DIR), + ('newlib_headers', os.path.join(PNACL_TC_DIR, 'le32-nacl', 'include')), + ('pnacl_libs', os.path.join(PNACL_TC_DIR, 'le32-nacl', 'lib')), + ('pnacl_translator_arm_libs', + os.path.join(PNACL_TRANSLATOR_DIR, 'arm', 'lib')), + ('pnacl_translator_x86_32_libs', + os.path.join(PNACL_TRANSLATOR_DIR, 'x86-32', 'lib')), + ('pnacl_translator_x86_64_libs', + os.path.join(PNACL_TRANSLATOR_DIR, 'x86-64', 'lib'))] + +BIONIC_ARCHIVE_MAP = [ + ('bionic', BIONIC_TC_DIR), + ('bionic_headers', os.path.join(BIONIC_TC_DIR, 'arm-nacl', 'include')), + ('bionic_arm_libs', os.path.join(BIONIC_TC_DIR, 'arm-nacl', 'lib'))] + + +TOOLCHAIN_ARCHIVE_MAPS = { + 'newlib': NEWLIB_ARCHIVE_MAP, + 'glibc': GLIBC_ARCHIVE_MAP, + 'pnacl': PNACL_ARCHIVE_MAP, + 'bionic': BIONIC_ARCHIVE_MAP, +} + +TOOLS_ARCHIVE_MAP = [('tools', 'tools')] + + +def Untar(archive, destdir): + if os.path.exists(TAR): + cmd = [TAR] + else: + cmd = [sys.executable, CYGTAR] + + if options.verbose: + cmd.extend(['-xvf', archive]) + else: + cmd.extend(['-xf', archive]) + + if not os.path.exists(destdir): + buildbot_common.MakeDir(destdir) + buildbot_common.Run(cmd, cwd=destdir) + + +def RemoveExt(path): + while True: + path, ext = os.path.splitext(path) + if ext == '': + return path + + +def ExtractArchive(archive_path, destdirs): + Untar(archive_path, EXTRACT_ARCHIVE_DIR) + basename = RemoveExt(os.path.basename(archive_path)) + srcdir = os.path.join(EXTRACT_ARCHIVE_DIR, basename) + if type(destdirs) is not list: + destdirs = [destdirs] + + for destdir in destdirs: + if not os.path.exists(destdir): + buildbot_common.MakeDir(destdir) + src_files = glob.glob(os.path.join(srcdir, '*')) + for src_file in src_files: + buildbot_common.CopyDir(src_file, destdir) + + +def ExtractAll(archive_dict, archive_dir, destroot): + for archive_part, rel_destdirs in archive_dict: + archive_name = '%s_%s.tar.bz2' % (PLATFORM, archive_part) + archive_path = os.path.join(archive_dir, archive_name) + if type(rel_destdirs) is not list: + rel_destdirs = [rel_destdirs] + destdirs = [os.path.join(destroot, d) for d in rel_destdirs] + ExtractArchive(archive_path, destdirs) + + +def main(args): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('-v', '--verbose') + parser.add_argument('-o', '--outdir') + parser.add_argument('-t', '--toolchain', action='append', dest='toolchains', + default=[]) + parser.add_argument('--clean', action='store_true') + global options + options = parser.parse_args(args) + + if options.clean: + buildbot_common.RemoveDir(options.outdir) + for toolchain in options.toolchains: + ExtractAll(TOOLCHAIN_ARCHIVE_MAPS[toolchain], DOWNLOAD_ARCHIVE_DIR, + options.outdir) + ExtractAll(TOOLS_ARCHIVE_MAP, DOWNLOAD_ARCHIVE_DIR, options.outdir) + Untar(PPAPI_ARCHIVE, EXTRACT_ARCHIVE_DIR) + return 0 + + +if __name__ == '__main__': + try: + sys.exit(main(sys.argv[1:])) + except KeyboardInterrupt: + buildbot_common.ErrorExit('extract_artifacts: interrupted')
diff --git a/native_client_sdk/src/build_tools/json/naclsdk_manifest0.json b/native_client_sdk/src/build_tools/json/naclsdk_manifest0.json index e192217f..85347fa9 100644 --- a/native_client_sdk/src/build_tools/json/naclsdk_manifest0.json +++ b/native_client_sdk/src/build_tools/json/naclsdk_manifest0.json
@@ -4,17 +4,17 @@ "archives": [ { "checksum": { - "sha1": "61bc0ab13c4ff1d3222446fb616f207b1617441f" + "sha1": "0593db33d2f6f7dacf9ae4447e35463951f0dbe3" }, "host_os": "all", - "size": 29619, - "url": "https://storage.googleapis.com/nativeclient-mirror/nacl/nacl_sdk/trunk.228691/sdk_tools.tgz" + "size": 29701, + "url": "https://storage.googleapis.com/nativeclient-mirror/nacl/nacl_sdk/trunk.306188/sdk_tools.tgz" } ], - "description": "Native Client SDK Tools, revision 228691", + "description": "Native Client SDK Tools, revision 306188", "name": "sdk_tools", "recommended": "yes", - "revision": 228691, + "revision": 306188, "stability": "stable", "version": 1 }
diff --git a/native_client_sdk/src/build_tools/json/naclsdk_manifest2.json b/native_client_sdk/src/build_tools/json/naclsdk_manifest2.json index 9d952f3..5547a650 100644 --- a/native_client_sdk/src/build_tools/json/naclsdk_manifest2.json +++ b/native_client_sdk/src/build_tools/json/naclsdk_manifest2.json
@@ -4,23 +4,23 @@ "archives": [ { "checksum": { - "sha1": "61bc0ab13c4ff1d3222446fb616f207b1617441f" + "sha1": "0593db33d2f6f7dacf9ae4447e35463951f0dbe3" }, "host_os": "all", - "size": 29619, - "url": "https://storage.googleapis.com/nativeclient-mirror/nacl/nacl_sdk/trunk.228691/sdk_tools.tgz" + "size": 29701, + "url": "https://storage.googleapis.com/nativeclient-mirror/nacl/nacl_sdk/trunk.306188/sdk_tools.tgz" } ], - "description": "Native Client SDK Tools, revision 228691", + "description": "Native Client SDK Tools, revision 306188", "name": "sdk_tools", "recommended": "yes", - "revision": 228691, + "revision": 306188, "stability": "stable", "version": 1 }, { - "archives": [ - { + "archives": [ + { "host_os": "win", "url": "https://storage.googleapis.com/nativeclient-mirror/nacl/nacl_sdk/sdk/${revision}/vs_addin.tgz" }
diff --git a/native_client_sdk/src/build_tools/update_nacl_manifest.py b/native_client_sdk/src/build_tools/update_nacl_manifest.py index 40c0860..c93198b 100755 --- a/native_client_sdk/src/build_tools/update_nacl_manifest.py +++ b/native_client_sdk/src/build_tools/update_nacl_manifest.py
@@ -896,7 +896,7 @@ parser.add_option('--bundle-version', help='Manually set a bundle version. This can be passed more than once. ' 'format: --bundle-version pepper_24=24.0.1312.25', action='append') - options, args = parser.parse_args(args[1:]) + options, args = parser.parse_args(args) if (options.mailfrom is None) != (not options.mailto): options.mailfrom = None
diff --git a/native_client_sdk/src/build_tools/verify_filelist.py b/native_client_sdk/src/build_tools/verify_filelist.py index 02e3491..33a9a4f 100755 --- a/native_client_sdk/src/build_tools/verify_filelist.py +++ b/native_client_sdk/src/build_tools/verify_filelist.py
@@ -202,7 +202,8 @@ version = build_version.ChromeMajorVersion() args.append(os.path.join(OUT_DIR, 'pepper_%s' % version)) - rule_path, directory_path = args + rule_path = args[0] + directory_path = args[1] if options.platform: if options.platform not in VALID_PLATFORMS: parser.error('Unknown platform: %s' % options.platform)
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc b/native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc index 4d1e1b6..394cea6 100644 --- a/native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc +++ b/native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc
@@ -149,22 +149,7 @@ } char* ki_getcwd(char* buf, size_t size) { - // gtest uses getcwd in a static initializer and expects it to always - // succeed. If we haven't initialized kernel-intercept yet, then try - // the IRT's getcwd, and fall back to just returning ".". - if (!ki_is_initialized()) { - int rtn = _real_getcwd(buf, size); - if (rtn != 0) { - if (rtn == ENOSYS) { - buf[0] = '.'; - buf[1] = 0; - } else { - errno = rtn; - return NULL; - } - } - return buf; - } + ON_NOSYS_RETURN(NULL); return s_state.kp->getcwd(buf, size); }
diff --git a/native_client_sdk/src/libraries/nacl_io/library.dsc b/native_client_sdk/src/libraries/nacl_io/library.dsc index ddf1ba5..2fce549 100644 --- a/native_client_sdk/src/libraries/nacl_io/library.dsc +++ b/native_client_sdk/src/libraries/nacl_io/library.dsc
@@ -72,7 +72,6 @@ "syscalls/fcntl.c", "syscalls/ftruncate.c", "syscalls/futimes.c", - "syscalls/getcwd.c", "syscalls/getwd.c", "syscalls/ioctl.c", "syscalls/isatty.c",
diff --git a/native_client_sdk/src/libraries/nacl_io/nacl_io.h b/native_client_sdk/src/libraries/nacl_io/nacl_io.h index bd76bbe3..e68d5df 100644 --- a/native_client_sdk/src/libraries/nacl_io/nacl_io.h +++ b/native_client_sdk/src/libraries/nacl_io/nacl_io.h
@@ -95,7 +95,11 @@ * read in JavaScript via the HTML5 FileSystem API. This filesystem * provides the use of persistent storage. Please read the * documentation in ppapi/c/ppb_file_system.h for more information. - * source: Unused. + * source: Used to mount a subtree of the filesystem. Necessary when + * mounting non-sandboxed filesystems provided from javascript (e.g. + * via chrome.fileSystem in a chrome app). This should be a path + * which will be transparently prepended to all paths when + * performing the underlying file operations. * data: A string of parameters: * "type": Which type of filesystem to mount. Valid values are * "PERSISTENT" and "TEMPORARY". The default is "PERSISTENT".
diff --git a/native_client_sdk/src/libraries/nacl_io/syscalls/getcwd.c b/native_client_sdk/src/libraries/nacl_io/syscalls/getcwd.c deleted file mode 100644 index 5e702ca..0000000 --- a/native_client_sdk/src/libraries/nacl_io/syscalls/getcwd.c +++ /dev/null
@@ -1,30 +0,0 @@ -/* Copyright (c) 2013 The Chromium Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. */ - -#include <limits.h> -#include <string.h> - -#include "nacl_io/kernel_intercept.h" -#include "nacl_io/kernel_wrap.h" - -/* - * This interception should not really be needed under glibc since we can - * hook the internal calls to getcwd. However, we need to intercept it here - * since gtest call getcwd in a static constructor which general runs before - * nacl_io is initiliased. - */ -char* getcwd(char* buf, size_t size) { - // If size is 0, allocate as much as we need. - if (size == 0) { - char stack_buf[PATH_MAX + 1]; - if (!ki_getcwd(stack_buf, PATH_MAX)) - return NULL; - size = strlen(stack_buf) + 1; - } - // Allocate the buffer if needed - if (buf == NULL) { - buf = (char*)malloc(size); - } - return ki_getcwd(buf, size); -}
diff --git a/net/PRESUBMIT.py b/net/PRESUBMIT.py new file mode 100644 index 0000000..207cad0 --- /dev/null +++ b/net/PRESUBMIT.py
@@ -0,0 +1,12 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Top-level presubmit script for src/net. + +See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts +for more details about the presubmit API built into depot_tools. +""" + +def CheckChangeOnUpload(input_api, output_api): + return input_api.canned_checks.CheckPatchFormatted(input_api, output_api)
diff --git a/net/android/BUILD.gn b/net/android/BUILD.gn index 8c803a10..f583e7f 100644 --- a/net/android/BUILD.gn +++ b/net/android/BUILD.gn
@@ -52,12 +52,15 @@ java_cpp_enum("net_android_java_enums_srcjar") { sources = [ "../base/mime_util.h", + "../base/network_change_notifier.h", "cert_verify_result_android.h", "keystore.h" ] outputs = [ "org/chromium/net/CertificateMimeType.java", "org/chromium/net/CertVerifyStatusAndroid.java", + "org/chromium/net/ConnectionSubtype.java", + "org/chromium/net/ConnectionType.java", "org/chromium/net/PrivateKeyType.java", ] }
diff --git a/net/android/java/src/org/chromium/net/NetworkChangeNotifier.java b/net/android/java/src/org/chromium/net/NetworkChangeNotifier.java index 1008b7e4..928af78 100644 --- a/net/android/java/src/org/chromium/net/NetworkChangeNotifier.java +++ b/net/android/java/src/org/chromium/net/NetworkChangeNotifier.java
@@ -33,21 +33,12 @@ public void onConnectionTypeChanged(int connectionType); } - // These constants must always match the ones in network_change_notifier.h. - public static final int CONNECTION_UNKNOWN = 0; - public static final int CONNECTION_ETHERNET = 1; - public static final int CONNECTION_WIFI = 2; - public static final int CONNECTION_2G = 3; - public static final int CONNECTION_3G = 4; - public static final int CONNECTION_4G = 5; - public static final int CONNECTION_NONE = 6; - public static final int CONNECTION_BLUETOOTH = 7; - private final Context mContext; private final ArrayList<Long> mNativeChangeNotifiers; private final ObserverList<ConnectionTypeObserver> mConnectionTypeObservers; private NetworkChangeNotifierAutoDetect mAutoDetector; - private int mCurrentConnectionType = CONNECTION_UNKNOWN; + private int mCurrentConnectionType = ConnectionType.CONNECTION_UNKNOWN; + private double mCurrentMaxBandwidth = Double.POSITIVE_INFINITY; private static NetworkChangeNotifier sInstance; @@ -81,6 +72,18 @@ return mCurrentConnectionType; } + @CalledByNative + public double getCurrentMaxBandwidth() { + return mCurrentMaxBandwidth; + } + + /** + * Calls a native map lookup of subtype to max bandwidth. + */ + public static double getMaxBandwidthForConnectionSubtype(int subtype) { + return nativeGetMaxBandwidthForConnectionSubtype(subtype); + } + /** * Adds a native-side observer. */ @@ -144,11 +147,13 @@ new NetworkChangeNotifierAutoDetect.Observer() { @Override public void onConnectionTypeChanged(int newConnectionType) { + updateCurrentMaxBandwidth(mAutoDetector.getCurrentMaxBandwidthInMbps()); updateCurrentConnectionType(newConnectionType); } }, mContext, alwaysWatchForChanges); + updateCurrentMaxBandwidth(mAutoDetector.getCurrentMaxBandwidthInMbps()); updateCurrentConnectionType(mAutoDetector.getCurrentConnectionType()); } } else { @@ -169,9 +174,12 @@ } private void forceConnectivityStateInternal(boolean forceOnline) { - boolean connectionCurrentlyExists = mCurrentConnectionType != CONNECTION_NONE; + boolean connectionCurrentlyExists = + mCurrentConnectionType != ConnectionType.CONNECTION_NONE; if (connectionCurrentlyExists != forceOnline) { - updateCurrentConnectionType(forceOnline ? CONNECTION_UNKNOWN : CONNECTION_NONE); + updateCurrentMaxBandwidth(forceOnline ? Double.POSITIVE_INFINITY : 0.0); + updateCurrentConnectionType(forceOnline ? ConnectionType.CONNECTION_UNKNOWN + : ConnectionType.CONNECTION_NONE); } } @@ -180,6 +188,10 @@ notifyObserversOfConnectionTypeChange(newConnectionType); } + private void updateCurrentMaxBandwidth(double maxBandwidth) { + mCurrentMaxBandwidth = maxBandwidth; + } + /** * Alerts all observers of a connection change. */ @@ -217,6 +229,8 @@ @NativeClassQualifiedName("NetworkChangeNotifierDelegateAndroid") private native void nativeNotifyConnectionTypeChanged(long nativePtr, int newConnectionType); + private static native double nativeGetMaxBandwidthForConnectionSubtype(int subtype); + // For testing only. public static NetworkChangeNotifierAutoDetect getAutoDetectorForTest() { return getInstance().mAutoDetector; @@ -227,6 +241,7 @@ */ public static boolean isOnline() { int connectionType = getInstance().getCurrentConnectionType(); - return connectionType != CONNECTION_UNKNOWN && connectionType != CONNECTION_NONE; + return connectionType != ConnectionType.CONNECTION_UNKNOWN + && connectionType != ConnectionType.CONNECTION_NONE; } }
diff --git a/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java b/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java index ec86b69..12ae465 100644 --- a/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java +++ b/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java
@@ -4,10 +4,12 @@ package org.chromium.net; +import android.Manifest.permission; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.wifi.WifiInfo; @@ -77,15 +79,27 @@ /** Queries the WifiManager for SSID of the current Wifi connection. */ static class WifiManagerDelegate { private final Context mContext; + private final WifiManager mWifiManager; + private final boolean mHasWifiPermission; WifiManagerDelegate(Context context) { mContext = context; + // TODO(jkarlin): If the embedder doesn't have ACCESS_WIFI_STATE permission then inform + // native code and fail if native NetworkChangeNotifierAndroid::GetMaxBandwidth() is + // called. + mHasWifiPermission = mContext.getPackageManager().checkPermission( + permission.ACCESS_WIFI_STATE, mContext.getPackageName()) + == PackageManager.PERMISSION_GRANTED; + mWifiManager = mHasWifiPermission + ? (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE) : null; } // For testing. WifiManagerDelegate() { // All the methods below should be overridden. mContext = null; + mWifiManager = null; + mHasWifiPermission = false; } String getWifiSSID() { @@ -102,10 +116,24 @@ } return ""; } + + /* + * Requires ACCESS_WIFI_STATE permission to get the real link speed, else returns + * UNKNOWN_LINK_SPEED. + */ + int getLinkSpeedInMbps() { + if (!mHasWifiPermission || mWifiManager == null) return UNKNOWN_LINK_SPEED; + final WifiInfo wifiInfo = mWifiManager.getConnectionInfo(); + if (wifiInfo == null) return UNKNOWN_LINK_SPEED; + + // wifiInfo.getLinkSpeed returns the current wifi linkspeed, which can change even + // though the connection type hasn't changed. + return wifiInfo.getLinkSpeed(); + } } private static final String TAG = "NetworkChangeNotifierAutoDetect"; - + private static final int UNKNOWN_LINK_SPEED = -1; private final NetworkConnectivityIntentFilter mIntentFilter = new NetworkConnectivityIntentFilter(); @@ -187,18 +215,18 @@ // Track exactly what type of connection we have. final NetworkState networkState = mConnectivityManagerDelegate.getNetworkState(); if (!networkState.isConnected()) { - return NetworkChangeNotifier.CONNECTION_NONE; + return ConnectionType.CONNECTION_NONE; } switch (networkState.getNetworkType()) { case ConnectivityManager.TYPE_ETHERNET: - return NetworkChangeNotifier.CONNECTION_ETHERNET; + return ConnectionType.CONNECTION_ETHERNET; case ConnectivityManager.TYPE_WIFI: - return NetworkChangeNotifier.CONNECTION_WIFI; + return ConnectionType.CONNECTION_WIFI; case ConnectivityManager.TYPE_WIMAX: - return NetworkChangeNotifier.CONNECTION_4G; + return ConnectionType.CONNECTION_4G; case ConnectivityManager.TYPE_BLUETOOTH: - return NetworkChangeNotifier.CONNECTION_BLUETOOTH; + return ConnectionType.CONNECTION_BLUETOOTH; case ConnectivityManager.TYPE_MOBILE: // Use information from TelephonyManager to classify the connection. switch (networkState.getNetworkSubType()) { @@ -207,7 +235,7 @@ case TelephonyManager.NETWORK_TYPE_CDMA: case TelephonyManager.NETWORK_TYPE_1xRTT: case TelephonyManager.NETWORK_TYPE_IDEN: - return NetworkChangeNotifier.CONNECTION_2G; + return ConnectionType.CONNECTION_2G; case TelephonyManager.NETWORK_TYPE_UMTS: case TelephonyManager.NETWORK_TYPE_EVDO_0: case TelephonyManager.NETWORK_TYPE_EVDO_A: @@ -217,19 +245,94 @@ case TelephonyManager.NETWORK_TYPE_EVDO_B: case TelephonyManager.NETWORK_TYPE_EHRPD: case TelephonyManager.NETWORK_TYPE_HSPAP: - return NetworkChangeNotifier.CONNECTION_3G; + return ConnectionType.CONNECTION_3G; case TelephonyManager.NETWORK_TYPE_LTE: - return NetworkChangeNotifier.CONNECTION_4G; + return ConnectionType.CONNECTION_4G; default: - return NetworkChangeNotifier.CONNECTION_UNKNOWN; + return ConnectionType.CONNECTION_UNKNOWN; } default: - return NetworkChangeNotifier.CONNECTION_UNKNOWN; + return ConnectionType.CONNECTION_UNKNOWN; + } + } + + /* + * Returns the bandwidth of the current connection in Mbps. The result is + * derived from the NetInfo v3 specification's mapping from network type to + * max link speed. In cases where more information is available, such as wifi, + * that is used instead. For more on NetInfo, see http://w3c.github.io/netinfo/. + * + * TODO(jkarlin): Add a notification of bandwidth change to the NetworkChangeNotifier. + * Without that the MaxBandwidth value will be stale until the network type or address + * changes again. + */ + public double getCurrentMaxBandwidthInMbps() { + if (getCurrentConnectionType() == ConnectionType.CONNECTION_WIFI) { + final int link_speed = mWifiManagerDelegate.getLinkSpeedInMbps(); + if (link_speed != UNKNOWN_LINK_SPEED) { + return link_speed; + } + } + + return NetworkChangeNotifier.getMaxBandwidthForConnectionSubtype( + getCurrentConnectionSubtype()); + } + + private int getCurrentConnectionSubtype() { + final NetworkState networkState = mConnectivityManagerDelegate.getNetworkState(); + if (!networkState.isConnected()) { + return ConnectionSubtype.SUBTYPE_NONE; + } + + switch (networkState.getNetworkType()) { + case ConnectivityManager.TYPE_ETHERNET: + case ConnectivityManager.TYPE_WIFI: + case ConnectivityManager.TYPE_WIMAX: + case ConnectivityManager.TYPE_BLUETOOTH: + return ConnectionSubtype.SUBTYPE_UNKNOWN; + case ConnectivityManager.TYPE_MOBILE: + // Use information from TelephonyManager to classify the connection. + switch (networkState.getNetworkSubType()) { + case TelephonyManager.NETWORK_TYPE_GPRS: + return ConnectionSubtype.SUBTYPE_GPRS; + case TelephonyManager.NETWORK_TYPE_EDGE: + return ConnectionSubtype.SUBTYPE_EDGE; + case TelephonyManager.NETWORK_TYPE_CDMA: + return ConnectionSubtype.SUBTYPE_CDMA; + case TelephonyManager.NETWORK_TYPE_1xRTT: + return ConnectionSubtype.SUBTYPE_1XRTT; + case TelephonyManager.NETWORK_TYPE_IDEN: + return ConnectionSubtype.SUBTYPE_IDEN; + case TelephonyManager.NETWORK_TYPE_UMTS: + return ConnectionSubtype.SUBTYPE_UMTS; + case TelephonyManager.NETWORK_TYPE_EVDO_0: + return ConnectionSubtype.SUBTYPE_EVDO_REV_0; + case TelephonyManager.NETWORK_TYPE_EVDO_A: + return ConnectionSubtype.SUBTYPE_EVDO_REV_A; + case TelephonyManager.NETWORK_TYPE_HSDPA: + return ConnectionSubtype.SUBTYPE_HSDPA; + case TelephonyManager.NETWORK_TYPE_HSUPA: + return ConnectionSubtype.SUBTYPE_HSUPA; + case TelephonyManager.NETWORK_TYPE_HSPA: + return ConnectionSubtype.SUBTYPE_HSPA; + case TelephonyManager.NETWORK_TYPE_EVDO_B: + return ConnectionSubtype.SUBTYPE_EVDO_REV_B; + case TelephonyManager.NETWORK_TYPE_EHRPD: + return ConnectionSubtype.SUBTYPE_EHRPD; + case TelephonyManager.NETWORK_TYPE_HSPAP: + return ConnectionSubtype.SUBTYPE_HSPAP; + case TelephonyManager.NETWORK_TYPE_LTE: + return ConnectionSubtype.SUBTYPE_LTE; + default: + return ConnectionSubtype.SUBTYPE_UNKNOWN; + } + default: + return ConnectionSubtype.SUBTYPE_UNKNOWN; } } private String getCurrentWifiSSID() { - if (getCurrentConnectionType() != NetworkChangeNotifier.CONNECTION_WIFI) + if (getCurrentConnectionType() != ConnectionType.CONNECTION_WIFI) return ""; return mWifiManagerDelegate.getWifiSSID(); }
diff --git a/net/android/javatests/src/org/chromium/net/NetworkChangeNotifierTest.java b/net/android/javatests/src/org/chromium/net/NetworkChangeNotifierTest.java index dd15a76..f4eafd9 100644 --- a/net/android/javatests/src/org/chromium/net/NetworkChangeNotifierTest.java +++ b/net/android/javatests/src/org/chromium/net/NetworkChangeNotifierTest.java
@@ -13,6 +13,7 @@ import android.test.suitebuilder.annotation.MediumTest; import org.chromium.base.ApplicationState; +import org.chromium.base.library_loader.LibraryLoader; import org.chromium.base.test.util.Feature; import org.chromium.net.NetworkChangeNotifierAutoDetect.NetworkState; @@ -74,6 +75,7 @@ class MockWifiManagerDelegate extends NetworkChangeNotifierAutoDetect.WifiManagerDelegate { private String mWifiSSID; + private int mLinkSpeedMbps; @Override String getWifiSSID() { @@ -83,6 +85,104 @@ void setWifiSSID(String wifiSSID) { mWifiSSID = wifiSSID; } + + @Override + int getLinkSpeedInMbps() { + return mLinkSpeedMbps; + } + + void setLinkSpeedInMbps(int linkSpeedInMbps) { + mLinkSpeedMbps = linkSpeedInMbps; + } + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + LibraryLoader.ensureInitialized(); + createTestNotifier(); + } + + private NetworkChangeNotifierAutoDetect mReceiver; + private MockConnectivityManagerDelegate mConnectivityDelegate; + private MockWifiManagerDelegate mWifiDelegate; + + private void createTestNotifier() { + Context context = getInstrumentation().getTargetContext(); + NetworkChangeNotifier.resetInstanceForTests(context); + NetworkChangeNotifier.setAutoDetectConnectivityState(true); + + mReceiver = NetworkChangeNotifier.getAutoDetectorForTest(); + assertNotNull(mReceiver); + + mConnectivityDelegate = + new MockConnectivityManagerDelegate(); + mConnectivityDelegate.setActiveNetworkExists(true); + mReceiver.setConnectivityManagerDelegateForTests(mConnectivityDelegate); + + mWifiDelegate = new MockWifiManagerDelegate(); + mReceiver.setWifiManagerDelegateForTests(mWifiDelegate); + mWifiDelegate.setWifiSSID("foo"); + } + + /** + * Tests that changing the network type changes the maxBandwidth. + */ + @UiThreadTest + @MediumTest + @Feature({"Android-AppBase"}) + public void testNetworkChangeNotifierMaxBandwidthEthernet() throws InterruptedException { + // Show that for Ethernet the link speed is unknown (+Infinity). + mConnectivityDelegate.setNetworkType(ConnectivityManager.TYPE_ETHERNET); + assertEquals(ConnectionType.CONNECTION_ETHERNET, + mReceiver.getCurrentConnectionType()); + assertEquals(Double.POSITIVE_INFINITY, mReceiver.getCurrentMaxBandwidthInMbps()); + } + + @UiThreadTest + @MediumTest + @Feature({"Android-AppBase"}) + public void testNetworkChangeNotifierMaxBandwidthWifi() throws InterruptedException { + // Test that for wifi types the link speed is read from the WifiManager. + mWifiDelegate.setLinkSpeedInMbps(42); + mConnectivityDelegate.setNetworkType(ConnectivityManager.TYPE_WIFI); + assertEquals(ConnectionType.CONNECTION_WIFI, mReceiver.getCurrentConnectionType()); + assertEquals(42.0, mReceiver.getCurrentMaxBandwidthInMbps()); + } + + @UiThreadTest + @MediumTest + @Feature({"Android-AppBase"}) + public void testNetworkChangeNotifierMaxBandwidthWiMax() throws InterruptedException { + // Show that for WiMax the link speed is unknown (+Infinity), although the type is 4g. + // TODO(jkarlin): Add support for CONNECTION_WIMAX as specified in + // http://w3c.github.io/netinfo/. + mConnectivityDelegate.setNetworkType(ConnectivityManager.TYPE_WIMAX); + assertEquals(ConnectionType.CONNECTION_4G, + mReceiver.getCurrentConnectionType()); + assertEquals(Double.POSITIVE_INFINITY, mReceiver.getCurrentMaxBandwidthInMbps()); + } + + @UiThreadTest + @MediumTest + @Feature({"Android-AppBase"}) + public void testNetworkChangeNotifierMaxBandwidthBluetooth() throws InterruptedException { + // Show that for bluetooth the link speed is unknown (+Infinity). + mConnectivityDelegate.setNetworkType(ConnectivityManager.TYPE_BLUETOOTH); + assertEquals(ConnectionType.CONNECTION_BLUETOOTH, + mReceiver.getCurrentConnectionType()); + assertEquals(Double.POSITIVE_INFINITY, mReceiver.getCurrentMaxBandwidthInMbps()); + } + + @UiThreadTest + @MediumTest + @Feature({"Android-AppBase"}) + public void testNetworkChangeNotifierMaxBandwidthMobile() throws InterruptedException { + // Test that for mobile types the subtype is used to determine the maxBandwidth. + mConnectivityDelegate.setNetworkType(ConnectivityManager.TYPE_MOBILE); + mConnectivityDelegate.setNetworkSubtype(TelephonyManager.NETWORK_TYPE_LTE); + assertEquals(ConnectionType.CONNECTION_4G, mReceiver.getCurrentConnectionType()); + assertEquals(100.0, mReceiver.getCurrentMaxBandwidthInMbps()); } /** @@ -93,70 +193,50 @@ @MediumTest @Feature({"Android-AppBase"}) public void testNetworkChangeNotifierJavaObservers() throws InterruptedException { - // Create a new notifier that doesn't have a native-side counterpart. - Context context = getInstrumentation().getTargetContext(); - NetworkChangeNotifier.resetInstanceForTests(context); - - NetworkChangeNotifier.setAutoDetectConnectivityState(true); - NetworkChangeNotifierAutoDetect receiver = NetworkChangeNotifier.getAutoDetectorForTest(); - assertTrue(receiver != null); - - MockConnectivityManagerDelegate connectivityDelegate = - new MockConnectivityManagerDelegate(); - connectivityDelegate.setActiveNetworkExists(true); - connectivityDelegate.setNetworkType(NetworkChangeNotifier.CONNECTION_UNKNOWN); - connectivityDelegate.setNetworkSubtype(TelephonyManager.NETWORK_TYPE_UNKNOWN); - receiver.setConnectivityManagerDelegateForTests(connectivityDelegate); - - MockWifiManagerDelegate wifiDelegate = new MockWifiManagerDelegate(); - wifiDelegate.setWifiSSID("foo"); - receiver.setWifiManagerDelegateForTests(wifiDelegate); - // Initialize the NetworkChangeNotifier with a connection. Intent connectivityIntent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); - receiver.onReceive(getInstrumentation().getTargetContext(), connectivityIntent); + mReceiver.onReceive(getInstrumentation().getTargetContext(), connectivityIntent); // We shouldn't be re-notified if the connection hasn't actually changed. NetworkChangeNotifierTestObserver observer = new NetworkChangeNotifierTestObserver(); NetworkChangeNotifier.addConnectionTypeObserver(observer); - receiver.onReceive(getInstrumentation().getTargetContext(), connectivityIntent); + mReceiver.onReceive(getInstrumentation().getTargetContext(), connectivityIntent); assertFalse(observer.hasReceivedNotification()); // We shouldn't be notified if we're connected to non-Wifi and the Wifi SSID changes. - wifiDelegate.setWifiSSID("bar"); - receiver.onReceive(getInstrumentation().getTargetContext(), connectivityIntent); + mWifiDelegate.setWifiSSID("bar"); + mReceiver.onReceive(getInstrumentation().getTargetContext(), connectivityIntent); assertFalse(observer.hasReceivedNotification()); // We should be notified when we change to Wifi. - connectivityDelegate.setNetworkType(ConnectivityManager.TYPE_WIFI); - receiver.onReceive(getInstrumentation().getTargetContext(), connectivityIntent); + mConnectivityDelegate.setNetworkType(ConnectivityManager.TYPE_WIFI); + mReceiver.onReceive(getInstrumentation().getTargetContext(), connectivityIntent); assertTrue(observer.hasReceivedNotification()); observer.resetHasReceivedNotification(); // We should be notified when the Wifi SSID changes. - wifiDelegate.setWifiSSID("foo"); - receiver.onReceive(getInstrumentation().getTargetContext(), connectivityIntent); + mWifiDelegate.setWifiSSID("foo"); + mReceiver.onReceive(getInstrumentation().getTargetContext(), connectivityIntent); assertTrue(observer.hasReceivedNotification()); observer.resetHasReceivedNotification(); // We shouldn't be re-notified if the Wifi SSID hasn't actually changed. - receiver.onReceive(getInstrumentation().getTargetContext(), connectivityIntent); + mReceiver.onReceive(getInstrumentation().getTargetContext(), connectivityIntent); assertFalse(observer.hasReceivedNotification()); // Mimic that connectivity has been lost and ensure that Chrome notifies our observer. - connectivityDelegate.setActiveNetworkExists(false); - connectivityDelegate.setNetworkType(NetworkChangeNotifier.CONNECTION_NONE); + mConnectivityDelegate.setActiveNetworkExists(false); Intent noConnectivityIntent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); - receiver.onReceive(getInstrumentation().getTargetContext(), noConnectivityIntent); + mReceiver.onReceive(getInstrumentation().getTargetContext(), noConnectivityIntent); assertTrue(observer.hasReceivedNotification()); observer.resetHasReceivedNotification(); // Pretend we got moved to the background. - receiver.onApplicationStateChange(ApplicationState.HAS_PAUSED_ACTIVITIES); + mReceiver.onApplicationStateChange(ApplicationState.HAS_PAUSED_ACTIVITIES); // Change the state. - connectivityDelegate.setActiveNetworkExists(true); - connectivityDelegate.setNetworkType(NetworkChangeNotifier.CONNECTION_WIFI); + mConnectivityDelegate.setActiveNetworkExists(true); + mConnectivityDelegate.setNetworkType(ConnectivityManager.TYPE_WIFI); // The NetworkChangeNotifierAutoDetect doesn't receive any notification while we are in the // background, but when we get back to the foreground the state changed should be detected // and a notification sent. - receiver.onApplicationStateChange(ApplicationState.HAS_RUNNING_ACTIVITIES); + mReceiver.onApplicationStateChange(ApplicationState.HAS_RUNNING_ACTIVITIES); assertTrue(observer.hasReceivedNotification()); } }
diff --git a/net/android/network_change_notifier_android.cc b/net/android/network_change_notifier_android.cc index 410d1fbd..2063e7b 100644 --- a/net/android/network_change_notifier_android.cc +++ b/net/android/network_change_notifier_android.cc
@@ -114,6 +114,10 @@ return delegate_->GetCurrentConnectionType(); } +double NetworkChangeNotifierAndroid::GetCurrentMaxBandwidth() const { + return delegate_->GetCurrentMaxBandwidth(); +} + void NetworkChangeNotifierAndroid::OnConnectionTypeChanged() { DnsConfigServiceThread::NotifyNetworkChangeNotifierObservers(); }
diff --git a/net/android/network_change_notifier_android.h b/net/android/network_change_notifier_android.h index 57d29b8..7710c26 100644 --- a/net/android/network_change_notifier_android.h +++ b/net/android/network_change_notifier_android.h
@@ -46,12 +46,19 @@ // NetworkChangeNotifier: virtual ConnectionType GetCurrentConnectionType() const override; + // Requires ACCESS_WIFI_STATE permission in order to provide precise WiFi link + // speed. + virtual double GetCurrentMaxBandwidth() const override; // NetworkChangeNotifierDelegateAndroid::Observer: virtual void OnConnectionTypeChanged() override; static bool Register(JNIEnv* env); + // Promote GetMaxBandwidthForConnectionSubtype to public for the Android + // delegate class. + using NetworkChangeNotifier::GetMaxBandwidthForConnectionSubtype; + private: friend class NetworkChangeNotifierAndroidTest; friend class NetworkChangeNotifierFactoryAndroid;
diff --git a/net/android/network_change_notifier_android_unittest.cc b/net/android/network_change_notifier_android_unittest.cc index 6aadb54..0818d5a7 100644 --- a/net/android/network_change_notifier_android_unittest.cc +++ b/net/android/network_change_notifier_android_unittest.cc
@@ -213,4 +213,17 @@ other_connection_type_observer_.notifications_count()); } +TEST_F(NetworkChangeNotifierAndroidTest, MaxBandwidth) { + SetOnline(); + EXPECT_EQ(NetworkChangeNotifier::CONNECTION_UNKNOWN, + notifier_.GetConnectionType()); + EXPECT_EQ(std::numeric_limits<double>::infinity(), + notifier_.GetMaxBandwidth()); + + SetOffline(); + EXPECT_EQ(NetworkChangeNotifier::CONNECTION_NONE, + notifier_.GetConnectionType()); + EXPECT_EQ(0.0, notifier_.GetMaxBandwidth()); +} + } // namespace net
diff --git a/net/android/network_change_notifier_delegate_android.cc b/net/android/network_change_notifier_delegate_android.cc index fbbacedd..a6a71322 100644 --- a/net/android/network_change_notifier_delegate_android.cc +++ b/net/android/network_change_notifier_delegate_android.cc
@@ -6,6 +6,7 @@ #include "base/logging.h" #include "jni/NetworkChangeNotifier_jni.h" +#include "net/android/network_change_notifier_android.h" namespace net { @@ -32,8 +33,24 @@ return static_cast<NetworkChangeNotifier::ConnectionType>(connection_type); } +// Converts a Java side connection type (integer) to +// the native side NetworkChangeNotifier::ConnectionType. +NetworkChangeNotifier::ConnectionSubtype ConvertConnectionSubtype( + jint subtype) { + DCHECK(subtype >= 0 && subtype <= NetworkChangeNotifier::SUBTYPE_LAST); + + return static_cast<NetworkChangeNotifier::ConnectionSubtype>(subtype); +} + } // namespace +jdouble GetMaxBandwidthForConnectionSubtype(JNIEnv* env, + jclass caller, + jint subtype) { + return NetworkChangeNotifierAndroid::GetMaxBandwidthForConnectionSubtype( + ConvertConnectionSubtype(subtype)); +} + NetworkChangeNotifierDelegateAndroid::NetworkChangeNotifierDelegateAndroid() : observers_(new ObserverListThreadSafe<Observer>()) { JNIEnv* env = base::android::AttachCurrentThread(); @@ -47,6 +64,8 @@ ConvertConnectionType( Java_NetworkChangeNotifier_getCurrentConnectionType( env, java_network_change_notifier_.obj()))); + SetCurrentMaxBandwidth(Java_NetworkChangeNotifier_getCurrentMaxBandwidth( + env, java_network_change_notifier_.obj())); } NetworkChangeNotifierDelegateAndroid::~NetworkChangeNotifierDelegateAndroid() { @@ -60,10 +79,15 @@ NetworkChangeNotifier::ConnectionType NetworkChangeNotifierDelegateAndroid::GetCurrentConnectionType() const { - base::AutoLock auto_lock(connection_type_lock_); + base::AutoLock auto_lock(connection_lock_); return connection_type_; } +double NetworkChangeNotifierDelegateAndroid::GetCurrentMaxBandwidth() const { + base::AutoLock auto_lock(connection_lock_); + return connection_max_bandwidth_; +} + void NetworkChangeNotifierDelegateAndroid::NotifyConnectionTypeChanged( JNIEnv* env, jobject obj, @@ -72,6 +96,8 @@ const ConnectionType actual_connection_type = ConvertConnectionType( new_connection_type); SetCurrentConnectionType(actual_connection_type); + SetCurrentMaxBandwidth(Java_NetworkChangeNotifier_getCurrentMaxBandwidth( + env, java_network_change_notifier_.obj())); observers_->Notify(&Observer::OnConnectionTypeChanged); } @@ -98,10 +124,16 @@ void NetworkChangeNotifierDelegateAndroid::SetCurrentConnectionType( ConnectionType new_connection_type) { - base::AutoLock auto_lock(connection_type_lock_); + base::AutoLock auto_lock(connection_lock_); connection_type_ = new_connection_type; } +void NetworkChangeNotifierDelegateAndroid::SetCurrentMaxBandwidth( + double max_bandwidth) { + base::AutoLock auto_lock(connection_lock_); + connection_max_bandwidth_ = max_bandwidth; +} + void NetworkChangeNotifierDelegateAndroid::SetOnline() { JNIEnv* env = base::android::AttachCurrentThread(); Java_NetworkChangeNotifier_forceConnectivityState(env, true);
diff --git a/net/android/network_change_notifier_delegate_android.h b/net/android/network_change_notifier_delegate_android.h index f93c30b..f561888 100644 --- a/net/android/network_change_notifier_delegate_android.h +++ b/net/android/network_change_notifier_delegate_android.h
@@ -55,6 +55,9 @@ // Can be called from any thread. ConnectionType GetCurrentConnectionType() const; + // Can be called from any thread. + double GetCurrentMaxBandwidth() const; + // Initializes JNI bindings. static bool Register(JNIEnv* env); @@ -62,6 +65,7 @@ friend class BaseNetworkChangeNotifierAndroidTest; void SetCurrentConnectionType(ConnectionType connection_type); + void SetCurrentMaxBandwidth(double max_bandwidth); // Methods calling the Java side exposed for testing. void SetOnline(); @@ -71,8 +75,9 @@ scoped_refptr<ObserverListThreadSafe<Observer> > observers_; scoped_refptr<base::SingleThreadTaskRunner> jni_task_runner_; base::android::ScopedJavaGlobalRef<jobject> java_network_change_notifier_; - mutable base::Lock connection_type_lock_; // Protects the state below. + mutable base::Lock connection_lock_; // Protects the state below. ConnectionType connection_type_; + double connection_max_bandwidth_; DISALLOW_COPY_AND_ASSIGN(NetworkChangeNotifierDelegateAndroid); };
diff --git a/net/base/host_port_pair.cc b/net/base/host_port_pair.cc index 1570bbb5..1550c36 100644 --- a/net/base/host_port_pair.cc +++ b/net/base/host_port_pair.cc
@@ -47,7 +47,10 @@ } std::string HostPortPair::ToString() const { - return base::StringPrintf("%s:%u", HostForURL().c_str(), port_); + std::string ret(HostForURL()); + ret += ':'; + ret += base::IntToString(port_); + return ret; } std::string HostPortPair::HostForURL() const {
diff --git a/net/base/network_change_notifier.cc b/net/base/network_change_notifier.cc index b952aa62..b797864a 100644 --- a/net/base/network_change_notifier.cc +++ b/net/base/network_change_notifier.cc
@@ -785,6 +785,81 @@ } // static +double NetworkChangeNotifier::GetMaxBandwidthForConnectionSubtype( + ConnectionSubtype subtype) { + switch (subtype) { + case SUBTYPE_GSM: + return 0.01; + case SUBTYPE_IDEN: + return 0.064; + case SUBTYPE_CDMA: + return 0.115; + case SUBTYPE_1XRTT: + return 0.153; + case SUBTYPE_GPRS: + return 0.237; + case SUBTYPE_EDGE: + return 0.384; + case SUBTYPE_UMTS: + return 2.0; + case SUBTYPE_EVDO_REV_0: + return 2.46; + case SUBTYPE_EVDO_REV_A: + return 3.1; + case SUBTYPE_HSPA: + return 3.6; + case SUBTYPE_EVDO_REV_B: + return 14.7; + case SUBTYPE_HSDPA: + return 14.3; + case SUBTYPE_HSUPA: + return 14.4; + case SUBTYPE_EHRPD: + return 21.0; + case SUBTYPE_HSPAP: + return 42.0; + case SUBTYPE_LTE: + return 100.0; + case SUBTYPE_LTE_ADVANCED: + return 100.0; + case SUBTYPE_BLUETOOTH_1_2: + return 1.0; + case SUBTYPE_BLUETOOTH_2_1: + return 3.0; + case SUBTYPE_BLUETOOTH_3_0: + return 24.0; + case SUBTYPE_BLUETOOTH_4_0: + return 1.0; + case SUBTYPE_ETHERNET: + return 10.0; + case SUBTYPE_FAST_ETHERNET: + return 100.0; + case SUBTYPE_GIGABIT_ETHERNET: + return 1000.0; + case SUBTYPE_10_GIGABIT_ETHERNET: + return 10000.0; + case SUBTYPE_WIFI_B: + return 11.0; + case SUBTYPE_WIFI_G: + return 54.0; + case SUBTYPE_WIFI_N: + return 600.0; + case SUBTYPE_WIFI_AC: + return 1300.0; + case SUBTYPE_WIFI_AD: + return 7000.0; + case SUBTYPE_UNKNOWN: + return std::numeric_limits<double>::infinity(); + case SUBTYPE_NONE: + return 0.0; + case SUBTYPE_OTHER: + return std::numeric_limits<double>::infinity(); + } + NOTREACHED(); + return std::numeric_limits<double>::infinity(); +} + +// static void NetworkChangeNotifier::NotifyObserversOfIPAddressChange() { if (g_network_change_notifier && !g_network_change_notifier->test_notifications_only_) {
diff --git a/net/base/network_change_notifier.h b/net/base/network_change_notifier.h index bdd2d18..285c52b8 100644 --- a/net/base/network_change_notifier.h +++ b/net/base/network_change_notifier.h
@@ -34,6 +34,9 @@ public: // This is a superset of the connection types in the NetInfo v3 specification: // http://w3c.github.io/netinfo/. + // + // A Java counterpart will be generated for this enum. + // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.net enum ConnectionType { CONNECTION_UNKNOWN = 0, // A connection exists, but its type is unknown. // Also used as a default value. @@ -47,6 +50,49 @@ CONNECTION_LAST = CONNECTION_BLUETOOTH }; + // This is the NetInfo v3 set of connection technologies as seen in + // http://w3c.github.io/netinfo/. This enum is copied in + // NetworkChangeNotifier.java so be sure to change both at once. + // + // A Java counterpart will be generated for this enum. + // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.net + enum ConnectionSubtype { + SUBTYPE_GSM = 0, + SUBTYPE_IDEN, + SUBTYPE_CDMA, + SUBTYPE_1XRTT, + SUBTYPE_GPRS, + SUBTYPE_EDGE, + SUBTYPE_UMTS, + SUBTYPE_EVDO_REV_0, + SUBTYPE_EVDO_REV_A, + SUBTYPE_HSPA, + SUBTYPE_EVDO_REV_B, + SUBTYPE_HSDPA, + SUBTYPE_HSUPA, + SUBTYPE_EHRPD, + SUBTYPE_HSPAP, + SUBTYPE_LTE, + SUBTYPE_LTE_ADVANCED, + SUBTYPE_BLUETOOTH_1_2, + SUBTYPE_BLUETOOTH_2_1, + SUBTYPE_BLUETOOTH_3_0, + SUBTYPE_BLUETOOTH_4_0, + SUBTYPE_ETHERNET, + SUBTYPE_FAST_ETHERNET, + SUBTYPE_GIGABIT_ETHERNET, + SUBTYPE_10_GIGABIT_ETHERNET, + SUBTYPE_WIFI_B, + SUBTYPE_WIFI_G, + SUBTYPE_WIFI_N, + SUBTYPE_WIFI_AC, + SUBTYPE_WIFI_AD, + SUBTYPE_UNKNOWN, + SUBTYPE_NONE, + SUBTYPE_OTHER, + SUBTYPE_LAST = SUBTYPE_OTHER + }; + class NET_EXPORT IPAddressObserver { public: // Will be called when the IP address of the primary interface changes. @@ -162,7 +208,9 @@ // Returns a theoretical upper limit on download bandwidth, potentially based // on underlying connection type, signal strength, or some other signal. The // default mapping of connection type to maximum bandwidth is provided in the - // NetInfo spec: http://w3c.github.io/netinfo/. + // NetInfo spec: http://w3c.github.io/netinfo/. Host-specific application + // permissions may be required, please see host-specific declaration for more + // information. static double GetMaxBandwidth(); // Retrieve the last read DnsConfig. This could be expensive if the system has @@ -306,6 +354,11 @@ // cheap as it is called often. virtual double GetCurrentMaxBandwidth() const; + // Returns a theoretical upper limit on download bandwidth given a connection + // subtype. The mapping of connection type to maximum bandwidth is provided in + // the NetInfo spec: http://w3c.github.io/netinfo/. + static double GetMaxBandwidthForConnectionSubtype(ConnectionSubtype subtype); + // Broadcasts a notification to all registered observers. Note that this // happens asynchronously, even for observers on the current thread, even in // tests.
diff --git a/net/cert/crl_set_storage.cc b/net/cert/crl_set_storage.cc index 1b11d78..2da4f929 100644 --- a/net/cert/crl_set_storage.cc +++ b/net/cert/crl_set_storage.cc
@@ -8,6 +8,7 @@ #include "base/debug/trace_event.h" #include "base/format_macros.h" #include "base/json/json_reader.h" +#include "base/numerics/safe_conversions.h" #include "base/strings/stringprintf.h" #include "base/values.h" #include "crypto/sha2.h" @@ -517,10 +518,12 @@ } std::string ret; - char* out = WriteInto(&ret, len + 1 /* to include final NUL */); + uint8_t* out = reinterpret_cast<uint8_t*>( + WriteInto(&ret, len + 1 /* to include final NUL */)); size_t off = 0; - out[off++] = header.size(); - out[off++] = header.size() >> 8; + CHECK(base::IsValueInRangeForNumericType<uint16>(header.size())); + out[off++] = static_cast<uint8_t>(header.size()); + out[off++] = static_cast<uint8_t>(header.size() >> 8); memcpy(out + off, header.data(), header.size()); off += header.size(); @@ -534,7 +537,8 @@ for (std::vector<std::string>::const_iterator j = i->second.begin(); j != i->second.end(); ++j) { - out[off++] = j->size(); + CHECK(base::IsValueInRangeForNumericType<uint8_t>(j->size())); + out[off++] = static_cast<uint8_t>(j->size()); memcpy(out + off, j->data(), j->size()); off += j->size(); }
diff --git a/net/cert/ct_log_response_parser.cc b/net/cert/ct_log_response_parser.cc index bd59a9e..f7cc25f 100644 --- a/net/cert/ct_log_response_parser.cc +++ b/net/cert/ct_log_response_parser.cc
@@ -127,7 +127,8 @@ signed_tree_head->tree_size = parsed_sth.tree_size; signed_tree_head->timestamp = base::Time::UnixEpoch() + - base::TimeDelta::FromMilliseconds(parsed_sth.timestamp); + base::TimeDelta::FromMilliseconds( + static_cast<int64>(parsed_sth.timestamp)); signed_tree_head->signature = parsed_sth.signature; memcpy(signed_tree_head->sha256_root_hash, parsed_sth.sha256_root_hash.c_str(),
diff --git a/net/cert/x509_certificate_win.cc b/net/cert/x509_certificate_win.cc index 0bed756..c965f69 100644 --- a/net/cert/x509_certificate_win.cc +++ b/net/cert/x509_certificate_win.cc
@@ -37,14 +37,14 @@ void ExplodedTimeToSystemTime(const base::Time::Exploded& exploded, SYSTEMTIME* system_time) { - system_time->wYear = exploded.year; - system_time->wMonth = exploded.month; - system_time->wDayOfWeek = exploded.day_of_week; - system_time->wDay = exploded.day_of_month; - system_time->wHour = exploded.hour; - system_time->wMinute = exploded.minute; - system_time->wSecond = exploded.second; - system_time->wMilliseconds = exploded.millisecond; + system_time->wYear = static_cast<WORD>(exploded.year); + system_time->wMonth = static_cast<WORD>(exploded.month); + system_time->wDayOfWeek = static_cast<WORD>(exploded.day_of_week); + system_time->wDay = static_cast<WORD>(exploded.day_of_month); + system_time->wHour = static_cast<WORD>(exploded.hour); + system_time->wMinute = static_cast<WORD>(exploded.minute); + system_time->wSecond = static_cast<WORD>(exploded.second); + system_time->wMilliseconds = static_cast<WORD>(exploded.millisecond); } //-----------------------------------------------------------------------------
diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc index cd9c9b8..e879a8f 100644 --- a/net/cookies/cookie_monster.cc +++ b/net/cookies/cookie_monster.cc
@@ -1162,6 +1162,7 @@ std::sort(cookie_ptrs.begin(), cookie_ptrs.end(), CookieSorter); CookieList cookies; + cookies.reserve(cookie_ptrs.size()); for (std::vector<CanonicalCookie*>::const_iterator it = cookie_ptrs.begin(); it != cookie_ptrs.end(); it++) cookies.push_back(**it);
diff --git a/net/dns/dns_hosts.cc b/net/dns/dns_hosts.cc index 3867b44b..b4d213b 100644 --- a/net/dns/dns_hosts.cc +++ b/net/dns/dns_hosts.cc
@@ -195,7 +195,8 @@ if (!base::GetFileSize(path, &size)) return false; - UMA_HISTOGRAM_COUNTS("AsyncDNS.HostsSize", size); + UMA_HISTOGRAM_COUNTS("AsyncDNS.HostsSize", + static_cast<base::HistogramBase::Sample>(size)); // Reject HOSTS files larger than |kMaxHostsSize| bytes. const int64 kMaxHostsSize = 1 << 25; // 32MB
diff --git a/net/dns/dns_session.cc b/net/dns/dns_session.cc index d6992f1..0b6292e8e 100644 --- a/net/dns/dns_session.cc +++ b/net/dns/dns_session.cc
@@ -39,7 +39,9 @@ : last_failure_count(0), rtt_estimate(rtt_estimate_param) { rtt_histogram.reset(new base::SampleVector(buckets)); // Seed histogram with 2 samples at |rtt_estimate| timeout. - rtt_histogram->Accumulate(rtt_estimate.InMilliseconds(), 2); + rtt_histogram->Accumulate( + static_cast<base::HistogramBase::Sample>(rtt_estimate.InMilliseconds()), + 2); } // Count of consecutive failures after last success. @@ -100,7 +102,9 @@ RecordServerStats(); } -int DnsSession::NextQueryId() const { return rand_callback_.Run(); } +uint16 DnsSession::NextQueryId() const { + return static_cast<uint16>(rand_callback_.Run()); +} unsigned DnsSession::NextFirstServerIndex() { unsigned index = NextGoodServerIndex(server_index_); @@ -182,8 +186,8 @@ deviation += (abs_error - deviation) / 4; // * delta // Histogram-based method. - server_stats_[server_index]->rtt_histogram - ->Accumulate(rtt.InMilliseconds(), 1); + server_stats_[server_index]->rtt_histogram->Accumulate( + static_cast<base::HistogramBase::Sample>(rtt.InMilliseconds()), 1); } void DnsSession::RecordLostPacket(unsigned server_index, int attempt) {
diff --git a/net/dns/dns_session.h b/net/dns/dns_session.h index 01ba5e5d1..e878a57 100644 --- a/net/dns/dns_session.h +++ b/net/dns/dns_session.h
@@ -66,7 +66,7 @@ NetLog* net_log() const { return net_log_; } // Return the next random query ID. - int NextQueryId() const; + uint16 NextQueryId() const; // Return the index of the first configured server to use on first attempt. unsigned NextFirstServerIndex();
diff --git a/net/dns/dns_transaction.cc b/net/dns/dns_transaction.cc index 03eb7f2..beb2197 100644 --- a/net/dns/dns_transaction.cc +++ b/net/dns/dns_transaction.cc
@@ -392,8 +392,10 @@ if (rv < 0) return rv; - base::WriteBigEndian<uint16>(length_buffer_->data(), - query_->io_buffer()->size()); + uint16 query_size = static_cast<uint16>(query_->io_buffer()->size()); + if (static_cast<int>(query_size) != query_->io_buffer()->size()) + return ERR_FAILED; + base::WriteBigEndian<uint16>(length_buffer_->data(), query_size); buffer_ = new DrainableIOBuffer(length_buffer_.get(), length_buffer_->size()); next_state_ = STATE_SEND_LENGTH;
diff --git a/net/dns/single_request_host_resolver.cc b/net/dns/single_request_host_resolver.cc index 7974abaf..2c4b3aa 100644 --- a/net/dns/single_request_host_resolver.cc +++ b/net/dns/single_request_host_resolver.cc
@@ -8,6 +8,7 @@ #include "base/bind_helpers.h" #include "base/compiler_specific.h" #include "base/logging.h" +#include "base/profiler/scoped_tracker.h" #include "net/base/net_errors.h" namespace net { @@ -63,6 +64,11 @@ } void SingleRequestHostResolver::OnResolveCompletion(int result) { + // TODO(vadimt): Remove ScopedTracker below once crbug.com/436634 is fixed. + tracked_objects::ScopedTracker tracking_profile( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "436634 SingleRequestHostResolver::OnResolveCompletion")); + DCHECK(cur_request_); DCHECK_EQ(false, cur_request_callback_.is_null());
diff --git a/net/filter/gzip_header.cc b/net/filter/gzip_header.cc index 4d1cad91..f4aca6b 100644 --- a/net/filter/gzip_header.cc +++ b/net/filter/gzip_header.cc
@@ -105,7 +105,7 @@ case IN_FEXTRA: { // Grab the rest of the bytes in the extra field, or as many // of them as are actually present so far. - const int num_extra_bytes = static_cast<const int>(std::min( + const uint16 num_extra_bytes = static_cast<uint16>(std::min( static_cast<ptrdiff_t>(extra_length_), (end - pos))); pos += num_extra_bytes;
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc index 896db76..23fb2d1 100644 --- a/net/http/http_cache_transaction.cc +++ b/net/http/http_cache_transaction.cc
@@ -2883,15 +2883,16 @@ } TimeDelta before_send_time = send_request_since_ - first_cache_access_since_; - int before_send_percent = - total_time.ToInternalValue() == 0 ? 0 - : before_send_time * 100 / total_time; - DCHECK_LE(0, before_send_percent); - DCHECK_GE(100, before_send_percent); + int64 before_send_percent = (total_time.ToInternalValue() == 0) ? + 0 : before_send_time * 100 / total_time; + DCHECK_GE(before_send_percent, 0); + DCHECK_LE(before_send_percent, 100); + base::HistogramBase::Sample before_send_sample = + static_cast<base::HistogramBase::Sample>(before_send_percent); UMA_HISTOGRAM_TIMES("HttpCache.AccessToDone.SentRequest", total_time); UMA_HISTOGRAM_TIMES("HttpCache.BeforeSend", before_send_time); - UMA_HISTOGRAM_PERCENTAGE("HttpCache.PercentBeforeSend", before_send_percent); + UMA_HISTOGRAM_PERCENTAGE("HttpCache.PercentBeforeSend", before_send_sample); // TODO(gavinp): Remove or minimize these histograms, particularly the ones // below this comment after we have received initial data. @@ -2900,25 +2901,25 @@ UMA_HISTOGRAM_TIMES("HttpCache.BeforeSend.CantConditionalize", before_send_time); UMA_HISTOGRAM_PERCENTAGE("HttpCache.PercentBeforeSend.CantConditionalize", - before_send_percent); + before_send_sample); break; } case PATTERN_ENTRY_NOT_CACHED: { UMA_HISTOGRAM_TIMES("HttpCache.BeforeSend.NotCached", before_send_time); UMA_HISTOGRAM_PERCENTAGE("HttpCache.PercentBeforeSend.NotCached", - before_send_percent); + before_send_sample); break; } case PATTERN_ENTRY_VALIDATED: { UMA_HISTOGRAM_TIMES("HttpCache.BeforeSend.Validated", before_send_time); UMA_HISTOGRAM_PERCENTAGE("HttpCache.PercentBeforeSend.Validated", - before_send_percent); + before_send_sample); break; } case PATTERN_ENTRY_UPDATED: { UMA_HISTOGRAM_TIMES("HttpCache.BeforeSend.Updated", before_send_time); UMA_HISTOGRAM_PERCENTAGE("HttpCache.PercentBeforeSend.Updated", - before_send_percent); + before_send_sample); break; } default:
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index 8cddaf5b..b4ef356 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.cc
@@ -961,11 +961,6 @@ return result; } - if (result == ERR_QUIC_HANDSHAKE_FAILED) { - ResetConnectionAndRequestForResend(); - return OK; - } - // ERR_CONNECTION_CLOSED is treated differently at this point; if partial // response headers were received, we do the best we can to make sense of it // and send it back up the stack.
diff --git a/net/http/http_response_info.cc b/net/http/http_response_info.cc index 6967d79..c3a4827 100644 --- a/net/http/http_response_info.cc +++ b/net/http/http_response_info.cc
@@ -343,7 +343,7 @@ ssl_info.signed_certificate_timestamps.begin(); it != ssl_info.signed_certificate_timestamps.end(); ++it) { it->sct->Persist(pickle); - pickle->WriteUInt16(it->status); + pickle->WriteUInt16(static_cast<uint16>(it->status)); } } }
diff --git a/net/http/http_server_properties.h b/net/http/http_server_properties.h index a63dc6a..b860cc7 100644 --- a/net/http/http_server_properties.h +++ b/net/http/http_server_properties.h
@@ -13,6 +13,7 @@ #include "base/time/time.h" #include "net/base/host_port_pair.h" #include "net/base/net_export.h" +#include "net/quic/quic_bandwidth.h" #include "net/socket/next_proto.h" #include "net/spdy/spdy_framer.h" // TODO(willchan): Reconsider this. #include "net/spdy/spdy_protocol.h" @@ -143,8 +144,10 @@ class NET_EXPORT HttpServerProperties { public: struct NetworkStats { + NetworkStats() : bandwidth_estimate(QuicBandwidth::Zero()) {} + base::TimeDelta srtt; - uint64 bandwidth_estimate; + QuicBandwidth bandwidth_estimate; }; HttpServerProperties() {}
diff --git a/net/http/http_server_properties_impl.cc b/net/http/http_server_properties_impl.cc index 1bf541bf..8a8e49a3 100644 --- a/net/http/http_server_properties_impl.cc +++ b/net/http/http_server_properties_impl.cc
@@ -127,16 +127,6 @@ } } -// static -std::string HttpServerPropertiesImpl::GetFlattenedSpdyServer( - const net::HostPortPair& host_port_pair) { - std::string spdy_server; - spdy_server.append(host_port_pair.host()); - spdy_server.append(":"); - base::StringAppendF(&spdy_server, "%d", host_port_pair.port()); - return spdy_server; -} - static const AlternateProtocolInfo* g_forced_alternate_protocol = NULL; // static @@ -172,10 +162,9 @@ DCHECK(CalledOnValidThread()); if (host_port_pair.host().empty()) return false; - std::string spdy_server = GetFlattenedSpdyServer(host_port_pair); SpdyServerHostPortMap::iterator spdy_host_port = - spdy_servers_map_.Get(spdy_server); + spdy_servers_map_.Get(host_port_pair.ToString()); if (spdy_host_port != spdy_servers_map_.end()) return spdy_host_port->second; return false; @@ -187,16 +176,15 @@ DCHECK(CalledOnValidThread()); if (host_port_pair.host().empty()) return; - std::string spdy_server = GetFlattenedSpdyServer(host_port_pair); SpdyServerHostPortMap::iterator spdy_host_port = - spdy_servers_map_.Get(spdy_server); + spdy_servers_map_.Get(host_port_pair.ToString()); if ((spdy_host_port != spdy_servers_map_.end()) && (spdy_host_port->second == support_spdy)) { return; } // Cache the data. - spdy_servers_map_.Put(spdy_server, support_spdy); + spdy_servers_map_.Put(host_port_pair.ToString(), support_spdy); } bool HttpServerPropertiesImpl::HasAlternateProtocol( @@ -204,12 +192,16 @@ if (g_forced_alternate_protocol) return true; AlternateProtocolMap::const_iterator it = alternate_protocol_map_.Get(server); - if (it != alternate_protocol_map_.end() && - it->second.probability >= alternate_protocol_probability_threshold_) { - return true; + if (it != alternate_protocol_map_.end()) + return it->second.probability >= alternate_protocol_probability_threshold_; + + auto canonical = GetCanonicalHost(server); + if (canonical == canonical_host_to_origin_map_.end() || + canonical->second.Equals(server)) { + return false; } - return GetCanonicalHost(server) != canonical_host_to_origin_map_.end(); + return HasAlternateProtocol(canonical->second); } std::string HttpServerPropertiesImpl::GetCanonicalSuffix(
diff --git a/net/http/http_server_properties_impl_unittest.cc b/net/http/http_server_properties_impl_unittest.cc index 3d1bacb..4dda0db 100644 --- a/net/http/http_server_properties_impl_unittest.cc +++ b/net/http/http_server_properties_impl_unittest.cc
@@ -34,12 +34,10 @@ TEST_F(SpdyServerPropertiesTest, Initialize) { HostPortPair spdy_server_google("www.google.com", 443); - std::string spdy_server_g = - HttpServerPropertiesImpl::GetFlattenedSpdyServer(spdy_server_google); + std::string spdy_server_g = spdy_server_google.ToString(); HostPortPair spdy_server_docs("docs.google.com", 443); - std::string spdy_server_d = - HttpServerPropertiesImpl::GetFlattenedSpdyServer(spdy_server_docs); + std::string spdy_server_d = spdy_server_docs.ToString(); // Check by initializing NULL spdy servers. impl_.InitializeSpdyServers(NULL, true); @@ -155,11 +153,9 @@ std::string string_value_g; std::string string_value_m; HostPortPair spdy_server_google("www.google.com", 443); - std::string spdy_server_g = - HttpServerPropertiesImpl::GetFlattenedSpdyServer(spdy_server_google); + std::string spdy_server_g = spdy_server_google.ToString(); HostPortPair spdy_server_mail("mail.google.com", 443); - std::string spdy_server_m = - HttpServerPropertiesImpl::GetFlattenedSpdyServer(spdy_server_mail); + std::string spdy_server_m = spdy_server_mail.ToString(); // Add www.google.com:443 as not supporting SPDY. impl_.SetSupportsSpdy(spdy_server_google, false); @@ -204,11 +200,9 @@ std::string string_value_g; std::string string_value_m; HostPortPair spdy_server_google("www.google.com", 443); - std::string spdy_server_g = - HttpServerPropertiesImpl::GetFlattenedSpdyServer(spdy_server_google); + std::string spdy_server_g = spdy_server_google.ToString(); HostPortPair spdy_server_mail("mail.google.com", 443); - std::string spdy_server_m = - HttpServerPropertiesImpl::GetFlattenedSpdyServer(spdy_server_mail); + std::string spdy_server_m = spdy_server_mail.ToString(); // Add www.google.com:443 as supporting SPDY. impl_.SetSupportsSpdy(spdy_server_google, true); @@ -445,6 +439,36 @@ EXPECT_EQ(".c.youtube.com", impl_.GetCanonicalSuffix(canonical_port_pair)); } +TEST_F(AlternateProtocolServerPropertiesTest, CanonicalBelowThreshold) { + impl_.SetAlternateProtocolProbabilityThreshold(0.02); + + HostPortPair test_host_port_pair("foo.c.youtube.com", 80); + HostPortPair canonical_port_pair("bar.c.youtube.com", 80); + AlternateProtocolInfo canonical_protocol(1234, QUIC, 0.01); + + impl_.SetAlternateProtocol(canonical_port_pair, + canonical_protocol.port, + canonical_protocol.protocol, + canonical_protocol.probability); + EXPECT_FALSE(impl_.HasAlternateProtocol(canonical_port_pair)); + EXPECT_FALSE(impl_.HasAlternateProtocol(test_host_port_pair)); +} + +TEST_F(AlternateProtocolServerPropertiesTest, CanonicalAboveThreshold) { + impl_.SetAlternateProtocolProbabilityThreshold(0.02); + + HostPortPair test_host_port_pair("foo.c.youtube.com", 80); + HostPortPair canonical_port_pair("bar.c.youtube.com", 80); + AlternateProtocolInfo canonical_protocol(1234, QUIC, 0.03); + + impl_.SetAlternateProtocol(canonical_port_pair, + canonical_protocol.port, + canonical_protocol.protocol, + canonical_protocol.probability); + EXPECT_TRUE(impl_.HasAlternateProtocol(canonical_port_pair)); + EXPECT_TRUE(impl_.HasAlternateProtocol(test_host_port_pair)); +} + TEST_F(AlternateProtocolServerPropertiesTest, ClearCanonical) { HostPortPair test_host_port_pair("foo.c.youtube.com", 80); HostPortPair canonical_port_pair("bar.c.youtube.com", 80);
diff --git a/net/http/http_stream_parser.cc b/net/http/http_stream_parser.cc index b998986..41b85df 100644 --- a/net/http/http_stream_parser.cc +++ b/net/http/http_stream_parser.cc
@@ -25,7 +25,7 @@ namespace { -const size_t kMaxMergedHeaderAndBodySize = 1400; +const uint64 kMaxMergedHeaderAndBodySize = 1400; const size_t kRequestBodyBufferSize = 1 << 14; // 16KB std::string GetResponseHeaderLines(const HttpResponseHeaders& headers) { @@ -59,12 +59,12 @@ return false; } -base::Value* NetLogSendRequestBodyCallback(int length, +base::Value* NetLogSendRequestBodyCallback(uint64 length, bool is_chunked, bool did_merge, NetLog::LogLevel /* log_level */) { base::DictionaryValue* dict = new base::DictionaryValue(); - dict->SetInteger("length", length); + dict->SetInteger("length", static_cast<int>(length)); dict->SetBoolean("is_chunked", is_chunked); dict->SetBoolean("did_merge", did_merge); return dict; @@ -253,8 +253,8 @@ // single write. bool did_merge = false; if (ShouldMergeRequestHeadersAndBody(request, request_->upload_data_stream)) { - size_t merged_size = - request_headers_length_ + request_->upload_data_stream->size(); + int merged_size = static_cast<int>( + request_headers_length_ + request_->upload_data_stream->size()); scoped_refptr<IOBuffer> merged_request_headers_and_body( new IOBuffer(merged_size)); // We'll repurpose |request_headers_| to store the merged headers and @@ -265,10 +265,10 @@ memcpy(request_headers_->data(), request.data(), request_headers_length_); request_headers_->DidConsume(request_headers_length_); - size_t todo = request_->upload_data_stream->size(); + uint64 todo = request_->upload_data_stream->size(); while (todo) { - int consumed = request_->upload_data_stream - ->Read(request_headers_.get(), todo, CompletionCallback()); + int consumed = request_->upload_data_stream->Read( + request_headers_.get(), static_cast<int>(todo), CompletionCallback()); DCHECK_GT(consumed, 0); // Read() won't fail if not chunked. request_headers_->DidConsume(consumed); todo -= consumed; @@ -1059,7 +1059,7 @@ // IsInMemory() ensures that the request body is not chunked. request_body->IsInMemory() && request_body->size() > 0) { - size_t merged_size = request_headers.size() + request_body->size(); + uint64 merged_size = request_headers.size() + request_body->size(); if (merged_size <= kMaxMergedHeaderAndBodySize) return true; }
diff --git a/net/http/transport_security_state.cc b/net/http/transport_security_state.cc index 6217d579..a2d377e 100644 --- a/net/http/transport_security_state.cc +++ b/net/http/transport_security_state.cc
@@ -264,7 +264,7 @@ break; for (size_t j = 0; j < label_length; ++j) { - new_host[i + 1 + j] = tolower(new_host[i + 1 + j]); + new_host[i + 1 + j] = static_cast<char>(tolower(new_host[i + 1 + j])); } }
diff --git a/net/net.gyp b/net/net.gyp index da91a92..5ddf4307 100644 --- a/net/net.gyp +++ b/net/net.gyp
@@ -1570,6 +1570,7 @@ '../base/base.gyp:base', 'cert_verify_status_android_java', 'certificate_mime_types_java', + 'network_change_notifier_types_java', 'net_errors_java', 'private_key_types_java', 'remote_android_keystore_aidl', @@ -1640,6 +1641,14 @@ 'includes': [ '../build/android/java_cpp_enum.gypi' ], }, { + 'target_name': 'network_change_notifier_types_java', + 'type': 'none', + 'variables': { + 'source_file': 'base/network_change_notifier.h', + }, + 'includes': [ '../build/android/java_cpp_enum.gypi' ], + }, + { 'target_name': 'private_key_types_java', 'type': 'none', 'variables': {
diff --git a/net/net_unittests.isolate b/net/net_unittests.isolate index e57f957..e062a7d6 100644 --- a/net/net_unittests.isolate +++ b/net/net_unittests.isolate
@@ -26,7 +26,7 @@ '../third_party/pywebsocket/', '../third_party/tlslite/', '<(PRODUCT_DIR)/net_unittests<(EXECUTABLE_SUFFIX)', - '<(PRODUCT_DIR)/pyproto/', + '<(PRODUCT_DIR)/pyproto/google/', 'tools/testserver/', ], 'read_only': 1,
diff --git a/net/proxy/proxy_resolver_v8_tracing.cc b/net/proxy/proxy_resolver_v8_tracing.cc index 17145d12..c498f74 100644 --- a/net/proxy/proxy_resolver_v8_tracing.cc +++ b/net/proxy/proxy_resolver_v8_tracing.cc
@@ -6,6 +6,7 @@ #include "base/bind.h" #include "base/message_loop/message_loop_proxy.h" +#include "base/profiler/scoped_tracker.h" #include "base/strings/stringprintf.h" #include "base/synchronization/cancellation_flag.h" #include "base/synchronization/waitable_event.h" @@ -717,6 +718,11 @@ } void ProxyResolverV8Tracing::Job::OnDnsOperationComplete(int result) { + // TODO(vadimt): Remove ScopedTracker below once crbug.com/436634 is fixed. + tracked_objects::ScopedTracker tracking_profile( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "436634 ProxyResolverV8Tracing::Job::OnDnsOperationComplete")); + CheckIsOnOriginThread(); DCHECK(!cancelled_.IsSet());
diff --git a/net/quic/congestion_control/cube_root.cc b/net/quic/congestion_control/cube_root.cc index c563ad9..191cccc 100644 --- a/net/quic/congestion_control/cube_root.cc +++ b/net/quic/congestion_control/cube_root.cc
@@ -64,7 +64,7 @@ if (msb < 7) { // MSB in our table. - return ((cube_root_table[static_cast<uint32>(a)]) + 31) >> 6; + return ((cube_root_table[a]) + 31) >> 6; } // MSB 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, ... // cubic_shift 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, ... @@ -72,9 +72,8 @@ cubic_shift = ((cubic_shift * 342) >> 10); // Div by 3, biased high. // 4 to 6 bits accuracy depending on MSB. - uint32 down_shifted_to_6bit = (a >> (cubic_shift * 3)); - uint64 root = ((cube_root_table[down_shifted_to_6bit] + 10) << cubic_shift) - >> 6; + uint64 root = + ((cube_root_table[a >> (cubic_shift * 3)] + 10) << cubic_shift) >> 6; // Make one Newton-Raphson iteration. // Since x has an error (inaccuracy due to the use of fix point) we get a
diff --git a/net/quic/congestion_control/cubic.cc b/net/quic/congestion_control/cubic.cc index eaec621..55ce803 100644 --- a/net/quic/congestion_control/cubic.cc +++ b/net/quic/congestion_control/cubic.cc
@@ -161,8 +161,8 @@ // suddenly, leading to more than one iteration through the following loop. while (true) { // Update estimated TCP congestion_window. - uint32 required_ack_count = - estimated_tcp_congestion_window_ / Alpha(); + QuicPacketCount required_ack_count = static_cast<QuicPacketCount>( + estimated_tcp_congestion_window_ / Alpha()); if (acked_packets_count_ < required_ack_count) { break; }
diff --git a/net/quic/congestion_control/cubic.h b/net/quic/congestion_control/cubic.h index fd53533..76faf561 100644 --- a/net/quic/congestion_control/cubic.h +++ b/net/quic/congestion_control/cubic.h
@@ -71,7 +71,7 @@ QuicPacketCount last_max_congestion_window_; // Number of acked packets since the cycle started (epoch). - uint32 acked_packets_count_; + QuicPacketCount acked_packets_count_; // TCP Reno equivalent congestion window in packets. QuicPacketCount estimated_tcp_congestion_window_;
diff --git a/net/quic/congestion_control/cubic_test.cc b/net/quic/congestion_control/cubic_test.cc index 915274a1..0b99b0a 100644 --- a/net/quic/congestion_control/cubic_test.cc +++ b/net/quic/congestion_control/cubic_test.cc
@@ -35,8 +35,8 @@ TEST_F(CubicTest, AboveOrigin) { // Convex growth. const QuicTime::Delta rtt_min = hundred_ms_; - uint32 current_cwnd = 10; - uint32 expected_cwnd = current_cwnd + 1; + QuicPacketCount current_cwnd = 10; + QuicPacketCount expected_cwnd = current_cwnd + 1; // Initialize the state. clock_.AdvanceTime(one_ms_); EXPECT_EQ(expected_cwnd, @@ -44,7 +44,7 @@ current_cwnd = expected_cwnd; // Normal TCP phase. for (int i = 0; i < 48; ++i) { - for (uint32 n = 1; n < current_cwnd / kNConnectionAlpha; ++n) { + for (QuicPacketCount n = 1; n < current_cwnd / kNConnectionAlpha; ++n) { // Call once per ACK. EXPECT_NEAR(current_cwnd, cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min), 1); @@ -56,7 +56,7 @@ } // Cubic phase. for (int i = 0; i < 52; ++i) { - for (uint32 n = 1; n < current_cwnd; ++n) { + for (QuicPacketCount n = 1; n < current_cwnd; ++n) { // Call once per ACK. EXPECT_EQ(current_cwnd, cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min)); @@ -74,15 +74,15 @@ TEST_F(CubicTest, CwndIncreaseStatsDuringConvexRegion) { const QuicTime::Delta rtt_min = hundred_ms_; - uint32 current_cwnd = 10; - uint32 expected_cwnd = current_cwnd + 1; + QuicPacketCount current_cwnd = 10; + QuicPacketCount expected_cwnd = current_cwnd + 1; // Initialize controller state. clock_.AdvanceTime(one_ms_); expected_cwnd = cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min); current_cwnd = expected_cwnd; // Testing Reno mode increase. for (int i = 0; i < 48; ++i) { - for (uint32 n = 1; n < current_cwnd / kNConnectionAlpha; ++n) { + for (QuicPacketCount n = 1; n < current_cwnd / kNConnectionAlpha; ++n) { // Call once per ACK, causing cwnd growth in Reno mode. cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min); } @@ -94,13 +94,13 @@ EXPECT_NEAR(1u, stats_.cwnd_increase_cubic_mode, 1); expected_cwnd++; } - uint32 old_cwnd = current_cwnd; + QuicPacketCount old_cwnd = current_cwnd; stats_.cwnd_increase_cubic_mode = 0; stats_.cwnd_increase_congestion_avoidance = 0; // Testing Cubic mode increase. for (int i = 0; i < 52; ++i) { - for (uint32 n = 1; n < current_cwnd; ++n) { + for (QuicPacketCount n = 1; n < current_cwnd; ++n) { // Call once per ACK. cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min); } @@ -120,16 +120,16 @@ TEST_F(CubicTest, LossEvents) { const QuicTime::Delta rtt_min = hundred_ms_; - uint32 current_cwnd = 422; - uint32 expected_cwnd = current_cwnd + 1; + QuicPacketCount current_cwnd = 422; + QuicPacketCount expected_cwnd = current_cwnd + 1; // Initialize the state. clock_.AdvanceTime(one_ms_); EXPECT_EQ(expected_cwnd, cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min)); - expected_cwnd = static_cast<int>(current_cwnd * kNConnectionBeta); + expected_cwnd = static_cast<QuicPacketCount>(current_cwnd * kNConnectionBeta); EXPECT_EQ(expected_cwnd, cubic_.CongestionWindowAfterPacketLoss(current_cwnd)); - expected_cwnd = static_cast<int>(current_cwnd * kNConnectionBeta); + expected_cwnd = static_cast<QuicPacketCount>(current_cwnd * kNConnectionBeta); EXPECT_EQ(expected_cwnd, cubic_.CongestionWindowAfterPacketLoss(current_cwnd)); } @@ -137,19 +137,19 @@ TEST_F(CubicTest, BelowOrigin) { // Concave growth. const QuicTime::Delta rtt_min = hundred_ms_; - uint32 current_cwnd = 422; - uint32 expected_cwnd = current_cwnd + 1; + QuicPacketCount current_cwnd = 422; + QuicPacketCount expected_cwnd = current_cwnd + 1; // Initialize the state. clock_.AdvanceTime(one_ms_); EXPECT_EQ(expected_cwnd, cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min)); - expected_cwnd = static_cast<int>(current_cwnd * kNConnectionBeta); + expected_cwnd = static_cast<QuicPacketCount>(current_cwnd * kNConnectionBeta); EXPECT_EQ(expected_cwnd, cubic_.CongestionWindowAfterPacketLoss(current_cwnd)); current_cwnd = expected_cwnd; // First update after loss to initialize the epoch. current_cwnd = cubic_.CongestionWindowAfterAck(current_cwnd, rtt_min); - uint32 old_cwnd = current_cwnd; + QuicPacketCount old_cwnd = current_cwnd; // Cubic phase. stats_.cwnd_increase_cubic_mode = 0; stats_.cwnd_increase_congestion_avoidance = 0;
diff --git a/net/quic/congestion_control/rtt_stats.cc b/net/quic/congestion_control/rtt_stats.cc index 32e3b58a..6c2687d 100644 --- a/net/quic/congestion_control/rtt_stats.cc +++ b/net/quic/congestion_control/rtt_stats.cc
@@ -79,9 +79,9 @@ mean_deviation_ = QuicTime::Delta::FromMicroseconds( rtt_sample.ToMicroseconds() / 2); } else { - mean_deviation_ = QuicTime::Delta::FromMicroseconds( + mean_deviation_ = QuicTime::Delta::FromMicroseconds(static_cast<int64>( kOneMinusBeta * mean_deviation_.ToMicroseconds() + - kBeta * std::abs(smoothed_rtt_.Subtract(rtt_sample).ToMicroseconds())); + kBeta * std::abs(smoothed_rtt_.Subtract(rtt_sample).ToMicroseconds()))); smoothed_rtt_ = smoothed_rtt_.Multiply(kOneMinusAlpha).Add( rtt_sample.Multiply(kAlpha)); DVLOG(1) << " smoothed_rtt(us):" << smoothed_rtt_.ToMicroseconds()
diff --git a/net/quic/congestion_control/tcp_cubic_sender.h b/net/quic/congestion_control/tcp_cubic_sender.h index 40c8219..e07e480c 100644 --- a/net/quic/congestion_control/tcp_cubic_sender.h +++ b/net/quic/congestion_control/tcp_cubic_sender.h
@@ -118,7 +118,7 @@ QuicPacketCount congestion_window_; // Congestion window before the last loss event or RTO. - QuicByteCount previous_congestion_window_; + QuicPacketCount previous_congestion_window_; // Slow start congestion window in packets, aka ssthresh. QuicPacketCount slowstart_threshold_;
diff --git a/net/quic/congestion_control/tcp_loss_algorithm.h b/net/quic/congestion_control/tcp_loss_algorithm.h index 03047cf8..a5f245e 100644 --- a/net/quic/congestion_control/tcp_loss_algorithm.h +++ b/net/quic/congestion_control/tcp_loss_algorithm.h
@@ -21,7 +21,7 @@ class NET_EXPORT_PRIVATE TCPLossAlgorithm : public LossDetectionInterface { public: // TCP retransmits after 3 nacks. - static const size_t kNumberOfNacksBeforeRetransmission = 3; + static const QuicPacketCount kNumberOfNacksBeforeRetransmission = 3; TCPLossAlgorithm(); ~TCPLossAlgorithm() override {}
diff --git a/net/quic/crypto/cert_compressor.cc b/net/quic/crypto/cert_compressor.cc index ba42152..95bb553 100644 --- a/net/quic/crypto/cert_compressor.cc +++ b/net/quic/crypto/cert_compressor.cc
@@ -260,7 +260,7 @@ void SerializeCertEntries(uint8* out, const vector<CertEntry>& entries) { for (vector<CertEntry>::const_iterator i = entries.begin(); i != entries.end(); ++i) { - *out++ = i->type; + *out++ = static_cast<uint8>(i->type); switch (i->type) { case CertEntry::COMPRESSED: break;
diff --git a/net/quic/crypto/crypto_framer.cc b/net/quic/crypto/crypto_framer.cc index 029ec53..79e17edbf 100644 --- a/net/quic/crypto/crypto_framer.cc +++ b/net/quic/crypto/crypto_framer.cc
@@ -112,7 +112,7 @@ DCHECK(false) << "Failed to write message tag."; return nullptr; } - if (!writer.WriteUInt16(num_entries)) { + if (!writer.WriteUInt16(static_cast<uint16>(num_entries))) { DCHECK(false) << "Failed to write size."; return nullptr; }
diff --git a/net/quic/crypto/crypto_utils.cc b/net/quic/crypto/crypto_utils.cc index 67af2e946..c595775 100644 --- a/net/quic/crypto/crypto_utils.cc +++ b/net/quic/crypto/crypto_utils.cc
@@ -28,19 +28,21 @@ // a 4-byte timestamp + 28 random bytes. nonce->reserve(kNonceSize); nonce->resize(kNonceSize); - uint32 gmt_unix_time = now.ToUNIXSeconds(); + + uint32 gmt_unix_time = static_cast<uint32>(now.ToUNIXSeconds()); // The time in the nonce must be encoded in big-endian because the // strike-register depends on the nonces being ordered by time. (*nonce)[0] = static_cast<char>(gmt_unix_time >> 24); (*nonce)[1] = static_cast<char>(gmt_unix_time >> 16); (*nonce)[2] = static_cast<char>(gmt_unix_time >> 8); (*nonce)[3] = static_cast<char>(gmt_unix_time); + size_t bytes_written = 4; - size_t bytes_written = sizeof(gmt_unix_time); if (orbit.size() == 8) { memcpy(&(*nonce)[bytes_written], orbit.data(), orbit.size()); bytes_written += orbit.size(); } + random_generator->RandBytes(&(*nonce)[bytes_written], kNonceSize - bytes_written); }
diff --git a/net/quic/crypto/p256_key_exchange_nss.cc b/net/quic/crypto/p256_key_exchange_nss.cc index 73aa03d..3296a6f 100644 --- a/net/quic/crypto/p256_key_exchange_nss.cc +++ b/net/quic/crypto/p256_key_exchange_nss.cc
@@ -5,6 +5,7 @@ #include "net/quic/crypto/p256_key_exchange.h" #include "base/logging.h" +#include "base/numerics/safe_conversions.h" #include "base/sys_byteorder.h" using base::StringPiece; @@ -131,7 +132,7 @@ } // TODO(thaidn): determine how large encrypted private key can be - uint16 private_key_size = private_key.size(); + uint16 private_key_size = base::checked_cast<uint16>(private_key.size()); const size_t result_size = sizeof(private_key_size) + private_key_size + public_key.size();
diff --git a/net/quic/crypto/quic_crypto_server_config.cc b/net/quic/crypto/quic_crypto_server_config.cc index 5a650b6..4623ff5 100644 --- a/net/quic/crypto/quic_crypto_server_config.cc +++ b/net/quic/crypto/quic_crypto_server_config.cc
@@ -251,9 +251,13 @@ string encoded_public_values; // First three bytes encode the length of the public value. - encoded_public_values.push_back(curve25519_public_value.size()); - encoded_public_values.push_back(curve25519_public_value.size() >> 8); - encoded_public_values.push_back(curve25519_public_value.size() >> 16); + DCHECK_LT(curve25519_public_value.size(), (1U << 24)); + encoded_public_values.push_back( + static_cast<char>(curve25519_public_value.size())); + encoded_public_values.push_back( + static_cast<char>(curve25519_public_value.size() >> 8)); + encoded_public_values.push_back( + static_cast<char>(curve25519_public_value.size() >> 16)); encoded_public_values.append(curve25519_public_value.data(), curve25519_public_value.size()); @@ -263,9 +267,13 @@ scoped_ptr<P256KeyExchange> p256(P256KeyExchange::New(p256_private_key)); StringPiece p256_public_value = p256->public_value(); - encoded_public_values.push_back(p256_public_value.size()); - encoded_public_values.push_back(p256_public_value.size() >> 8); - encoded_public_values.push_back(p256_public_value.size() >> 16); + DCHECK_LT(p256_public_value.size(), (1U << 24)); + encoded_public_values.push_back( + static_cast<char>(p256_public_value.size())); + encoded_public_values.push_back( + static_cast<char>(p256_public_value.size() >> 8)); + encoded_public_values.push_back( + static_cast<char>(p256_public_value.size() >> 16)); encoded_public_values.append(p256_public_value.data(), p256_public_value.size()); }
diff --git a/net/quic/crypto/source_address_token.cc b/net/quic/crypto/source_address_token.cc index 5faedaa6..5c1877a 100644 --- a/net/quic/crypto/source_address_token.cc +++ b/net/quic/crypto/source_address_token.cc
@@ -20,10 +20,10 @@ string SourceAddressToken::SerializeAsString() const { string out; - out.push_back(ip_.size()); + out.push_back(static_cast<char>(ip_.size())); out.append(ip_); string time_str = base::Int64ToString(timestamp_); - out.push_back(time_str.size()); + out.push_back(static_cast<char>(time_str.size())); out.append(time_str); // TODO(rtenneti): Implement serialization of optional CachedNetworkParameters // when they are used.
diff --git a/net/quic/crypto/source_address_token.h b/net/quic/crypto/source_address_token.h index f9a5098..32f11c5 100644 --- a/net/quic/crypto/source_address_token.h +++ b/net/quic/crypto/source_address_token.h
@@ -8,6 +8,7 @@ #include <string> #include "base/basictypes.h" +#include "base/logging.h" #include "base/strings/string_piece.h" #include "net/base/net_export.h" #include "net/quic/crypto/cached_network_parameters.h" @@ -31,6 +32,8 @@ } void set_ip(base::StringPiece ip) { ip_ = ip.as_string(); + DCHECK_LE(ip_.size(), + static_cast<size_t>(std::numeric_limits<char>::max())); } int64 timestamp() const {
diff --git a/net/quic/crypto/strike_register.cc b/net/quic/crypto/strike_register.cc index d727ece..fd5dc4f 100644 --- a/net/quic/crypto/strike_register.cc +++ b/net/quic/crypto/strike_register.cc
@@ -66,9 +66,9 @@ uint32 child(unsigned n) const { return data_[n] >> 8; } - uint8 critbyte() const { return data_[0]; } + uint8 critbyte() const { return static_cast<uint8>(data_[0]); } - uint8 otherbits() const { return data_[1]; } + uint8 otherbits() const { return static_cast<uint8>(data_[1]); } // These bytes are organised thus: // <24 bits> left child @@ -194,9 +194,10 @@ } // Now we need to find the first bit where we differ from |best_match|. - unsigned differing_byte; + uint8 differing_byte; uint8 new_other_bits; - for (differing_byte = 0; differing_byte < sizeof(value); differing_byte++) { + for (differing_byte = 0; differing_byte < arraysize(value); + differing_byte++) { new_other_bits = value[differing_byte] ^ best_match[differing_byte]; if (new_other_bits) { break;
diff --git a/net/quic/quic_bandwidth.cc b/net/quic/quic_bandwidth.cc index dbce39d..8612d5f 100644 --- a/net/quic/quic_bandwidth.cc +++ b/net/quic/quic_bandwidth.cc
@@ -96,7 +96,7 @@ } QuicBandwidth QuicBandwidth::Scale(float scale_factor) const { - return QuicBandwidth(bits_per_second_ * scale_factor); + return QuicBandwidth(static_cast<int64>(bits_per_second_ * scale_factor)); } QuicTime::Delta QuicBandwidth::TransferTime(QuicByteCount bytes) const {
diff --git a/net/quic/quic_client_session.cc b/net/quic/quic_client_session.cc index 37aa311..ef8bc20 100644 --- a/net/quic/quic_client_session.cc +++ b/net/quic/quic_client_session.cc
@@ -318,8 +318,9 @@ UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.MaxReorderingTimeLongRtt", reordering, 0, kMaxReordering, 50); } - UMA_HISTOGRAM_COUNTS("Net.QuicSession.MaxReordering", - stats.max_sequence_reordering); + UMA_HISTOGRAM_COUNTS( + "Net.QuicSession.MaxReordering", + static_cast<base::HistogramBase::Sample>(stats.max_sequence_reordering)); } void QuicClientSession::OnStreamFrames( @@ -451,7 +452,7 @@ // Report the TLS cipher suite that most closely resembles the crypto // parameters of the QUIC connection. QuicTag aead = crypto_stream_->crypto_negotiated_params().aead; - int cipher_suite; + uint16 cipher_suite; int security_bits; switch (aead) { case kAESG: @@ -467,9 +468,7 @@ return false; } int ssl_connection_status = 0; - ssl_connection_status |= - (cipher_suite & SSL_CONNECTION_CIPHERSUITE_MASK) << - SSL_CONNECTION_CIPHERSUITE_SHIFT; + ssl_connection_status |= cipher_suite; ssl_connection_status |= (SSL_CONNECTION_VERSION_QUIC & SSL_CONNECTION_VERSION_MASK) << SSL_CONNECTION_VERSION_SHIFT;
diff --git a/net/quic/quic_config.cc b/net/quic/quic_config.cc index 622cf3f..d2a10a4 100644 --- a/net/quic/quic_config.cc +++ b/net/quic/quic_config.cc
@@ -484,8 +484,8 @@ QuicTime::Delta max_idle_connection_state_lifetime, QuicTime::Delta default_idle_conection_state_lifetime) { idle_connection_state_lifetime_seconds_.set( - max_idle_connection_state_lifetime.ToSeconds(), - default_idle_conection_state_lifetime.ToSeconds()); + static_cast<uint32>(max_idle_connection_state_lifetime.ToSeconds()), + static_cast<uint32>(default_idle_conection_state_lifetime.ToSeconds())); } QuicTime::Delta QuicConfig::IdleConnectionStateLifetime() const { @@ -523,7 +523,7 @@ return bytes_for_connection_id_.GetReceivedValue(); } -void QuicConfig::SetInitialRoundTripTimeUsToSend(size_t rtt) { +void QuicConfig::SetInitialRoundTripTimeUsToSend(uint32 rtt) { initial_round_trip_time_us_.SetSendValue(rtt); }
diff --git a/net/quic/quic_config.h b/net/quic/quic_config.h index cf3775c..507dd9dc 100644 --- a/net/quic/quic_config.h +++ b/net/quic/quic_config.h
@@ -320,7 +320,7 @@ uint32 ReceivedBytesForConnectionId() const; // Sets an estimated initial round trip time in us. - void SetInitialRoundTripTimeUsToSend(size_t rtt_us); + void SetInitialRoundTripTimeUsToSend(uint32 rtt_us); bool HasReceivedInitialRoundTripTimeUs() const;
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc index ca48185..c33aec5 100644 --- a/net/quic/quic_connection.cc +++ b/net/quic/quic_connection.cc
@@ -15,6 +15,7 @@ #include <utility> #include "base/debug/stack_trace.h" +#include "base/format_macros.h" #include "base/logging.h" #include "base/stl_util.h" #include "base/strings/stringprintf.h" @@ -57,10 +58,10 @@ const size_t kMaxFecGroups = 2; // Maximum number of acks received before sending an ack in response. -const size_t kMaxPacketsReceivedBeforeAckSend = 20; +const QuicPacketCount kMaxPacketsReceivedBeforeAckSend = 20; // Maximum number of tracked packets. -const size_t kMaxTrackedPackets = 5 * kMaxTcpCongestionWindow;; +const QuicPacketCount kMaxTrackedPackets = 5 * kMaxTcpCongestionWindow; bool Near(QuicPacketSequenceNumber a, QuicPacketSequenceNumber b) { QuicPacketSequenceNumber delta = (a > b) ? a - b : b - a; @@ -949,14 +950,14 @@ (sent_packet_manager_.GetLeastUnacked() + kMaxTrackedPackets)) { SendConnectionCloseWithDetails( QUIC_TOO_MANY_OUTSTANDING_SENT_PACKETS, - StringPrintf("More than %zu outstanding.", kMaxTrackedPackets)); + StringPrintf("More than %" PRIu64 " outstanding.", kMaxTrackedPackets)); } // This occurs if there are received packet gaps and the peer does not raise // the least unacked fast enough. if (received_packet_manager_.NumTrackedPackets() > kMaxTrackedPackets) { SendConnectionCloseWithDetails( QUIC_TOO_MANY_OUTSTANDING_RECEIVED_PACKETS, - StringPrintf("More than %zu outstanding.", kMaxTrackedPackets)); + StringPrintf("More than %" PRIu64 " outstanding.", kMaxTrackedPackets)); } } @@ -1138,8 +1139,7 @@ sent_packet_manager_.GetRttStats()->min_rtt().ToMicroseconds(); stats_.srtt_us = sent_packet_manager_.GetRttStats()->smoothed_rtt().ToMicroseconds(); - stats_.estimated_bandwidth = - sent_packet_manager_.BandwidthEstimate().ToBytesPerSecond(); + stats_.estimated_bandwidth = sent_packet_manager_.BandwidthEstimate(); stats_.max_packet_size = packet_generator_.max_packet_length(); return stats_; }
diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h index 9e320ae..14c45a1e 100644 --- a/net/quic/quic_connection.h +++ b/net/quic/quic_connection.h
@@ -753,7 +753,7 @@ // Indicates whether an ack should be sent the next time we try to write. bool ack_queued_; // Indicates how many consecutive packets have arrived without sending an ack. - uint32 num_packets_received_since_last_ack_sent_; + QuicPacketCount num_packets_received_since_last_ack_sent_; // Indicates how many consecutive times an ack has arrived which indicates // the peer needs to stop waiting for some packets. int stop_waiting_count_;
diff --git a/net/quic/quic_connection_logger.cc b/net/quic/quic_connection_logger.cc index 205a571..4a125214 100644 --- a/net/quic/quic_connection_logger.cc +++ b/net/quic/quic_connection_logger.cc
@@ -58,7 +58,8 @@ dict->SetString("packet_sequence_number", base::Uint64ToString(serialized_packet.sequence_number)); dict->SetInteger("size", packet_size); - dict->SetInteger("sent_time_us", sent_time.ToDebuggingValue()); + dict->SetInteger("sent_time_us", + static_cast<int>(sent_time.ToDebuggingValue())); return dict; } @@ -85,7 +86,7 @@ base::Uint64ToString(header->packet_sequence_number)); dict->SetInteger("entropy_flag", header->entropy_flag); dict->SetInteger("fec_flag", header->fec_flag); - dict->SetInteger("fec_group", header->fec_group); + dict->SetInteger("fec_group", static_cast<int>(header->fec_group)); return dict; } @@ -104,8 +105,9 @@ base::DictionaryValue* dict = new base::DictionaryValue(); dict->SetString("largest_observed", base::Uint64ToString(frame->largest_observed)); - dict->SetInteger("delta_time_largest_observed_us", - frame->delta_time_largest_observed.ToMicroseconds()); + dict->SetInteger( + "delta_time_largest_observed_us", + static_cast<int>(frame->delta_time_largest_observed.ToMicroseconds())); dict->SetInteger("entropy_hash", frame->entropy_hash); dict->SetBoolean("truncated", frame->is_truncated); @@ -132,8 +134,9 @@ for (PacketTimeList::const_iterator it = received_times.begin(); it != received_times.end(); ++it) { base::DictionaryValue* info = new base::DictionaryValue(); - info->SetInteger("sequence_number", it->first); - info->SetInteger("received", it->second.ToDebuggingValue()); + info->SetInteger("sequence_number", static_cast<int>(it->first)); + info->SetInteger("received", + static_cast<int>(it->second.ToDebuggingValue())); received->Append(info); } @@ -147,7 +150,8 @@ switch (frame->type) { case kTCP: dict->SetString("type", "TCP"); - dict->SetInteger("receive_window", frame->tcp.receive_window); + dict->SetInteger("receive_window", + static_cast<int>(frame->tcp.receive_window)); break; } @@ -552,17 +556,22 @@ // There is a gap between the largest packet previously received and // the current packet. This indicates either loss, or out-of-order // delivery. - UMA_HISTOGRAM_COUNTS("Net.QuicSession.PacketGapReceived", delta - 1); + UMA_HISTOGRAM_COUNTS("Net.QuicSession.PacketGapReceived", + static_cast<base::HistogramBase::Sample>(delta - 1)); } largest_received_packet_sequence_number_ = header.packet_sequence_number; } - if (header.packet_sequence_number < received_packets_.size()) - received_packets_[header.packet_sequence_number] = true; + if (header.packet_sequence_number < received_packets_.size()) { + received_packets_[static_cast<size_t>(header.packet_sequence_number)] = + true; + } if (header.packet_sequence_number < last_received_packet_sequence_number_) { ++num_out_of_order_received_packets_; - UMA_HISTOGRAM_COUNTS("Net.QuicSession.OutOfOrderGapReceived", - last_received_packet_sequence_number_ - - header.packet_sequence_number); + UMA_HISTOGRAM_COUNTS( + "Net.QuicSession.OutOfOrderGapReceived", + static_cast<base::HistogramBase::Sample>( + last_received_packet_sequence_number_ - + header.packet_sequence_number)); } last_received_packet_sequence_number_ = header.packet_sequence_number; } @@ -580,8 +589,10 @@ const size_t kApproximateLargestSoloAckBytes = 100; if (last_received_packet_sequence_number_ < received_acks_.size() && - last_received_packet_size_ < kApproximateLargestSoloAckBytes) - received_acks_[last_received_packet_sequence_number_] = true; + last_received_packet_size_ < kApproximateLargestSoloAckBytes) { + received_acks_[static_cast<size_t>(last_received_packet_sequence_number_)] = + true; + } if (frame.is_truncated) ++num_truncated_acks_received_; @@ -839,7 +850,7 @@ base::HistogramBase* histogram = base::Histogram::FactoryGet( prefix + connection_description_, 1, 1000, 75, base::HistogramBase::kUmaTargetedHistogramFlag); - histogram->Add(numerator / divisor); + histogram->Add(static_cast<base::HistogramBase::Sample>(numerator / divisor)); } void QuicConnectionLogger::RecordLossHistograms() const {
diff --git a/net/quic/quic_connection_logger.h b/net/quic/quic_connection_logger.h index 29acfdc..fdd813a 100644 --- a/net/quic/quic_connection_logger.h +++ b/net/quic/quic_connection_logger.h
@@ -132,7 +132,7 @@ // The number of times that OnPacketHeader was called. // If the network replicates packets, then this number may be slightly // different from the real number of distinct packets received. - QuicPacketSequenceNumber num_packets_received_; + QuicPacketCount num_packets_received_; // Number of times a truncated ACK frame was sent. size_t num_truncated_acks_sent_; // Number of times a truncated ACK frame was received.
diff --git a/net/quic/quic_connection_stats.cc b/net/quic/quic_connection_stats.cc index 6625c61..10425de 100644 --- a/net/quic/quic_connection_stats.cc +++ b/net/quic/quic_connection_stats.cc
@@ -33,7 +33,7 @@ min_rtt_us(0), srtt_us(0), max_packet_size(0), - estimated_bandwidth(0), + estimated_bandwidth(QuicBandwidth::Zero()), packets_reordered(0), max_sequence_reordering(0), max_time_reordering_us(0), @@ -70,7 +70,7 @@ << ", min_rtt(us): " << s.min_rtt_us << ", srtt(us): " << s.srtt_us << ", max packet size: " << s.max_packet_size - << ", estimated bandwidth: " << s.estimated_bandwidth + << ", estimated bandwidth: " << s.estimated_bandwidth.ToBytesPerSecond() << ", tcp_loss_events: " << s.tcp_loss_events << ", packets reordered: " << s.packets_reordered << ", max sequence reordering: " << s.max_sequence_reordering
diff --git a/net/quic/quic_connection_stats.h b/net/quic/quic_connection_stats.h index 2abdb594..247d2c5 100644 --- a/net/quic/quic_connection_stats.h +++ b/net/quic/quic_connection_stats.h
@@ -9,6 +9,8 @@ #include "base/basictypes.h" #include "net/base/net_export.h" +#include "net/quic/quic_bandwidth.h" +#include "net/quic/quic_protocol.h" #include "net/quic/quic_time.h" namespace net { @@ -20,47 +22,52 @@ NET_EXPORT_PRIVATE friend std::ostream& operator<<( std::ostream& os, const QuicConnectionStats& s); - uint64 bytes_sent; // Includes retransmissions, fec. - uint32 packets_sent; - uint64 stream_bytes_sent; // non-retransmitted bytes sent in a stream frame. - uint32 packets_discarded; // Packets serialized and discarded before sending. + QuicByteCount bytes_sent; // Includes retransmissions, fec. + QuicPacketCount packets_sent; + // Non-retransmitted bytes sent in a stream frame. + QuicByteCount stream_bytes_sent; + // Packets serialized and discarded before sending. + QuicPacketCount packets_discarded; // These include version negotiation and public reset packets, which do not // have sequence numbers or frame data. - uint64 bytes_received; // Includes duplicate data for a stream, fec. - uint32 packets_received; // Includes packets which were not processable. - uint32 packets_processed; // Excludes packets which were not processable. - uint64 stream_bytes_received; // Bytes received in a stream frame. + QuicByteCount bytes_received; // Includes duplicate data for a stream, fec. + // Includes packets which were not processable. + QuicPacketCount packets_received; + // Excludes packets which were not processable. + QuicPacketCount packets_processed; + QuicByteCount stream_bytes_received; // Bytes received in a stream frame. - uint64 bytes_retransmitted; - uint32 packets_retransmitted; + QuicByteCount bytes_retransmitted; + QuicPacketCount packets_retransmitted; - uint64 bytes_spuriously_retransmitted; - uint32 packets_spuriously_retransmitted; + QuicByteCount bytes_spuriously_retransmitted; + QuicPacketCount packets_spuriously_retransmitted; // Number of packets abandoned as lost by the loss detection algorithm. - uint32 packets_lost; - uint32 slowstart_packets_lost; // Number of packets lost exiting slow start. + QuicPacketCount packets_lost; + // Number of packets lost exiting slow start. + QuicPacketCount slowstart_packets_lost; - uint32 packets_revived; - uint32 packets_dropped; // Duplicate or less than least unacked. + QuicPacketCount packets_revived; + QuicPacketCount packets_dropped; // Duplicate or less than least unacked. uint32 crypto_retransmit_count; // Count of times the loss detection alarm fired. At least one packet should // be lost when the alarm fires. uint32 loss_timeout_count; - uint32 tlp_count; - uint32 rto_count; // Count of times the rto timer fired. - uint32 spurious_rto_count; + size_t tlp_count; + size_t rto_count; // Count of times the rto timer fired. + size_t spurious_rto_count; int64 min_rtt_us; // Minimum RTT in microseconds. int64 srtt_us; // Smoothed RTT in microseconds. - uint32 max_packet_size; // In bytes. - uint64 estimated_bandwidth; // In bytes per second. + QuicByteCount max_packet_size; + QuicBandwidth estimated_bandwidth; // Reordering stats for received packets. // Number of packets received out of sequence number order. - uint32 packets_reordered; + QuicPacketCount packets_reordered; // Maximum reordering observed in sequence space. - uint32 max_sequence_reordering; + QuicPacketSequenceNumber max_sequence_reordering; // Maximum reordering observed in microseconds int64 max_time_reordering_us; @@ -69,9 +76,9 @@ // one or more lost packets. uint32 tcp_loss_events; // Total amount of cwnd increase by TCPCubic in congestion avoidance. - uint32 cwnd_increase_congestion_avoidance; + QuicPacketCount cwnd_increase_congestion_avoidance; // Total amount of cwnd increase by TCPCubic in cubic mode. - uint32 cwnd_increase_cubic_mode; + QuicPacketCount cwnd_increase_cubic_mode; // Creation time, as reported by the QuicClock. QuicTime connection_creation_time;
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc index ede61c8..32d7544 100644 --- a/net/quic/quic_connection_test.cc +++ b/net/quic/quic_connection_test.cc
@@ -1166,8 +1166,8 @@ } EXPECT_CALL(*loss_algorithm_, DetectLostPackets(_, _, _, _)) .WillOnce(Return(lost_packets)); - EXPECT_CALL(entropy_calculator_, - EntropyHash(511)).WillOnce(testing::Return(0)); + EXPECT_CALL(entropy_calculator_, EntropyHash(511)) + .WillOnce(Return(static_cast<QuicPacketEntropyHash>(0))); EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _)); ProcessAckPacket(&frame);
diff --git a/net/quic/quic_crypto_client_stream.cc b/net/quic/quic_crypto_client_stream.cc index 1c41e0a6..fd740dd 100644 --- a/net/quic/quic_crypto_client_stream.cc +++ b/net/quic/quic_crypto_client_stream.cc
@@ -256,8 +256,8 @@ session()->connection()->supported_versions().front(), cached, &crypto_negotiated_params_, &out); // Pad the inchoate client hello to fill up a packet. - const size_t kFramingOverhead = 50; // A rough estimate. - const size_t max_packet_size = + const QuicByteCount kFramingOverhead = 50; // A rough estimate. + const QuicByteCount max_packet_size = session()->connection()->max_packet_length(); if (max_packet_size <= kFramingOverhead) { DLOG(DFATAL) << "max_packet_length (" << max_packet_size @@ -270,7 +270,8 @@ CloseConnection(QUIC_INTERNAL_ERROR); return; } - out.set_minimum_size(max_packet_size - kFramingOverhead); + out.set_minimum_size( + static_cast<size_t>(max_packet_size - kFramingOverhead)); next_state_ = STATE_RECV_REJ; SendHandshakeMessage(out); return;
diff --git a/net/quic/quic_data_writer.cc b/net/quic/quic_data_writer.cc index 11b6b55..d48f89f 100644 --- a/net/quic/quic_data_writer.cc +++ b/net/quic/quic_data_writer.cc
@@ -11,9 +11,6 @@ #include "base/basictypes.h" #include "base/logging.h" -using base::StringPiece; -using std::numeric_limits; - namespace net { QuicDataWriter::QuicDataWriter(size_t size) @@ -47,8 +44,8 @@ } bool QuicDataWriter::WriteUInt48(uint64 value) { - uint32 hi = value >> 32; - uint32 lo = value & GG_UINT64_C(0x00000000FFFFFFFF); + uint16 hi = static_cast<uint16>(value >> 32); + uint32 lo = static_cast<uint32>(value); return WriteUInt32(lo) && WriteUInt16(hi); } @@ -61,10 +58,10 @@ if (value < (GG_UINT64_C(1) << kUFloat16MantissaEffectiveBits)) { // Fast path: either the value is denormalized, or has exponent zero. // Both cases are represented by the value itself. - result = value; + result = static_cast<uint16>(value); } else if (value >= kUFloat16MaxValue) { // Value is out of range; clamp it to the maximum representable. - result = numeric_limits<uint16>::max(); + result = std::numeric_limits<uint16>::max(); } else { // The highest bit is between position 13 and 42 (zero-based), which // corresponds to exponent 1-30. In the output, mantissa is from 0 to 10, @@ -89,17 +86,17 @@ // Hidden bit (position 11) is set. We should remove it and increment the // exponent. Equivalently, we just add it to the exponent. // This hides the bit. - result = value + (exponent << kUFloat16MantissaBits); + result = static_cast<uint16>(value + (exponent << kUFloat16MantissaBits)); } return WriteBytes(&result, sizeof(result)); } -bool QuicDataWriter::WriteStringPiece16(StringPiece val) { - if (val.length() > numeric_limits<uint16>::max()) { +bool QuicDataWriter::WriteStringPiece16(base::StringPiece val) { + if (val.size() > std::numeric_limits<uint16>::max()) { return false; } - if (!WriteUInt16(val.size())) { + if (!WriteUInt16(static_cast<uint16>(val.size()))) { return false; } return WriteBytes(val.data(), val.size()); @@ -127,7 +124,7 @@ } #ifdef ARCH_CPU_64_BITS - DCHECK_LE(length, numeric_limits<uint32>::max()); + DCHECK_LE(length, std::numeric_limits<uint32>::max()); #endif return buffer_ + length_;
diff --git a/net/quic/quic_fec_group.cc b/net/quic/quic_fec_group.cc index 5d55aed..3d52810 100644 --- a/net/quic/quic_fec_group.cc +++ b/net/quic/quic_fec_group.cc
@@ -164,8 +164,9 @@ size_t QuicFecGroup::NumMissingPackets() const { if (min_protected_packet_ == kNoSequenceNumber) return numeric_limits<size_t>::max(); - return (max_protected_packet_ - min_protected_packet_ + 1) - - received_packets_.size(); + return static_cast<size_t>( + (max_protected_packet_ - min_protected_packet_ + 1) - + received_packets_.size()); } } // namespace net
diff --git a/net/quic/quic_flow_controller.cc b/net/quic/quic_flow_controller.cc index 722b243..59ae8c0 100644 --- a/net/quic/quic_flow_controller.cc +++ b/net/quic/quic_flow_controller.cc
@@ -16,9 +16,9 @@ QuicFlowController::QuicFlowController(QuicConnection* connection, QuicStreamId id, bool is_server, - uint64 send_window_offset, - uint64 receive_window_offset, - uint64 max_receive_window) + QuicStreamOffset send_window_offset, + QuicStreamOffset receive_window_offset, + QuicByteCount max_receive_window) : connection_(connection), id_(id), is_enabled_(true), @@ -38,7 +38,7 @@ << ", setting send window offset to: " << send_window_offset_; } -void QuicFlowController::AddBytesConsumed(uint64 bytes_consumed) { +void QuicFlowController::AddBytesConsumed(QuicByteCount bytes_consumed) { if (!IsEnabled()) { return; } @@ -49,7 +49,8 @@ MaybeSendWindowUpdate(); } -bool QuicFlowController::UpdateHighestReceivedOffset(uint64 new_offset) { +bool QuicFlowController::UpdateHighestReceivedOffset( + QuicStreamOffset new_offset) { if (!IsEnabled()) { return false; } @@ -66,7 +67,7 @@ return true; } -void QuicFlowController::AddBytesSent(uint64 bytes_sent) { +void QuicFlowController::AddBytesSent(QuicByteCount bytes_sent) { if (!IsEnabled()) { return; } @@ -111,8 +112,8 @@ // (receive window offset - consumed bytes) < (max window / 2). // This is behaviour copied from SPDY. DCHECK_LT(bytes_consumed_, receive_window_offset_); - size_t consumed_window = receive_window_offset_ - bytes_consumed_; - size_t threshold = (max_receive_window_ / 2); + QuicStreamOffset consumed_window = receive_window_offset_ - bytes_consumed_; + QuicByteCount threshold = (max_receive_window_ / 2); if (consumed_window < threshold) { // Update our receive window. @@ -151,7 +152,8 @@ } } -bool QuicFlowController::UpdateSendWindowOffset(uint64 new_send_window_offset) { +bool QuicFlowController::UpdateSendWindowOffset( + QuicStreamOffset new_send_window_offset) { if (!IsEnabled()) { return false; }
diff --git a/net/quic/quic_flow_controller.h b/net/quic/quic_flow_controller.h index 0df2b0e7..371b8c9 100644 --- a/net/quic/quic_flow_controller.h +++ b/net/quic/quic_flow_controller.h
@@ -28,30 +28,30 @@ QuicFlowController(QuicConnection* connection, QuicStreamId id, bool is_server, - uint64 send_window_offset, - uint64 receive_window_offset, - uint64 max_receive_window); + QuicStreamOffset send_window_offset, + QuicStreamOffset receive_window_offset, + QuicByteCount max_receive_window); ~QuicFlowController() {} // Called when we see a new highest received byte offset from the peer, either // via a data frame or a RST. // Returns true if this call changes highest_received_byte_offset_, and false // in the case where |new_offset| is <= highest_received_byte_offset_. - bool UpdateHighestReceivedOffset(uint64 new_offset); + bool UpdateHighestReceivedOffset(QuicStreamOffset new_offset); // Called when bytes received from the peer are consumed locally. This may // trigger the sending of a WINDOW_UPDATE frame using |connection|. - void AddBytesConsumed(uint64 bytes_consumed); + void AddBytesConsumed(QuicByteCount bytes_consumed); // Called when bytes are sent to the peer. - void AddBytesSent(uint64 bytes_sent); + void AddBytesSent(QuicByteCount bytes_sent); // Set a new send window offset. // Returns true if this increases send_window_offset_ and is now blocked. - bool UpdateSendWindowOffset(uint64 new_send_window_offset); + bool UpdateSendWindowOffset(QuicStreamOffset new_send_window_offset); // Returns the current available send window. - uint64 SendWindowSize() const; + QuicByteCount SendWindowSize() const; // Send a BLOCKED frame if appropriate. void MaybeSendBlocked(); @@ -68,9 +68,9 @@ // Returns true if flow control receive limits have been violated by the peer. bool FlowControlViolation(); - uint64 bytes_consumed() const { return bytes_consumed_; } + QuicByteCount bytes_consumed() const { return bytes_consumed_; } - uint64 highest_received_byte_offset() const { + QuicStreamOffset highest_received_byte_offset() const { return highest_received_byte_offset_; } @@ -97,29 +97,29 @@ // Track number of bytes received from the peer, which have been consumed // locally. - uint64 bytes_consumed_; + QuicByteCount bytes_consumed_; // The highest byte offset we have seen from the peer. This could be the // highest offset in a data frame, or a final value in a RST. - uint64 highest_received_byte_offset_; + QuicStreamOffset highest_received_byte_offset_; // Tracks number of bytes sent to the peer. - uint64 bytes_sent_; + QuicByteCount bytes_sent_; // The absolute offset in the outgoing byte stream. If this offset is reached // then we become flow control blocked until we receive a WINDOW_UPDATE. - uint64 send_window_offset_; + QuicStreamOffset send_window_offset_; // The absolute offset in the incoming byte stream. The peer should never send // us bytes which are beyond this offset. - uint64 receive_window_offset_; + QuicStreamOffset receive_window_offset_; // Largest size the receive window can grow to. - uint64 max_receive_window_; + QuicByteCount max_receive_window_; // Keep track of the last time we sent a BLOCKED frame. We should only send // another when the number of bytes we have sent has changed. - uint64 last_blocked_send_window_offset_; + QuicStreamOffset last_blocked_send_window_offset_; DISALLOW_COPY_AND_ASSIGN(QuicFlowController); };
diff --git a/net/quic/quic_flow_controller_test.cc b/net/quic/quic_flow_controller_test.cc index f9601695..e3fcafe 100644 --- a/net/quic/quic_flow_controller_test.cc +++ b/net/quic/quic_flow_controller_test.cc
@@ -4,6 +4,7 @@ #include "net/quic/quic_flow_controller.h" +#include "base/format_macros.h" #include "base/strings/stringprintf.h" #include "net/quic/quic_utils.h" #include "net/quic/test_tools/quic_connection_peer.h" @@ -12,13 +13,9 @@ #include "net/test/gtest_util.h" #include "testing/gmock/include/gmock/gmock.h" -using base::StringPrintf; - namespace net { namespace test { -using ::testing::_; - class QuicFlowControllerTest : public ::testing::Test { public: QuicFlowControllerTest() @@ -37,9 +34,9 @@ protected: QuicStreamId stream_id_; - uint64 send_window_; - uint64 receive_window_; - uint64 max_receive_window_; + QuicByteCount send_window_; + QuicByteCount receive_window_; + QuicByteCount max_receive_window_; scoped_ptr<QuicFlowController> flow_controller_; MockConnection connection_; }; @@ -80,8 +77,8 @@ SendConnectionClose(QUIC_FLOW_CONTROL_SENT_TOO_MUCH_DATA)); EXPECT_DFATAL( flow_controller_->AddBytesSent(send_window_ * 10), - StringPrintf("Trying to send an extra %d bytes", - static_cast<int>(send_window_ * 10))); + base::StringPrintf("Trying to send an extra %" PRIu64 " bytes", + send_window_ * 10)); EXPECT_TRUE(flow_controller_->IsBlocked()); EXPECT_EQ(0u, flow_controller_->SendWindowSize()); } @@ -104,7 +101,7 @@ QuicFlowControllerPeer::ReceiveWindowSize(flow_controller_.get())); // Consume enough bytes to send a WINDOW_UPDATE frame. - EXPECT_CALL(connection_, SendWindowUpdate(stream_id_, _)).Times(1); + EXPECT_CALL(connection_, SendWindowUpdate(stream_id_, ::testing::_)).Times(1); flow_controller_->AddBytesConsumed(1 + receive_window_ / 2);
diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc index d2a7694..c381695e 100644 --- a/net/quic/quic_framer.cc +++ b/net/quic/quic_framer.cc
@@ -781,12 +781,12 @@ // The FEC group number is the sequence number of the first fec // protected packet, or 0 if this packet is not protected. if (header.is_in_fec_group == IN_FEC_GROUP) { - DCHECK_GE(header.packet_sequence_number, header.fec_group); - DCHECK_GT(255u, header.packet_sequence_number - header.fec_group); + DCHECK_LE(header.fec_group, header.packet_sequence_number); + DCHECK_LT(header.packet_sequence_number - header.fec_group, 255u); // Offset from the current packet sequence number to the first fec // protected packet. uint8 first_fec_protected_packet_offset = - header.packet_sequence_number - header.fec_group; + static_cast<uint8>(header.packet_sequence_number - header.fec_group); if (!writer->WriteBytes(&first_fec_protected_packet_offset, 1)) { return false; } @@ -987,18 +987,20 @@ QuicPacketSequenceNumber last_missing = *iter; ++iter; for (; iter != frame.missing_packets.end(); ++iter) { - if (cur_range_length != numeric_limits<uint8>::max() && + if (cur_range_length < numeric_limits<uint8>::max() && *iter == (last_missing + 1)) { ++cur_range_length; } else { - ack_info.nack_ranges[last_missing - cur_range_length] = cur_range_length; + ack_info.nack_ranges[last_missing - cur_range_length] = + static_cast<uint8>(cur_range_length); cur_range_length = 0; } ack_info.max_delta = max(ack_info.max_delta, *iter - last_missing); last_missing = *iter; } // Include the last nack range. - ack_info.nack_ranges[last_missing - cur_range_length] = cur_range_length; + ack_info.nack_ranges[last_missing - cur_range_length] = + static_cast<uint8>(cur_range_length); // Include the range to the largest observed. ack_info.max_delta = max(ack_info.max_delta, frame.largest_observed - last_missing); @@ -1904,7 +1906,7 @@ break; } default: - type_byte = frame.type; + type_byte = static_cast<uint8>(frame.type); break; } @@ -1957,7 +1959,9 @@ return false; } if (!no_stream_frame_length) { - if (!writer->WriteUInt16(frame.data.TotalBufferSize())) { + if ((frame.data.TotalBufferSize() > std::numeric_limits<uint16>::max()) || + !writer->WriteUInt16( + static_cast<uint16>(frame.data.TotalBufferSize()))) { LOG(DFATAL) << "Writing stream frame length failed"; return false; } @@ -2071,7 +2075,7 @@ } const uint8 num_missing_ranges = - min(ack_info.nack_ranges.size(), max_num_ranges); + static_cast<uint8>(min(ack_info.nack_ranges.size(), max_num_ranges)); if (!writer->WriteBytes(&num_missing_ranges, 1)) { return false; } @@ -2098,11 +2102,11 @@ // Append revived packets. // If not all the revived packets fit, only mention the ones that do. - uint8 num_revived_packets = min(frame.revived_packets.size(), - kMaxRevivedPackets); - num_revived_packets = min( + uint8 num_revived_packets = + static_cast<uint8>(min(frame.revived_packets.size(), kMaxRevivedPackets)); + num_revived_packets = static_cast<uint8>(min( static_cast<size_t>(num_revived_packets), - (writer->capacity() - writer->length()) / largest_observed_length); + (writer->capacity() - writer->length()) / largest_observed_length)); if (!writer->WriteBytes(&num_revived_packets, 1)) { return false; }
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h index 258cf02..d5b8d1b 100644 --- a/net/quic/quic_protocol.h +++ b/net/quic/quic_protocol.h
@@ -1089,7 +1089,7 @@ QuicTime sent_time; // Zero when the packet is serialized, non-zero once it's sent. QuicByteCount bytes_sent; - size_t nack_count; + QuicPacketCount nack_count; // Reason why this packet was transmitted. TransmissionType transmission_type; // Stores the sequence numbers of all transmissions of this packet.
diff --git a/net/quic/quic_received_packet_manager.cc b/net/quic/quic_received_packet_manager.cc index e8be74a4..195dbd8 100644 --- a/net/quic/quic_received_packet_manager.cc +++ b/net/quic/quic_received_packet_manager.cc
@@ -164,9 +164,9 @@ // Record how out of order stats. ++stats_->packets_reordered; - uint32 sequence_gap = ack_frame_.largest_observed - sequence_number; stats_->max_sequence_reordering = - max(stats_->max_sequence_reordering, sequence_gap); + max(stats_->max_sequence_reordering, + ack_frame_.largest_observed - sequence_number); int64 reordering_time_us = receipt_time.Subtract(time_largest_observed_).ToMicroseconds(); stats_->max_time_reordering_us = max(stats_->max_time_reordering_us,
diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc index ebb78f1d..56c327c 100644 --- a/net/quic/quic_sent_packet_manager.cc +++ b/net/quic/quic_sent_packet_manager.cc
@@ -285,7 +285,7 @@ // threshold is to tolerate re-ordering. This handles both StretchAcks // and Forward Acks. // The nack count only increases when the largest observed increases. - size_t min_nacks = ack_frame.largest_observed - sequence_number; + QuicPacketCount min_nacks = ack_frame.largest_observed - sequence_number; // Truncated acks can nack the largest observed, so use a min of 1. if (min_nacks == 0) { min_nacks = 1;
diff --git a/net/quic/quic_server.cc b/net/quic/quic_server.cc index fecb4e51..7b0f454 100644 --- a/net/quic/quic_server.cc +++ b/net/quic/quic_server.cc
@@ -74,7 +74,8 @@ // These send and receive buffer sizes are sized for a single connection, // because the default usage of QuicServer is as a test server with one or // two clients. Adjust higher for use with many clients. - rc = socket->SetReceiveBufferSize(TcpReceiver::kReceiveWindowTCP); + rc = socket->SetReceiveBufferSize( + static_cast<int32>(TcpReceiver::kReceiveWindowTCP)); if (rc < 0) { LOG(ERROR) << "SetReceiveBufferSize() failed: " << ErrorToString(rc); return rc;
diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc index d6af16e7..f05395e 100644 --- a/net/quic/quic_session.cc +++ b/net/quic/quic_session.cc
@@ -437,7 +437,7 @@ DVLOG(1) << ENDPOINT << "Received final byte offset " << final_byte_offset << " for stream " << stream_id; - uint64 offset_diff = final_byte_offset - it->second; + QuicByteCount offset_diff = final_byte_offset - it->second; if (flow_controller_->UpdateHighestReceivedOffset( flow_controller_->highest_received_byte_offset() + offset_diff)) { // If the final offset violates flow control, close the connection now. @@ -483,7 +483,8 @@ if (config_.HasReceivedInitialFlowControlWindowBytes()) { // Streams which were created before the SHLO was received (0-RTT // requests) are now informed of the peer's initial flow control window. - uint32 new_window = config_.ReceivedInitialFlowControlWindowBytes(); + QuicStreamOffset new_window = + config_.ReceivedInitialFlowControlWindowBytes(); OnNewStreamFlowControlWindow(new_window); OnNewSessionFlowControlWindow(new_window); } @@ -505,7 +506,7 @@ } } -void QuicSession::OnNewStreamFlowControlWindow(uint32 new_window) { +void QuicSession::OnNewStreamFlowControlWindow(QuicStreamOffset new_window) { if (new_window < kDefaultFlowControlSendWindow) { LOG(ERROR) << "Peer sent us an invalid stream flow control send window: " @@ -527,7 +528,7 @@ } } -void QuicSession::OnNewSessionFlowControlWindow(uint32 new_window) { +void QuicSession::OnNewSessionFlowControlWindow(QuicStreamOffset new_window) { if (new_window < kDefaultFlowControlSendWindow) { LOG(ERROR) << "Peer sent us an invalid session flow control send window: "
diff --git a/net/quic/quic_session.h b/net/quic/quic_session.h index 43f4042..7bc743a20e 100644 --- a/net/quic/quic_session.h +++ b/net/quic/quic_session.h
@@ -280,11 +280,11 @@ // Called in OnConfigNegotiated when we receive a new stream level flow // control window in a negotiated config. Closes the connection if invalid. - void OnNewStreamFlowControlWindow(uint32 new_window); + void OnNewStreamFlowControlWindow(QuicStreamOffset new_window); // Called in OnConfigNegotiated when we receive a new session level flow // control window in a negotiated config. Closes the connection if invalid. - void OnNewSessionFlowControlWindow(uint32 new_window); + void OnNewSessionFlowControlWindow(QuicStreamOffset new_window); // Keep track of highest received byte offset of locally closed streams, while // waiting for a definitive final highest offset from the peer.
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc index 32adedae..e7612a01 100644 --- a/net/quic/quic_stream_factory.cc +++ b/net/quic/quic_stream_factory.cc
@@ -871,7 +871,8 @@ // that is more than large enough for a full receive window, and yet // does not consume "too much" memory. If we see bursty packet loss, we may // revisit this setting and test for its impact. - const int32 kSocketBufferSize(TcpReceiver::kReceiveWindowTCP); + const int32 kSocketBufferSize = + static_cast<int32>(TcpReceiver::kReceiveWindowTCP); rv = socket->SetReceiveBufferSize(kSocketBufferSize); if (rv != OK) { HistogramCreateSessionFailure(CREATION_ERROR_SETTING_RECEIVE_BUFFER); @@ -928,7 +929,8 @@ http_server_properties_->GetServerNetworkStats( server_id.host_port_pair()); if (stats != nullptr) { - config.SetInitialRoundTripTimeUsToSend(stats->srtt.InMicroseconds()); + config.SetInitialRoundTripTimeUsToSend( + static_cast<uint32>(stats->srtt.InMicroseconds())); } }
diff --git a/net/quic/quic_stream_sequencer.cc b/net/quic/quic_stream_sequencer.cc index 5df81e5d..153e6cf 100644 --- a/net/quic/quic_stream_sequencer.cc +++ b/net/quic/quic_stream_sequencer.cc
@@ -160,7 +160,7 @@ size_t iov_index = 0; size_t iov_offset = 0; size_t frame_offset = 0; - size_t initial_bytes_consumed = num_bytes_consumed_; + QuicStreamOffset initial_bytes_consumed = num_bytes_consumed_; while (iov_index < iov_len && it != buffered_frames_.end() && @@ -194,7 +194,7 @@ buffered_frames_.erase(buffered_frames_.begin()); RecordBytesConsumed(frame_offset); } - return num_bytes_consumed_ - initial_bytes_consumed; + return static_cast<int>(num_bytes_consumed_ - initial_bytes_consumed); } bool QuicStreamSequencer::HasBytesToRead() const {
diff --git a/net/quic/quic_time.cc b/net/quic/quic_time.cc index e20a338..5d653a3 100644 --- a/net/quic/quic_time.cc +++ b/net/quic/quic_time.cc
@@ -67,7 +67,8 @@ } QuicTime::Delta QuicTime::Delta::Multiply(double d) const { - return QuicTime::Delta::FromMicroseconds(ToMicroseconds() * d); + return QuicTime::Delta::FromMicroseconds( + static_cast<int64>(ToMicroseconds() * d)); } // static
diff --git a/net/quic/quic_unacked_packet_map.cc b/net/quic/quic_unacked_packet_map.cc index bbff3c9f..1267707a1 100644 --- a/net/quic/quic_unacked_packet_map.cc +++ b/net/quic/quic_unacked_packet_map.cc
@@ -182,7 +182,7 @@ } void QuicUnackedPacketMap::NackPacket(QuicPacketSequenceNumber sequence_number, - size_t min_nacks) { + QuicPacketCount min_nacks) { DCHECK_GE(sequence_number, least_unacked_); DCHECK_LT(sequence_number, least_unacked_ + unacked_packets_.size()); unacked_packets_[sequence_number - least_unacked_].nack_count =
diff --git a/net/quic/quic_unacked_packet_map.h b/net/quic/quic_unacked_packet_map.h index 165e41f..6c56dd6 100644 --- a/net/quic/quic_unacked_packet_map.h +++ b/net/quic/quic_unacked_packet_map.h
@@ -38,7 +38,7 @@ // Sets the nack count to the max of the current nack count and |min_nacks|. void NackPacket(QuicPacketSequenceNumber sequence_number, - size_t min_nacks); + QuicPacketCount min_nacks); // Marks |sequence_number| as no longer in flight. void RemoveFromInFlight(QuicPacketSequenceNumber sequence_number); @@ -164,7 +164,7 @@ // The packet at the 0th index of unacked_packets_. QuicPacketSequenceNumber least_unacked_; - size_t bytes_in_flight_; + QuicByteCount bytes_in_flight_; // Number of retransmittable crypto handshake packets. size_t pending_crypto_packet_count_;
diff --git a/net/quic/quic_utils.cc b/net/quic/quic_utils.cc index f144651..a0e1de5 100644 --- a/net/quic/quic_utils.cc +++ b/net/quic/quic_utils.cc
@@ -259,13 +259,13 @@ // static string QuicUtils::TagToString(QuicTag tag) { - char chars[4]; + char chars[sizeof tag]; bool ascii = true; const QuicTag orig_tag = tag; - for (size_t i = 0; i < sizeof(chars); i++) { - chars[i] = tag; - if ((chars[i] == 0 || chars[i] == '\xff') && i == 3) { + for (size_t i = 0; i < arraysize(chars); i++) { + chars[i] = static_cast<char>(tag); + if ((chars[i] == 0 || chars[i] == '\xff') && i == arraysize(chars) - 1) { chars[i] = ' '; } if (!isprint(static_cast<unsigned char>(chars[i]))) {
diff --git a/net/quic/reliable_quic_stream.cc b/net/quic/reliable_quic_stream.cc index 70b6d9af..116d843d 100644 --- a/net/quic/reliable_quic_stream.cc +++ b/net/quic/reliable_quic_stream.cc
@@ -363,7 +363,7 @@ if (flow_controller_.IsEnabled()) { // How much data we are allowed to write from flow control. - uint64 send_window = flow_controller_.SendWindowSize(); + QuicByteCount send_window = flow_controller_.SendWindowSize(); // TODO(rjshade): Remove connection_flow_controller_->IsEnabled() check when // removing QUIC_VERSION_19. if (stream_contributes_to_connection_flow_control_ && @@ -383,7 +383,7 @@ fin = false; // Writing more data would be a violation of flow control. - write_length = send_window; + write_length = static_cast<size_t>(send_window); } } @@ -466,7 +466,8 @@ // As there may be more bytes in flight and we need to ensure that both // endpoints have the same connection level flow control state, mark all // unreceived or buffered bytes as consumed. - uint64 bytes_to_consume = flow_controller_.highest_received_byte_offset() - + QuicByteCount bytes_to_consume = + flow_controller_.highest_received_byte_offset() - flow_controller_.bytes_consumed(); AddBytesConsumed(bytes_to_consume); } @@ -487,7 +488,8 @@ } } -bool ReliableQuicStream::MaybeIncreaseHighestReceivedOffset(uint64 new_offset) { +bool ReliableQuicStream::MaybeIncreaseHighestReceivedOffset( + QuicStreamOffset new_offset) { if (!flow_controller_.IsEnabled()) { return false; } @@ -508,7 +510,7 @@ return true; } -void ReliableQuicStream::AddBytesSent(uint64 bytes) { +void ReliableQuicStream::AddBytesSent(QuicByteCount bytes) { if (flow_controller_.IsEnabled()) { flow_controller_.AddBytesSent(bytes); if (stream_contributes_to_connection_flow_control_) { @@ -517,7 +519,7 @@ } } -void ReliableQuicStream::AddBytesConsumed(uint64 bytes) { +void ReliableQuicStream::AddBytesConsumed(QuicByteCount bytes) { if (flow_controller_.IsEnabled()) { // Only adjust stream level flow controller if we are still reading. if (!read_side_closed_) { @@ -530,7 +532,7 @@ } } -void ReliableQuicStream::UpdateSendWindowOffset(uint64 new_window) { +void ReliableQuicStream::UpdateSendWindowOffset(QuicStreamOffset new_window) { if (flow_controller_.UpdateSendWindowOffset(new_window)) { OnCanWrite(); }
diff --git a/net/quic/reliable_quic_stream.h b/net/quic/reliable_quic_stream.h index 24bc349..698fefb 100644 --- a/net/quic/reliable_quic_stream.h +++ b/net/quic/reliable_quic_stream.h
@@ -103,17 +103,17 @@ // Called when we see a frame which could increase the highest offset. // Returns true if the highest offset did increase. - bool MaybeIncreaseHighestReceivedOffset(uint64 new_offset); + bool MaybeIncreaseHighestReceivedOffset(QuicStreamOffset new_offset); // Called when bytese are sent to the peer. - void AddBytesSent(uint64 bytes); + void AddBytesSent(QuicByteCount bytes); // Called by the stream sequencer as bytes are consumed from the buffer. // If our receive window has dropped below the threshold, then send a // WINDOW_UPDATE frame. - void AddBytesConsumed(uint64 bytes); + void AddBytesConsumed(QuicByteCount bytes); // Updates the flow controller's send window offset and calls OnCanWrite if // it was blocked before. - void UpdateSendWindowOffset(uint64 new_offset); + void UpdateSendWindowOffset(QuicStreamOffset new_offset); // Returns true if the stream is flow control blocked, by the stream flow // control window or the connection flow control window.
diff --git a/net/quic/test_tools/quic_flow_controller_peer.cc b/net/quic/test_tools/quic_flow_controller_peer.cc index 35882ede..d6a10987 100644 --- a/net/quic/test_tools/quic_flow_controller_peer.cc +++ b/net/quic/test_tools/quic_flow_controller_peer.cc
@@ -15,43 +15,44 @@ // static void QuicFlowControllerPeer::SetSendWindowOffset( QuicFlowController* flow_controller, - uint64 offset) { + QuicStreamOffset offset) { flow_controller->send_window_offset_ = offset; } // static void QuicFlowControllerPeer::SetReceiveWindowOffset( QuicFlowController* flow_controller, - uint64 offset) { + QuicStreamOffset offset) { flow_controller->receive_window_offset_ = offset; } // static void QuicFlowControllerPeer::SetMaxReceiveWindow( - QuicFlowController* flow_controller, uint64 window_size) { + QuicFlowController* flow_controller, + QuicByteCount window_size) { flow_controller->max_receive_window_ = window_size; } // static -uint64 QuicFlowControllerPeer::SendWindowOffset( +QuicStreamOffset QuicFlowControllerPeer::SendWindowOffset( QuicFlowController* flow_controller) { return flow_controller->send_window_offset_; } // static -uint64 QuicFlowControllerPeer::SendWindowSize( +QuicByteCount QuicFlowControllerPeer::SendWindowSize( QuicFlowController* flow_controller) { return flow_controller->SendWindowSize(); } // static -uint64 QuicFlowControllerPeer::ReceiveWindowOffset( +QuicStreamOffset QuicFlowControllerPeer::ReceiveWindowOffset( QuicFlowController* flow_controller) { return flow_controller->receive_window_offset_; } // static -uint64 QuicFlowControllerPeer::ReceiveWindowSize( +QuicByteCount QuicFlowControllerPeer::ReceiveWindowSize( QuicFlowController* flow_controller) { return flow_controller->receive_window_offset_ - flow_controller->highest_received_byte_offset_;
diff --git a/net/quic/test_tools/quic_flow_controller_peer.h b/net/quic/test_tools/quic_flow_controller_peer.h index 213d40d6..4270d96 100644 --- a/net/quic/test_tools/quic_flow_controller_peer.h +++ b/net/quic/test_tools/quic_flow_controller_peer.h
@@ -16,21 +16,22 @@ class QuicFlowControllerPeer { public: static void SetSendWindowOffset(QuicFlowController* flow_controller, - uint64 offset); + QuicStreamOffset offset); static void SetReceiveWindowOffset(QuicFlowController* flow_controller, - uint64 offset); + QuicStreamOffset offset); static void SetMaxReceiveWindow(QuicFlowController* flow_controller, - uint64 window_size); + QuicByteCount window_size); - static uint64 SendWindowOffset(QuicFlowController* flow_controller); + static QuicStreamOffset SendWindowOffset(QuicFlowController* flow_controller); - static uint64 SendWindowSize(QuicFlowController* flow_controller); + static QuicByteCount SendWindowSize(QuicFlowController* flow_controller); - static uint64 ReceiveWindowOffset(QuicFlowController* flow_controller); + static QuicStreamOffset ReceiveWindowOffset( + QuicFlowController* flow_controller); - static uint64 ReceiveWindowSize(QuicFlowController* flow_controller); + static QuicByteCount ReceiveWindowSize(QuicFlowController* flow_controller); private: DISALLOW_COPY_AND_ASSIGN(QuicFlowControllerPeer);
diff --git a/net/quic/test_tools/quic_sent_packet_manager_peer.cc b/net/quic/test_tools/quic_sent_packet_manager_peer.cc index bb9fb38e..311b688 100644 --- a/net/quic/test_tools/quic_sent_packet_manager_peer.cc +++ b/net/quic/test_tools/quic_sent_packet_manager_peer.cc
@@ -72,7 +72,7 @@ } // static -size_t QuicSentPacketManagerPeer::GetNackCount( +QuicPacketCount QuicSentPacketManagerPeer::GetNackCount( const QuicSentPacketManager* sent_packet_manager, QuicPacketSequenceNumber sequence_number) { return sent_packet_manager->unacked_packets_.
diff --git a/net/quic/test_tools/quic_sent_packet_manager_peer.h b/net/quic/test_tools/quic_sent_packet_manager_peer.h index dfc524dc..2d850d3 100644 --- a/net/quic/test_tools/quic_sent_packet_manager_peer.h +++ b/net/quic/test_tools/quic_sent_packet_manager_peer.h
@@ -42,7 +42,7 @@ static RttStats* GetRttStats(QuicSentPacketManager* sent_packet_manager); - static size_t GetNackCount( + static QuicPacketCount GetNackCount( const QuicSentPacketManager* sent_packet_manager, QuicPacketSequenceNumber sequence_number);
diff --git a/net/socket/ssl_client_socket.h b/net/socket/ssl_client_socket.h index 7adfa8c..af4f3ba 100644 --- a/net/socket/ssl_client_socket.h +++ b/net/socket/ssl_client_socket.h
@@ -149,6 +149,10 @@ // sessions. static void ClearSessionCache(); + // Get the maximum SSL version supported by the underlying library and + // cryptographic implementation. + static uint16 GetMaxSupportedSSLVersion(); + virtual bool set_was_npn_negotiated(bool negotiated); virtual bool was_spdy_negotiated() const;
diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc index 3e5bde0..1319e4b 100644 --- a/net/socket/ssl_client_socket_nss.cc +++ b/net/socket/ssl_client_socket_nss.cc
@@ -2473,10 +2473,7 @@ if (ok == SECSuccess && channel_info.length == sizeof(channel_info) && channel_info.cipherSuite) { - nss_handshake_state_.ssl_connection_status |= - (static_cast<int>(channel_info.cipherSuite) & - SSL_CONNECTION_CIPHERSUITE_MASK) << - SSL_CONNECTION_CIPHERSUITE_SHIFT; + nss_handshake_state_.ssl_connection_status |= channel_info.cipherSuite; nss_handshake_state_.ssl_connection_status |= (static_cast<int>(channel_info.compressionMethod) & @@ -2856,6 +2853,19 @@ SSL_ClearSessionCache(); } +#if !defined(CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256) +#define CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256 (CKM_NSS + 24) +#endif + +// static +uint16 SSLClientSocket::GetMaxSupportedSSLVersion() { + if (PK11_TokenExists(CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256)) { + return SSL_PROTOCOL_VERSION_TLS1_2; + } else { + return SSL_PROTOCOL_VERSION_TLS1_1; + } +} + bool SSLClientSocketNSS::GetSSLInfo(SSLInfo* ssl_info) { EnterFunction(""); ssl_info->Reset();
diff --git a/net/socket/ssl_client_socket_openssl.cc b/net/socket/ssl_client_socket_openssl.cc index 05eb1cb..b417e13 100644 --- a/net/socket/ssl_client_socket_openssl.cc +++ b/net/socket/ssl_client_socket_openssl.cc
@@ -81,11 +81,10 @@ #endif // Used for encoding the |connection_status| field of an SSLInfo object. -int EncodeSSLConnectionStatus(int cipher_suite, +int EncodeSSLConnectionStatus(uint16 cipher_suite, int compression, int version) { - return ((cipher_suite & SSL_CONNECTION_CIPHERSUITE_MASK) << - SSL_CONNECTION_CIPHERSUITE_SHIFT) | + return cipher_suite | ((compression & SSL_CONNECTION_COMPRESSION_MASK) << SSL_CONNECTION_COMPRESSION_SHIFT) | ((version & SSL_CONNECTION_VERSION_MASK) << @@ -345,6 +344,11 @@ context->session_cache()->Flush(); } +// static +uint16 SSLClientSocket::GetMaxSupportedSSLVersion() { + return SSL_PROTOCOL_VERSION_TLS1_2; +} + SSLClientSocketOpenSSL::SSLClientSocketOpenSSL( scoped_ptr<ClientSocketHandle> transport_socket, const HostPortPair& host_and_port, @@ -625,7 +629,7 @@ ssl_info->security_bits = SSL_CIPHER_get_bits(cipher, NULL); ssl_info->connection_status = EncodeSSLConnectionStatus( - SSL_CIPHER_get_id(cipher), 0 /* no compression */, + static_cast<uint16>(SSL_CIPHER_get_id(cipher)), 0 /* no compression */, GetNetSSLVersion(ssl_)); if (!SSL_get_secure_renegotiation_support(ssl_)) @@ -788,7 +792,7 @@ // appended to the cipher removal |command|. for (size_t i = 0; i < sk_SSL_CIPHER_num(ciphers); ++i) { const SSL_CIPHER* cipher = sk_SSL_CIPHER_value(ciphers, i); - const uint16 id = SSL_CIPHER_get_id(cipher); + const uint16 id = static_cast<uint16>(SSL_CIPHER_get_id(cipher)); // Remove any ciphers with a strength of less than 80 bits. Note the NSS // implementation uses "effective" bits here but OpenSSL does not provide // this detail. This only impacts Triple DES: reports 112 vs. 168 bits, @@ -960,7 +964,7 @@ // Only record OCSP histograms if OCSP was requested. if (ssl_config_.signed_cert_timestamps_enabled || IsOCSPStaplingSupported()) { - uint8_t* ocsp_response; + const uint8_t* ocsp_response; size_t ocsp_response_len; SSL_get0_ocsp_response(ssl_, &ocsp_response, &ocsp_response_len); @@ -968,7 +972,7 @@ UMA_HISTOGRAM_BOOLEAN("Net.OCSPResponseStapled", ocsp_response_len != 0); } - uint8_t* sct_list; + const uint8_t* sct_list; size_t sct_list_len; SSL_get0_signed_cert_timestamp_list(ssl_, &sct_list, &sct_list_len); set_signed_cert_timestamps_received(sct_list_len != 0); @@ -1201,13 +1205,13 @@ // update IsOCSPStaplingSupported for Mac. https://crbug.com/430714 if (IsOCSPStaplingSupported()) { #if defined(OS_WIN) - uint8_t* ocsp_response_raw; + const uint8_t* ocsp_response_raw; size_t ocsp_response_len; SSL_get0_ocsp_response(ssl_, &ocsp_response_raw, &ocsp_response_len); CRYPT_DATA_BLOB ocsp_response_blob; ocsp_response_blob.cbData = ocsp_response_len; - ocsp_response_blob.pbData = ocsp_response_raw; + ocsp_response_blob.pbData = const_cast<BYTE*>(ocsp_response_raw); BOOL ok = CertSetCertificateContextProperty( server_cert_->os_cert_handle(), CERT_OCSP_RESPONSE_PROP_ID, @@ -1228,7 +1232,7 @@ if (!cert_transparency_verifier_) return; - uint8_t* ocsp_response_raw; + const uint8_t* ocsp_response_raw; size_t ocsp_response_len; SSL_get0_ocsp_response(ssl_, &ocsp_response_raw, &ocsp_response_len); std::string ocsp_response; @@ -1237,7 +1241,7 @@ ocsp_response_len); } - uint8_t* sct_list_raw; + const uint8_t* sct_list_raw; size_t sct_list_len; SSL_get0_signed_cert_timestamp_list(ssl_, &sct_list_raw, &sct_list_len); std::string sct_list;
diff --git a/net/spdy/spdy_http_stream_unittest.cc b/net/spdy/spdy_http_stream_unittest.cc index f22b75f2..04b5088 100644 --- a/net/spdy/spdy_http_stream_unittest.cc +++ b/net/spdy/spdy_http_stream_unittest.cc
@@ -754,16 +754,18 @@ // Verify that the window size has decreased. ASSERT_TRUE(http_stream->stream() != NULL); - EXPECT_NE(static_cast<int>(kSpdyStreamInitialWindowSize), - http_stream->stream()->send_window_size()); + EXPECT_NE( + static_cast<int>(SpdySession::GetInitialWindowSize(session_->protocol())), + http_stream->stream()->send_window_size()); // Read window update. deterministic_data_->RunFor(1); // Verify the window update. ASSERT_TRUE(http_stream->stream() != NULL); - EXPECT_EQ(static_cast<int>(kSpdyStreamInitialWindowSize), - http_stream->stream()->send_window_size()); + EXPECT_EQ( + static_cast<int>(SpdySession::GetInitialWindowSize(session_->protocol())), + http_stream->stream()->send_window_size()); // Read response headers. deterministic_data_->RunFor(1);
diff --git a/net/spdy/spdy_network_transaction_unittest.cc b/net/spdy/spdy_network_transaction_unittest.cc index 3836fd31..4c6c205 100644 --- a/net/spdy/spdy_network_transaction_unittest.cc +++ b/net/spdy/spdy_network_transaction_unittest.cc
@@ -4416,7 +4416,8 @@ scoped_ptr<SpdyFrame> initial_window_update( spdy_util_.ConstructSpdyWindowUpdate( kSessionFlowControlStreamId, - kDefaultInitialRecvWindowSize - kSpdySessionInitialWindowSize)); + kDefaultInitialRecvWindowSize - + SpdySession::GetInitialWindowSize(GetParam().protocol))); // Construct the persisted SETTINGS frame. const SettingsMap& settings = @@ -5909,10 +5910,10 @@ SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get()); ASSERT_TRUE(stream != NULL); ASSERT_TRUE(stream->stream() != NULL); - EXPECT_EQ(static_cast<int>(kSpdyStreamInitialWindowSize) + - kDeltaWindowSize * kDeltaCount - - kMaxSpdyFrameChunkSize * kFrameCount, - stream->stream()->send_window_size()); + EXPECT_EQ( + static_cast<int>(SpdySession::GetInitialWindowSize(GetParam().protocol)) + + kDeltaWindowSize * kDeltaCount - kMaxSpdyFrameChunkSize * kFrameCount, + stream->stream()->send_window_size()); data.RunFor(1); @@ -5925,8 +5926,10 @@ // Test that received data frames and sent WINDOW_UPDATE frames change // the recv_window_size_ correctly. TEST_P(SpdyNetworkTransactionTest, WindowUpdateSent) { + const int32 initial_window_size = + SpdySession::GetInitialWindowSize(GetParam().protocol); // Amount of body required to trigger a sent window update. - const size_t kTargetSize = kSpdyStreamInitialWindowSize / 2 + 1; + const size_t kTargetSize = initial_window_size / 2 + 1; scoped_ptr<SpdyFrame> req( spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); @@ -5955,7 +5958,7 @@ reads.push_back(CreateMockRead(*body_frames.back())); remaining -= frame_size; } - reads.push_back(MockRead(ASYNC, ERR_IO_PENDING, 0)); // Yield. + reads.push_back(MockRead(ASYNC, ERR_IO_PENDING, 0)); // Yield. DelayedSocketData data(1, vector_as_array(&reads), reads.size(), vector_as_array(&writes), writes.size()); @@ -5979,7 +5982,7 @@ ASSERT_TRUE(stream->stream() != NULL); // All data has been read, but not consumed. The window reflects this. - EXPECT_EQ(static_cast<int>(kSpdyStreamInitialWindowSize - kTargetSize), + EXPECT_EQ(static_cast<int>(initial_window_size - kTargetSize), stream->stream()->recv_window_size()); const HttpResponseInfo* response = trans->GetResponseInfo(); @@ -5993,7 +5996,7 @@ scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kTargetSize)); EXPECT_EQ(static_cast<int>(kTargetSize), trans->Read(buf.get(), kTargetSize, CompletionCallback())); - EXPECT_EQ(static_cast<int>(kSpdyStreamInitialWindowSize), + EXPECT_EQ(static_cast<int>(initial_window_size), stream->stream()->recv_window_size()); EXPECT_THAT(base::StringPiece(buf->data(), kTargetSize), Each(Eq('x'))); @@ -6083,22 +6086,22 @@ // After that, next read is artifically enforced, which causes a // WINDOW_UPDATE to be read and I/O process resumes. TEST_P(SpdyNetworkTransactionTest, FlowControlStallResume) { + const int32 initial_window_size = + SpdySession::GetInitialWindowSize(GetParam().protocol); // Number of frames we need to send to zero out the window size: data // frames plus SYN_STREAM plus the last data frame; also we need another // data frame that we will send once the WINDOW_UPDATE is received, // therefore +3. - size_t num_writes = kSpdyStreamInitialWindowSize / kMaxSpdyFrameChunkSize + 3; + size_t num_writes = initial_window_size / kMaxSpdyFrameChunkSize + 3; // Calculate last frame's size; 0 size data frame is legal. - size_t last_frame_size = - kSpdyStreamInitialWindowSize % kMaxSpdyFrameChunkSize; + size_t last_frame_size = initial_window_size % kMaxSpdyFrameChunkSize; // Construct content for a data frame of maximum size. std::string content(kMaxSpdyFrameChunkSize, 'a'); scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost( - kRequestUrl, 1, kSpdyStreamInitialWindowSize + kUploadDataSize, - LOWEST, NULL, 0)); + kRequestUrl, 1, initial_window_size + kUploadDataSize, LOWEST, NULL, 0)); // Full frames. scoped_ptr<SpdyFrame> body1( @@ -6151,7 +6154,7 @@ writes.get(), num_writes); ScopedVector<UploadElementReader> element_readers; - std::string upload_data_string(kSpdyStreamInitialWindowSize, 'a'); + std::string upload_data_string(initial_window_size, 'a'); upload_data_string.append(kUploadData, kUploadDataSize); element_readers.push_back(new UploadBytesElementReader( upload_data_string.c_str(), upload_data_string.size())); @@ -6194,21 +6197,22 @@ // Test we correctly handle the case where the SETTINGS frame results in // unstalling the send window. TEST_P(SpdyNetworkTransactionTest, FlowControlStallResumeAfterSettings) { + const int32 initial_window_size = + SpdySession::GetInitialWindowSize(GetParam().protocol); + // Number of frames we need to send to zero out the window size: data // frames plus SYN_STREAM plus the last data frame; also we need another // data frame that we will send once the SETTING is received, therefore +3. - size_t num_writes = kSpdyStreamInitialWindowSize / kMaxSpdyFrameChunkSize + 3; + size_t num_writes = initial_window_size / kMaxSpdyFrameChunkSize + 3; // Calculate last frame's size; 0 size data frame is legal. - size_t last_frame_size = - kSpdyStreamInitialWindowSize % kMaxSpdyFrameChunkSize; + size_t last_frame_size = initial_window_size % kMaxSpdyFrameChunkSize; // Construct content for a data frame of maximum size. std::string content(kMaxSpdyFrameChunkSize, 'a'); scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost( - kRequestUrl, 1, kSpdyStreamInitialWindowSize + kUploadDataSize, - LOWEST, NULL, 0)); + kRequestUrl, 1, initial_window_size + kUploadDataSize, LOWEST, NULL, 0)); // Full frames. scoped_ptr<SpdyFrame> body1( @@ -6236,8 +6240,7 @@ // rest of the data. SettingsMap settings; settings[SETTINGS_INITIAL_WINDOW_SIZE] = - SettingsFlagsAndValue( - SETTINGS_FLAG_NONE, kSpdyStreamInitialWindowSize * 2); + SettingsFlagsAndValue(SETTINGS_FLAG_NONE, initial_window_size * 2); scoped_ptr<SpdyFrame> settings_frame_large( spdy_util_.ConstructSpdySettings(settings)); @@ -6265,7 +6268,7 @@ vector_as_array(&writes), writes.size()); ScopedVector<UploadElementReader> element_readers; - std::string upload_data_string(kSpdyStreamInitialWindowSize, 'a'); + std::string upload_data_string(initial_window_size, 'a'); upload_data_string.append(kUploadData, kUploadDataSize); element_readers.push_back(new UploadBytesElementReader( upload_data_string.c_str(), upload_data_string.size())); @@ -6312,21 +6315,21 @@ // Test we correctly handle the case where the SETTINGS frame results in a // negative send window size. TEST_P(SpdyNetworkTransactionTest, FlowControlNegativeSendWindowSize) { + const int32 initial_window_size = + SpdySession::GetInitialWindowSize(GetParam().protocol); // Number of frames we need to send to zero out the window size: data // frames plus SYN_STREAM plus the last data frame; also we need another // data frame that we will send once the SETTING is received, therefore +3. - size_t num_writes = kSpdyStreamInitialWindowSize / kMaxSpdyFrameChunkSize + 3; + size_t num_writes = initial_window_size / kMaxSpdyFrameChunkSize + 3; // Calculate last frame's size; 0 size data frame is legal. - size_t last_frame_size = - kSpdyStreamInitialWindowSize % kMaxSpdyFrameChunkSize; + size_t last_frame_size = initial_window_size % kMaxSpdyFrameChunkSize; // Construct content for a data frame of maximum size. std::string content(kMaxSpdyFrameChunkSize, 'a'); scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost( - kRequestUrl, 1, kSpdyStreamInitialWindowSize + kUploadDataSize, - LOWEST, NULL, 0)); + kRequestUrl, 1, initial_window_size + kUploadDataSize, LOWEST, NULL, 0)); // Full frames. scoped_ptr<SpdyFrame> body1( @@ -6354,16 +6357,15 @@ // negative. SettingsMap new_settings; new_settings[SETTINGS_INITIAL_WINDOW_SIZE] = - SettingsFlagsAndValue( - SETTINGS_FLAG_NONE, kSpdyStreamInitialWindowSize / 2); + SettingsFlagsAndValue(SETTINGS_FLAG_NONE, initial_window_size / 2); scoped_ptr<SpdyFrame> settings_frame_small( spdy_util_.ConstructSpdySettings(new_settings)); // Construct read frames for WINDOW_UPDATE that makes the send_window_size // positive. scoped_ptr<SpdyFrame> session_window_update_init_size( - spdy_util_.ConstructSpdyWindowUpdate(0, kSpdyStreamInitialWindowSize)); + spdy_util_.ConstructSpdyWindowUpdate(0, initial_window_size)); scoped_ptr<SpdyFrame> window_update_init_size( - spdy_util_.ConstructSpdyWindowUpdate(1, kSpdyStreamInitialWindowSize)); + spdy_util_.ConstructSpdyWindowUpdate(1, initial_window_size)); reads.push_back(CreateMockRead(*settings_frame_small, i++)); reads.push_back(CreateMockRead(*session_window_update_init_size, i++)); @@ -6386,7 +6388,7 @@ vector_as_array(&writes), writes.size()); ScopedVector<UploadElementReader> element_readers; - std::string upload_data_string(kSpdyStreamInitialWindowSize, 'a'); + std::string upload_data_string(initial_window_size, 'a'); upload_data_string.append(kUploadData, kUploadDataSize); element_readers.push_back(new UploadBytesElementReader( upload_data_string.c_str(), upload_data_string.size()));
diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc index 1c9abce..4b91909 100644 --- a/net/spdy/spdy_session.cc +++ b/net/spdy/spdy_session.cc
@@ -655,7 +655,7 @@ check_ping_status_pending_(false), send_connection_header_prefix_(false), flow_control_state_(FLOW_CONTROL_NONE), - stream_initial_send_window_size_(kSpdyStreamInitialWindowSize), + stream_initial_send_window_size_(GetInitialWindowSize(default_protocol)), stream_initial_recv_window_size_(stream_initial_recv_window_size == 0 ? kDefaultInitialRecvWindowSize : stream_initial_recv_window_size), @@ -729,6 +729,7 @@ connection_->socket()->GetNegotiatedProtocol(); if (protocol_negotiated != kProtoUnknown) { protocol_ = protocol_negotiated; + stream_initial_send_window_size_ = GetInitialWindowSize(protocol_); } DCHECK_GE(protocol_, kProtoSPDYMinimumVersion); DCHECK_LE(protocol_, kProtoSPDYMaximumVersion); @@ -739,8 +740,8 @@ if (protocol_ >= kProtoSPDY31) { flow_control_state_ = FLOW_CONTROL_STREAM_AND_SESSION; - session_send_window_size_ = kSpdySessionInitialWindowSize; - session_recv_window_size_ = kSpdySessionInitialWindowSize; + session_send_window_size_ = GetInitialWindowSize(protocol_); + session_recv_window_size_ = GetInitialWindowSize(protocol_); } else if (protocol_ >= kProtoSPDY3) { flow_control_state_ = FLOW_CONTROL_STREAM; } else { @@ -2778,7 +2779,7 @@ settings_map[SETTINGS_MAX_CONCURRENT_STREAMS] = SettingsFlagsAndValue(SETTINGS_FLAG_NONE, kMaxConcurrentPushedStreams); if (flow_control_state_ >= FLOW_CONTROL_STREAM && - stream_initial_recv_window_size_ != kSpdyStreamInitialWindowSize) { + stream_initial_recv_window_size_ != GetInitialWindowSize(protocol_)) { settings_map[SETTINGS_INITIAL_WINDOW_SIZE] = SettingsFlagsAndValue(SETTINGS_FLAG_NONE, stream_initial_recv_window_size_); @@ -3195,7 +3196,8 @@ delta_window_size, session_recv_window_size_)); session_unacked_recv_window_bytes_ += delta_window_size; - if (session_unacked_recv_window_bytes_ > kSpdySessionInitialWindowSize / 2) { + if (session_unacked_recv_window_bytes_ > + GetInitialWindowSize(protocol_) / 2) { SendWindowUpdateFrame(kSessionFlowControlStreamId, session_unacked_recv_window_bytes_, HIGHEST);
diff --git a/net/spdy/spdy_session.h b/net/spdy/spdy_session.h index 862918b..06dfae6 100644 --- a/net/spdy/spdy_session.h +++ b/net/spdy/spdy_session.h
@@ -511,6 +511,10 @@ return buffered_spdy_framer_->GetDataFrameMaximumPayload(); } + static int32 GetInitialWindowSize(NextProto protocol) { + return protocol < kProtoSPDY4MinimumVersion ? 65536 : 65535; + } + // https://http2.github.io/http2-spec/#TLSUsage mandates minimum security // standards for TLS. bool HasAcceptableTransportSecurity() const;
diff --git a/net/spdy/spdy_session_unittest.cc b/net/spdy/spdy_session_unittest.cc index 6ec3383..ce53711 100644 --- a/net/spdy/spdy_session_unittest.cc +++ b/net/spdy/spdy_session_unittest.cc
@@ -1235,7 +1235,7 @@ if (session->flow_control_state_ == SpdySession::FLOW_CONTROL_STREAM_AND_SESSION) { // Unclaimed push body consumed bytes from the session window. - EXPECT_EQ(kSpdySessionInitialWindowSize - kUploadDataSize, + EXPECT_EQ(SpdySession::GetInitialWindowSize(GetParam()) - kUploadDataSize, session->session_recv_window_size_); EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); } @@ -1254,7 +1254,7 @@ if (session->flow_control_state_ == SpdySession::FLOW_CONTROL_STREAM_AND_SESSION) { // Verify that the session window reclaimed the evicted stream body. - EXPECT_EQ(kSpdySessionInitialWindowSize, + EXPECT_EQ(SpdySession::GetInitialWindowSize(GetParam()), session->session_recv_window_size_); EXPECT_EQ(kUploadDataSize, session->session_unacked_recv_window_bytes_); } @@ -1553,7 +1553,8 @@ scoped_ptr<SpdyFrame> initial_window_update( spdy_util_.ConstructSpdyWindowUpdate( kSessionFlowControlStreamId, - kDefaultInitialRecvWindowSize - kSpdySessionInitialWindowSize)); + kDefaultInitialRecvWindowSize - + SpdySession::GetInitialWindowSize(GetParam()))); std::vector<MockWrite> writes; if ((GetParam() >= kProtoSPDY4MinimumVersion) && (GetParam() <= kProtoSPDY4MaximumVersion)) { @@ -3081,9 +3082,9 @@ session->buffered_spdy_framer_->protocol_version()); EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION, session->flow_control_state()); - EXPECT_EQ(kSpdySessionInitialWindowSize, + EXPECT_EQ(SpdySession::GetInitialWindowSize(GetParam()), session->session_send_window_size_); - EXPECT_EQ(kSpdySessionInitialWindowSize, + EXPECT_EQ(SpdySession::GetInitialWindowSize(GetParam()), session->session_recv_window_size_); EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); } @@ -3510,16 +3511,16 @@ session_deps_.host_resolver->set_synchronous_mode(true); + const int32 initial_window_size = + SpdySession::GetInitialWindowSize(GetParam()); const int32 delta_window_size = 100; MockConnect connect_data(SYNCHRONOUS, OK); MockRead reads[] = { MockRead(ASYNC, 0, 1) // EOF }; - scoped_ptr<SpdyFrame> window_update( - spdy_util_.ConstructSpdyWindowUpdate( - kSessionFlowControlStreamId, - kSpdySessionInitialWindowSize + delta_window_size)); + scoped_ptr<SpdyFrame> window_update(spdy_util_.ConstructSpdyWindowUpdate( + kSessionFlowControlStreamId, initial_window_size + delta_window_size)); MockWrite writes[] = { CreateMockWrite(*window_update, 0), }; @@ -3534,18 +3535,17 @@ EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION, session->flow_control_state()); - EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_); + EXPECT_EQ(initial_window_size, session->session_recv_window_size_); EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); session->IncreaseRecvWindowSize(delta_window_size); - EXPECT_EQ(kSpdySessionInitialWindowSize + delta_window_size, + EXPECT_EQ(initial_window_size + delta_window_size, session->session_recv_window_size_); EXPECT_EQ(delta_window_size, session->session_unacked_recv_window_bytes_); // Should trigger sending a WINDOW_UPDATE frame. - session->IncreaseRecvWindowSize(kSpdySessionInitialWindowSize); - EXPECT_EQ(kSpdySessionInitialWindowSize + delta_window_size + - kSpdySessionInitialWindowSize, + session->IncreaseRecvWindowSize(initial_window_size); + EXPECT_EQ(initial_window_size + delta_window_size + initial_window_size, session->session_recv_window_size_); EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); @@ -3553,9 +3553,8 @@ // DecreaseRecvWindowSize() expects |in_io_loop_| to be true. session->in_io_loop_ = true; - session->DecreaseRecvWindowSize( - kSpdySessionInitialWindowSize + delta_window_size + - kSpdySessionInitialWindowSize); + session->DecreaseRecvWindowSize(initial_window_size + delta_window_size + + initial_window_size); session->in_io_loop_ = false; EXPECT_EQ(0, session->session_recv_window_size_); EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); @@ -3584,16 +3583,18 @@ EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION, session->flow_control_state()); + const int32 initial_window_size = + SpdySession::GetInitialWindowSize(GetParam()); const int32 delta_window_size = 100; - EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_); + EXPECT_EQ(initial_window_size, session->session_send_window_size_); session->IncreaseSendWindowSize(delta_window_size); - EXPECT_EQ(kSpdySessionInitialWindowSize + delta_window_size, + EXPECT_EQ(initial_window_size + delta_window_size, session->session_send_window_size_); session->DecreaseSendWindowSize(delta_window_size); - EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_); + EXPECT_EQ(initial_window_size, session->session_send_window_size_); } // Incoming data for an inactive stream should not cause the session @@ -3621,12 +3622,14 @@ EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION, session->flow_control_state()); - EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_); + EXPECT_EQ(SpdySession::GetInitialWindowSize(GetParam()), + session->session_recv_window_size_); EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); data.RunFor(1); - EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_); + EXPECT_EQ(SpdySession::GetInitialWindowSize(GetParam()), + session->session_recv_window_size_); EXPECT_EQ(kUploadDataSize, session->session_unacked_recv_window_bytes_); data.RunFor(1); @@ -3711,7 +3714,9 @@ stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND)); EXPECT_TRUE(stream->HasUrlFromHeaders()); - EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_); + const int32 initial_window_size = + SpdySession::GetInitialWindowSize(GetParam()); + EXPECT_EQ(initial_window_size, session->session_recv_window_size_); EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); data.RunFor(4); @@ -3719,7 +3724,7 @@ EXPECT_TRUE(data.at_write_eof()); EXPECT_TRUE(data.at_read_eof()); - EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_); + EXPECT_EQ(initial_window_size, session->session_recv_window_size_); EXPECT_EQ(msg_data_size, session->session_unacked_recv_window_bytes_); stream->Close(); @@ -3727,7 +3732,7 @@ EXPECT_EQ(OK, delegate.WaitForClose()); - EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_); + EXPECT_EQ(initial_window_size, session->session_recv_window_size_); EXPECT_EQ(msg_data_size, session->session_unacked_recv_window_bytes_); } @@ -3786,25 +3791,27 @@ stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND)); EXPECT_TRUE(stream->HasUrlFromHeaders()); - EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_); + const int32 initial_window_size = + SpdySession::GetInitialWindowSize(GetParam()); + EXPECT_EQ(initial_window_size, session->session_send_window_size_); data.RunFor(1); - EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_); + EXPECT_EQ(initial_window_size, session->session_send_window_size_); data.RunFor(1); EXPECT_TRUE(data.at_write_eof()); EXPECT_TRUE(data.at_read_eof()); - EXPECT_EQ(kSpdySessionInitialWindowSize - msg_data_size, + EXPECT_EQ(initial_window_size - msg_data_size, session->session_send_window_size_); // Closing the stream should increase the session's send window. stream->Close(); EXPECT_EQ(NULL, stream.get()); - EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_); + EXPECT_EQ(initial_window_size, session->session_send_window_size_); EXPECT_EQ(OK, delegate.WaitForClose()); } @@ -3875,42 +3882,44 @@ stream->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND)); EXPECT_TRUE(stream->HasUrlFromHeaders()); - EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_); - EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_); + const int32 initial_window_size = + SpdySession::GetInitialWindowSize(GetParam()); + EXPECT_EQ(initial_window_size, session->session_send_window_size_); + EXPECT_EQ(initial_window_size, session->session_recv_window_size_); EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); data.RunFor(1); - EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_); - EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_); + EXPECT_EQ(initial_window_size, session->session_send_window_size_); + EXPECT_EQ(initial_window_size, session->session_recv_window_size_); EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); data.RunFor(1); - EXPECT_EQ(kSpdySessionInitialWindowSize - msg_data_size, + EXPECT_EQ(initial_window_size - msg_data_size, session->session_send_window_size_); - EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_); + EXPECT_EQ(initial_window_size, session->session_recv_window_size_); EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); data.RunFor(1); - EXPECT_EQ(kSpdySessionInitialWindowSize - msg_data_size, + EXPECT_EQ(initial_window_size - msg_data_size, session->session_send_window_size_); - EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_); + EXPECT_EQ(initial_window_size, session->session_recv_window_size_); EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); data.RunFor(1); - EXPECT_EQ(kSpdySessionInitialWindowSize - msg_data_size, + EXPECT_EQ(initial_window_size - msg_data_size, session->session_send_window_size_); - EXPECT_EQ(kSpdySessionInitialWindowSize - msg_data_size, + EXPECT_EQ(initial_window_size - msg_data_size, session->session_recv_window_size_); EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); data.RunFor(1); - EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_); - EXPECT_EQ(kSpdySessionInitialWindowSize - msg_data_size, + EXPECT_EQ(initial_window_size, session->session_send_window_size_); + EXPECT_EQ(initial_window_size - msg_data_size, session->session_recv_window_size_); EXPECT_EQ(0, session->session_unacked_recv_window_bytes_); @@ -3921,8 +3930,8 @@ // Draining the delegate's read queue should increase the session's // receive window. - EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_); - EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_); + EXPECT_EQ(initial_window_size, session->session_send_window_size_); + EXPECT_EQ(initial_window_size, session->session_recv_window_size_); EXPECT_EQ(msg_data_size, session->session_unacked_recv_window_bytes_); stream->Close(); @@ -3930,8 +3939,8 @@ EXPECT_EQ(OK, delegate.WaitForClose()); - EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_send_window_size_); - EXPECT_EQ(kSpdySessionInitialWindowSize, session->session_recv_window_size_); + EXPECT_EQ(initial_window_size, session->session_send_window_size_); + EXPECT_EQ(initial_window_size, session->session_recv_window_size_); EXPECT_EQ(msg_data_size, session->session_unacked_recv_window_bytes_); }
diff --git a/net/spdy/spdy_stream_unittest.cc b/net/spdy/spdy_stream_unittest.cc index e8915bb..b8638d9 100644 --- a/net/spdy/spdy_stream_unittest.cc +++ b/net/spdy/spdy_stream_unittest.cc
@@ -186,12 +186,9 @@ base::WeakPtr<SpdySession> spdy_session(CreateDefaultSpdySession()); // Conjure up a stream. - SpdyStream stream(SPDY_PUSH_STREAM, - spdy_session, - GURL(), - DEFAULT_PRIORITY, - kSpdyStreamInitialWindowSize, - kSpdyStreamInitialWindowSize, + SpdyStream stream(SPDY_PUSH_STREAM, spdy_session, GURL(), DEFAULT_PRIORITY, + SpdySession::GetInitialWindowSize(kProtoSPDY31), + SpdySession::GetInitialWindowSize(kProtoSPDY31), BoundNetLog()); stream.set_stream_id(2); EXPECT_FALSE(stream.HasUrlFromHeaders());
diff --git a/net/spdy/spdy_test_util_common.cc b/net/spdy/spdy_test_util_common.cc index 9543e64..f0765a09 100644 --- a/net/spdy/spdy_test_util_common.cc +++ b/net/spdy/spdy_test_util_common.cc
@@ -367,7 +367,8 @@ enable_ping(false), enable_user_alternate_protocol_ports(false), protocol(protocol), - stream_initial_recv_window_size(kSpdyStreamInitialWindowSize), + stream_initial_recv_window_size( + SpdySession::GetInitialWindowSize(protocol)), time_func(&base::TimeTicks::Now), force_spdy_over_ssl(false), force_spdy_always(false), @@ -384,8 +385,8 @@ host_resolver->set_synchronous_mode(true); } -SpdySessionDependencies::SpdySessionDependencies( - NextProto protocol, ProxyService* proxy_service) +SpdySessionDependencies::SpdySessionDependencies(NextProto protocol, + ProxyService* proxy_service) : host_resolver(new MockHostResolver), cert_verifier(new MockCertVerifier), transport_security_state(new TransportSecurityState), @@ -400,7 +401,8 @@ enable_ping(false), enable_user_alternate_protocol_ports(false), protocol(protocol), - stream_initial_recv_window_size(kSpdyStreamInitialWindowSize), + stream_initial_recv_window_size( + SpdySession::GetInitialWindowSize(protocol)), time_func(&base::TimeTicks::Now), force_spdy_over_ssl(false), force_spdy_always(false),
diff --git a/net/ssl/ssl_connection_status_flags.h b/net/ssl/ssl_connection_status_flags.h index faae306..e2a8193 100644 --- a/net/ssl/ssl_connection_status_flags.h +++ b/net/ssl/ssl_connection_status_flags.h
@@ -13,7 +13,6 @@ // Status flags for SSLInfo::connection_status. enum { // The lower 16 bits are reserved for the TLS ciphersuite id. - SSL_CONNECTION_CIPHERSUITE_SHIFT = 0, SSL_CONNECTION_CIPHERSUITE_MASK = 0xffff, // The next two bits are reserved for the compression used. @@ -53,9 +52,8 @@ COMPILE_ASSERT(SSL_CONNECTION_VERSION_MAX - 1 <= SSL_CONNECTION_VERSION_MASK, SSL_CONNECTION_VERSION_MASK_too_small); -inline int SSLConnectionStatusToCipherSuite(int connection_status) { - return (connection_status >> SSL_CONNECTION_CIPHERSUITE_SHIFT) & - SSL_CONNECTION_CIPHERSUITE_MASK; +inline uint16 SSLConnectionStatusToCipherSuite(int connection_status) { + return static_cast<uint16>(connection_status); } inline int SSLConnectionStatusToVersion(int connection_status) { @@ -63,14 +61,12 @@ SSL_CONNECTION_VERSION_MASK; } -inline void SSLConnectionStatusSetCipherSuite(int cipher_suite, +inline void SSLConnectionStatusSetCipherSuite(uint16 cipher_suite, int* connection_status) { // Clear out the old ciphersuite. - *connection_status &= - ~(SSL_CONNECTION_CIPHERSUITE_MASK << SSL_CONNECTION_CIPHERSUITE_SHIFT); + *connection_status &= ~SSL_CONNECTION_CIPHERSUITE_MASK; // Set the new ciphersuite. - *connection_status |= ((cipher_suite & SSL_CONNECTION_CIPHERSUITE_MASK) - << SSL_CONNECTION_CIPHERSUITE_SHIFT); + *connection_status |= cipher_suite; } inline void SSLConnectionStatusSetVersion(int version, int* connection_status) {
diff --git a/net/ssl/ssl_connection_status_flags_unittest.cc b/net/ssl/ssl_connection_status_flags_unittest.cc index 64fea13..98e4f53 100644 --- a/net/ssl/ssl_connection_status_flags_unittest.cc +++ b/net/ssl/ssl_connection_status_flags_unittest.cc
@@ -15,13 +15,13 @@ int expected_version = SSLConnectionStatusToVersion(connection_status); SSLConnectionStatusSetCipherSuite(12345, &connection_status); - EXPECT_EQ(12345, SSLConnectionStatusToCipherSuite(connection_status)); + EXPECT_EQ(12345U, SSLConnectionStatusToCipherSuite(connection_status)); EXPECT_EQ(expected_version, SSLConnectionStatusToVersion(connection_status)); } TEST(SSLConnectionStatusTest, SetVersion) { int connection_status = 0xDEADBEEF; - int expected_cipher_suite = + uint16 expected_cipher_suite = SSLConnectionStatusToCipherSuite(connection_status); SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_TLS1_2,
diff --git a/net/tools/quic/quic_client.h b/net/tools/quic/quic_client.h index 4111b1a..6bf87f9 100644 --- a/net/tools/quic/quic_client.h +++ b/net/tools/quic/quic_client.h
@@ -246,9 +246,8 @@ bool initialized_; // If overflow_supported_ is true, this will be the number of packets dropped - // during the lifetime of the server. This may overflow if enough packets - // are dropped. - uint32 packets_dropped_; + // during the lifetime of the server. + QuicPacketCount packets_dropped_; // True if the kernel supports SO_RXQ_OVFL, the number of packets dropped // because the socket would otherwise overflow.
diff --git a/net/tools/quic/quic_server.cc b/net/tools/quic/quic_server.cc index 26943653..fd24059 100644 --- a/net/tools/quic/quic_server.cc +++ b/net/tools/quic/quic_server.cc
@@ -204,7 +204,7 @@ bool QuicServer::ReadAndDispatchSinglePacket(int fd, int port, ProcessPacketInterface* processor, - uint32* packets_dropped) { + QuicPacketCount* packets_dropped) { // Allocate some extra space so we can send an error if the client goes over // the limit. char buf[2 * kMaxPacketSize];
diff --git a/net/tools/quic/quic_server.h b/net/tools/quic/quic_server.h index 980f9ba2..f8a5533 100644 --- a/net/tools/quic/quic_server.h +++ b/net/tools/quic/quic_server.h
@@ -58,7 +58,7 @@ // dropped packets. static bool ReadAndDispatchSinglePacket(int fd, int port, ProcessPacketInterface* processor, - uint32* packets_dropped); + QuicPacketCount* packets_dropped); void OnShutdown(EpollServer* eps, int fd) override {} @@ -74,7 +74,7 @@ bool overflow_supported() { return overflow_supported_; } - uint32 packets_dropped() { return packets_dropped_; } + QuicPacketCount packets_dropped() { return packets_dropped_; } int port() { return port_; } @@ -110,7 +110,7 @@ // If overflow_supported_ is true this will be the number of packets dropped // during the lifetime of the server. This may overflow if enough packets // are dropped. - uint32 packets_dropped_; + QuicPacketCount packets_dropped_; // True if the kernel supports SO_RXQ_OVFL, the number of packets dropped // because the socket would otherwise overflow.
diff --git a/net/tools/quic/quic_socket_utils.cc b/net/tools/quic/quic_socket_utils.cc index f11647b9..3ac0bf31 100644 --- a/net/tools/quic/quic_socket_utils.cc +++ b/net/tools/quic/quic_socket_utils.cc
@@ -51,8 +51,9 @@ } // static -bool QuicSocketUtils::GetOverflowFromMsghdr(struct msghdr *hdr, - uint32 *dropped_packets) { +bool QuicSocketUtils::GetOverflowFromMsghdr( + struct msghdr *hdr, + QuicPacketCount *dropped_packets) { if (hdr->msg_controllen > 0) { struct cmsghdr *cmsg; for (cmsg = CMSG_FIRSTHDR(hdr); @@ -99,7 +100,7 @@ // static int QuicSocketUtils::ReadPacket(int fd, char* buffer, size_t buf_len, - uint32* dropped_packets, + QuicPacketCount* dropped_packets, IPAddressNumber* self_address, IPEndPoint* peer_address) { CHECK(peer_address != nullptr);
diff --git a/net/tools/quic/quic_socket_utils.h b/net/tools/quic/quic_socket_utils.h index 03b95e51..41d3b93c 100644 --- a/net/tools/quic/quic_socket_utils.h +++ b/net/tools/quic/quic_socket_utils.h
@@ -13,6 +13,7 @@ #include "base/basictypes.h" #include "net/base/ip_endpoint.h" +#include "net/quic/quic_bandwidth.h" #include "net/quic/quic_types.h" namespace net { @@ -28,7 +29,7 @@ // If the msghdr contains an SO_RXQ_OVFL entry, this will set dropped_packets // to the correct value and return true. Otherwise it will return false. static bool GetOverflowFromMsghdr(struct msghdr *hdr, - uint32 *dropped_packets); + QuicPacketCount *dropped_packets); // Sets either IP_PKTINFO or IPV6_PKTINFO on the socket, based on // address_family. Returns the return code from setsockopt. @@ -52,7 +53,7 @@ static int ReadPacket(int fd, char* buffer, size_t buf_len, - uint32* dropped_packets, + QuicPacketCount* dropped_packets, IPAddressNumber* self_address, IPEndPoint* peer_address);
diff --git a/net/url_request/sdch_dictionary_fetcher.cc b/net/url_request/sdch_dictionary_fetcher.cc index 9aeed9a..450a6082 100644 --- a/net/url_request/sdch_dictionary_fetcher.cc +++ b/net/url_request/sdch_dictionary_fetcher.cc
@@ -11,6 +11,7 @@ #include "base/compiler_specific.h" #include "base/profiler/scoped_tracker.h" #include "base/thread_task_runner_handle.h" +#include "net/base/io_buffer.h" #include "net/base/load_flags.h" #include "net/base/sdch_net_log_params.h" #include "net/url_request/url_request_context.h"
diff --git a/net/url_request/url_fetcher_core.cc b/net/url_request/url_fetcher_core.cc index 23399f3..420e831 100644 --- a/net/url_request/url_fetcher_core.cc +++ b/net/url_request/url_fetcher_core.cc
@@ -436,16 +436,36 @@ URLRequestThrottlerManager* throttler_manager = request->context()->throttler_manager(); if (throttler_manager) { + // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed. + tracked_objects::ScopedTracker tracking_profile1( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "423948 URLFetcherCore::OnReadCompleted1")); + url_throttler_entry_ = throttler_manager->RegisterRequestUrl(url_); } + // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed. + tracked_objects::ScopedTracker tracking_profile2( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "423948 URLFetcherCore::OnReadCompleted2")); + do { if (!request_->status().is_success() || bytes_read <= 0) break; + // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed. + tracked_objects::ScopedTracker tracking_profile3( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "423948 URLFetcherCore::OnReadCompleted3")); + current_response_bytes_ += bytes_read; InformDelegateDownloadProgress(); + // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed. + tracked_objects::ScopedTracker tracking_profile4( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "423948 URLFetcherCore::OnReadCompleted4")); + const int result = WriteBuffer(new DrainableIOBuffer(buffer_.get(), bytes_read)); if (result < 0) { @@ -456,17 +476,38 @@ const URLRequestStatus status = request_->status(); + // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed. + tracked_objects::ScopedTracker tracking_profile5( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "423948 URLFetcherCore::OnReadCompleted5")); + if (status.is_success()) request_->GetResponseCookies(&cookies_); // See comments re: HEAD requests in ReadResponse(). if (!status.is_io_pending() || request_type_ == URLFetcher::HEAD) { + // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed. + tracked_objects::ScopedTracker tracking_profile6( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "423948 URLFetcherCore::OnReadCompleted6")); + status_ = status; ReleaseRequest(); + // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed. + tracked_objects::ScopedTracker tracking_profile7( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "423948 URLFetcherCore::OnReadCompleted7")); + // No more data to write. const int result = response_writer_->Finish( base::Bind(&URLFetcherCore::DidFinishWriting, this)); + + // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed. + tracked_objects::ScopedTracker tracking_profile8( + FROM_HERE_WITH_EXPLICIT_FUNCTION( + "423948 URLFetcherCore::OnReadCompleted8")); + if (result != ERR_IO_PENDING) DidFinishWriting(result); }
diff --git a/net/url_request/url_request_simple_job.cc b/net/url_request/url_request_simple_job.cc index 060a90e..ebc2b5df 100644 --- a/net/url_request/url_request_simple_job.cc +++ b/net/url_request/url_request_simple_job.cc
@@ -53,9 +53,9 @@ "422489 URLRequestSimpleJob::ReadRawData")); DCHECK(bytes_read); - int remaining = byte_range_.last_byte_position() - data_offset_ + 1; - if (buf_size > remaining) - buf_size = remaining; + buf_size = static_cast<int>(std::min( + static_cast<int64>(buf_size), + byte_range_.last_byte_position() - data_offset_ + 1)); memcpy(buf->data(), data_->front() + data_offset_, buf_size); data_offset_ += buf_size; *bytes_read = buf_size; @@ -138,9 +138,8 @@ } data_offset_ = byte_range_.first_byte_position(); - int remaining_bytes = byte_range_.last_byte_position() - - byte_range_.first_byte_position() + 1; - set_expected_content_size(remaining_bytes); + set_expected_content_size( + byte_range_.last_byte_position() - data_offset_ + 1); NotifyHeadersComplete(); } else { NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED, result));
diff --git a/net/url_request/url_request_simple_job.h b/net/url_request/url_request_simple_job.h index 99b6cb6..f605fe4 100644 --- a/net/url_request/url_request_simple_job.h +++ b/net/url_request/url_request_simple_job.h
@@ -66,7 +66,7 @@ std::string mime_type_; std::string charset_; scoped_refptr<base::RefCountedMemory> data_; - int data_offset_; + int64 data_offset_; base::WeakPtrFactory<URLRequestSimpleJob> weak_factory_; };
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc index 9892a692..b114ecc 100644 --- a/net/url_request/url_request_unittest.cc +++ b/net/url_request/url_request_unittest.cc
@@ -258,9 +258,9 @@ EXPECT_GT(ssl_info.security_bits, 0); // The cipher suite TLS_NULL_WITH_NULL_NULL (0) must not be negotiated. - int cipher_suite = SSLConnectionStatusToCipherSuite( + uint16 cipher_suite = SSLConnectionStatusToCipherSuite( ssl_info.connection_status); - EXPECT_NE(0, cipher_suite); + EXPECT_NE(0U, cipher_suite); } void CheckFullRequestHeaders(const HttpRequestHeaders& headers, @@ -3763,7 +3763,7 @@ ASSERT_LT(upper_bound, 1000000); } - int tolerance = upper_bound * 0.005; + int tolerance = static_cast<int>(upper_bound * 0.005); if (tolerance < 2) tolerance = 2; @@ -4969,8 +4969,10 @@ base::RunLoop().Run(); - int64 size = 0; - ASSERT_EQ(true, base::GetFileSize(path, &size)); + int64 size64 = 0; + ASSERT_EQ(true, base::GetFileSize(path, &size64)); + ASSERT_LE(size64, std::numeric_limits<int>::max()); + int size = static_cast<int>(size64); scoped_ptr<char[]> buf(new char[size]); ASSERT_EQ(size, base::ReadFile(path, buf.get(), size));
diff --git a/net/websockets/websocket_basic_handshake_stream.cc b/net/websockets/websocket_basic_handshake_stream.cc index 08ee6ae..bac2438 100644 --- a/net/websockets/websocket_basic_handshake_stream.cc +++ b/net/websockets/websocket_basic_handshake_stream.cc
@@ -25,6 +25,7 @@ #include "base/strings/stringprintf.h" #include "base/time/time.h" #include "crypto/random.h" +#include "net/base/io_buffer.h" #include "net/http/http_request_headers.h" #include "net/http/http_request_info.h" #include "net/http/http_response_body_drainer.h"
diff --git a/ppapi/ppapi_nacl_test_common.gypi b/ppapi/ppapi_nacl_test_common.gypi index ca119fe..ea61327 100644 --- a/ppapi/ppapi_nacl_test_common.gypi +++ b/ppapi/ppapi_nacl_test_common.gypi
@@ -163,7 +163,7 @@ 'outputs': ['>(nmf_glibc)'], 'action': [ 'python', - '>(create_nmf)', + '>@(_inputs)', '--objdump=>(nacl_objdump)', '--output=>(nmf_glibc)', '--path-prefix=>(nexe_target)_libs', @@ -174,7 +174,6 @@ ['enable_x86_64==1', { 'inputs': ['>(out_glibc64)'], 'action': [ - '>(out_glibc64)', '--library-path=>(libdir_glibc64)', '--library-path=>(tc_lib_dir_glibc64)', ], @@ -182,7 +181,6 @@ ['enable_x86_32==1', { 'inputs': ['>(out_glibc32)'], 'action': [ - '>(out_glibc32)', '--library-path=>(libdir_glibc32)', '--library-path=>(tc_lib_dir_glibc32)', ],
diff --git a/remoting/client/plugin/pepper_cursor_setter.cc b/remoting/client/plugin/pepper_cursor_setter.cc index bfb904d2..90052b1 100644 --- a/remoting/client/plugin/pepper_cursor_setter.cc +++ b/remoting/client/plugin/pepper_cursor_setter.cc
@@ -29,10 +29,11 @@ // Clear PPAPI cursor and fall-back to rendering cursor via delegate. pp::MouseCursor::SetCursor(instance_, PP_MOUSECURSOR_TYPE_NONE); delegate_stub_->SetCursorShape(cursor_shape); + } else { + // TODO(wez): Fall-back to cropping & re-trying the cursor iff there is no + // delegate and the cursor is >32x32? + DLOG(FATAL) << "Failed to set PPAPI cursor, and no delegate provided."; } - // TODO(wez): Fall-back to cropping & re-trying the cursor iff there is no - // delegate and the cursor is >32x32? - DLOG(FATAL) << "Failed to set PPAPI cursor, and no delegate provided."; } bool PepperCursorSetter::SetInstanceCursor(
diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp index 1a57b7d0..02b7a66 100644 --- a/remoting/remoting.gyp +++ b/remoting/remoting.gyp
@@ -171,7 +171,7 @@ 'host/win/version.rc.jinja2', 'resources/play_store_resources.cc', 'webapp/crd/manifest.json.jinja2', - '<@(remoting_webapp_all_js_files)', + '<@(remoting_webapp_crd_js_files)', ], }, 'actions': [
diff --git a/remoting/remoting_client.gypi b/remoting/remoting_client.gypi index 786389a..f2414ac 100644 --- a/remoting/remoting_client.gypi +++ b/remoting/remoting_client.gypi
@@ -69,7 +69,9 @@ '<(SHARED_INTERMEDIATE_DIR)/main.html', '<(remoting_webapp_template_main)', '--template', '<@(remoting_webapp_template_files)', - '--js', '<@(remoting_webapp_main_html_js_files)', + '--js', + '<@(remoting_webapp_shared_main_html_js_files)', + '<@(remoting_webapp_crd_main_html_js_files)', ], }, {
diff --git a/remoting/remoting_test.gypi b/remoting/remoting_test.gypi index 23f43c7d..2251868 100644 --- a/remoting/remoting_test.gypi +++ b/remoting/remoting_test.gypi
@@ -331,7 +331,7 @@ 'variables': { 'output_dir': '<(PRODUCT_DIR)/remoting/unittests', 'webapp_js_files': [ - '<@(remoting_webapp_main_html_js_files)', + '<@(remoting_webapp_shared_main_html_js_files)', '<@(remoting_webapp_js_wcs_sandbox_files)', '<@(remoting_webapp_background_js_files)', ]
diff --git a/remoting/remoting_webapp.gypi b/remoting/remoting_webapp.gypi index 57d0c36..05a1321 100644 --- a/remoting/remoting_webapp.gypi +++ b/remoting/remoting_webapp.gypi
@@ -27,7 +27,7 @@ { 'action_name': 'Verify remoting webapp', 'inputs': [ - '<@(remoting_webapp_all_js_files)', + '<@(remoting_webapp_crd_js_files)', '<@(remoting_webapp_js_proto_files)', ], 'outputs': [ @@ -35,7 +35,7 @@ ], 'action': [ 'python', 'tools/jscompile.py', - '<@(remoting_webapp_all_js_files)', + '<@(remoting_webapp_crd_js_files)', '<@(remoting_webapp_js_proto_files)', '--success-stamp', '<(success_stamp)' ], @@ -52,7 +52,7 @@ '<(chrome_version_path)', '<(remoting_version_path)', '<@(generated_html_files)', - '<@(remoting_webapp_files)', + '<@(remoting_webapp_crd_files)', '<@(remoting_webapp_locale_files)', '<@(extra_files)', ], @@ -69,7 +69,7 @@ 'webapp/crd/manifest.json.jinja2', '<(webapp_type)', '<@(generated_html_files)', - '<@(remoting_webapp_files)', + '<@(remoting_webapp_crd_files)', '<@(extra_files)', '--locales', '<@(remoting_webapp_locale_files)', ],
diff --git a/remoting/remoting_webapp_files.gypi b/remoting/remoting_webapp_files.gypi index 358dbe5444..3275f99 100644 --- a/remoting/remoting_webapp_files.gypi +++ b/remoting/remoting_webapp_files.gypi
@@ -34,6 +34,7 @@ # Auth (Google account) JavaScript files. 'remoting_webapp_js_auth_google_files': [ 'webapp/base/js/auth_dialog.js', + 'webapp/base/js/auth_init.js', 'webapp/crd/js/identity.js', 'webapp/crd/js/oauth2.js', 'webapp/crd/js/oauth2_api.js', @@ -154,9 +155,6 @@ # background.js is where the onLoad handler is defined, which # makes it the entry point of the background page. 'webapp/crd/js/background.js', - # event_handlers.js is where the onLoad handler is defined, which - # makes it the entry point of the webapp. - 'webapp/crd/js/event_handlers.js', ], # The unit test cases for the webapp 'remoting_webapp_unittest_js_files': [ @@ -178,8 +176,8 @@ 'remoting_webapp_unittest_template_main': 'webapp/crd/html/template_unittest.html', - # The JavaScript files required by main.html. - 'remoting_webapp_main_html_js_files': [ + # The shared JavaScript files required by main.html. + 'remoting_webapp_shared_main_html_js_files': [ # Include the core files first as it is required by the other files. # Otherwise, Jscompile will complain. '<@(remoting_webapp_js_core_files)', @@ -199,6 +197,11 @@ # '<@(remoting_webapp_js_browser_test_files)' ], + # The CRD-specific JavaScript files required by main.html. + 'remoting_webapp_crd_main_html_js_files': [ + 'webapp/crd/js/crd_main.js', + ], + # The JavaScript files that are used in the background page. 'remoting_webapp_background_js_files': [ 'webapp/base/js/base.js', @@ -229,10 +232,10 @@ 'webapp/crd/js/plugin_settings.js', ], - # All the JavaScript files required by the webapp. - 'remoting_webapp_all_js_files': [ + # All the JavaScript files that are shared by webapps. + 'remoting_webapp_shared_js_files': [ # JS files for main.html. - '<@(remoting_webapp_main_html_js_files)', + '<@(remoting_webapp_shared_main_html_js_files)', '<@(remoting_webapp_background_js_files)', # JS files for message_window.html 'webapp/base/js/message_window.js', @@ -244,6 +247,12 @@ '<@(remoting_webapp_js_auth_v1_files)', ], + # All the JavaScript files required by CRD. + 'remoting_webapp_crd_js_files': [ + '<@(remoting_webapp_shared_js_files)', + '<@(remoting_webapp_crd_main_html_js_files)', + ], + 'remoting_webapp_resource_files': [ 'resources/disclosure_arrow_down.webp', 'resources/disclosure_arrow_right.webp', @@ -279,9 +288,9 @@ 'webapp/crd/resources/scale-to-fit.webp', ], - 'remoting_webapp_files': [ + 'remoting_webapp_crd_files': [ '<@(remoting_webapp_info_files)', - '<@(remoting_webapp_all_js_files)', + '<@(remoting_webapp_crd_js_files)', '<@(remoting_webapp_resource_files)', ],
diff --git a/remoting/resources/remoting_strings.grd b/remoting/resources/remoting_strings.grd index 99bc94a..d7eefcd 100644 --- a/remoting/resources/remoting_strings.grd +++ b/remoting/resources/remoting_strings.grd
@@ -28,13 +28,17 @@ <output filename="remoting/resources/en-AU.pak" lang="en-AU" type="data_package"/> </if> <output filename="remoting/resources/en-GB.pak" lang="en-GB" type="data_package"/> - <if expr="chromeos"> + <if expr="chromeos or is_ios"> <output filename="remoting/resources/en-US.pak" lang="en" type="data_package"/> </if> <output filename="remoting/resources/en.pak" lang="en" type="data_package"/> <if expr="use_third_party_translations"> <output filename="remoting/resources/eo.pak" lang="eo" type="data_package"/> </if> + <if expr="is_ios"> + <!-- iOS uses es-MX for es-419 --> + <output filename="remoting/resources/es-MX.pak" lang="es-419" type="data_package"/> + </if> <output filename="remoting/resources/es-419.pak" lang="es-419" type="data_package"/> <output filename="remoting/resources/es.pak" lang="es" type="data_package"/> <output filename="remoting/resources/et.pak" lang="et" type="data_package"/> @@ -79,6 +83,10 @@ <output filename="remoting/resources/nb.pak" lang="no" type="data_package"/> <output filename="remoting/resources/nl.pak" lang="nl" type="data_package"/> <output filename="remoting/resources/pl.pak" lang="pl" type="data_package"/> + <if expr="is_ios"> + <!-- iOS uses pt for pt-BR --> + <output filename="remoting/resources/pt.pak" lang="pt-BR" type="data_package"/> + </if> <output filename="remoting/resources/pt-BR.pak" lang="pt-BR" type="data_package"/> <output filename="remoting/resources/pt-PT.pak" lang="pt-PT" type="data_package"/> <output filename="remoting/resources/ro.pak" lang="ro" type="data_package"/> @@ -254,7 +262,7 @@ <release allow_pseudo="false" seq="1"> <messages fallback_to_english="true"> <if expr="_google_chrome"> - <if expr="is_android"> + <if expr="is_android or is_ios"> <message desc="Message shown in popup dialog on Android when there are no Google accounts on the device" name="IDS_NOACCOUNTS_MESSAGE" formatter_data="android_java"> To use Chrome Remote Desktop, you'll need to add a Google Account to your device. </message> @@ -356,7 +364,7 @@ </if> <if expr="not _google_chrome"> - <if expr="is_android"> + <if expr="is_android or is_ios"> <message desc="Message shown in popup dialog on Android when there are no Google accounts on the device" name="IDS_NOACCOUNTS_MESSAGE" formatter_data="android_java"> To use Chromoting, you'll need to add a Google Account to your device. </message> @@ -457,7 +465,7 @@ </message> </if> - <if expr="is_android"> + <if expr="is_android or is_ios"> <message desc="Button to show or hide the on-screen keyboard." name="IDS_SHOW_HIDE_KEYBOARD" formatter_data="android_java"> Show/hide keyboard. </message>
diff --git a/remoting/tools/build/remoting_ios_localize.py b/remoting/tools/build/remoting_ios_localize.py new file mode 100755 index 0000000..04beb18 --- /dev/null +++ b/remoting/tools/build/remoting_ios_localize.py
@@ -0,0 +1,311 @@ +#!/usr/bin/env python +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Tool to produce localized strings for the remoting iOS client. + +This script uses a subset of grit-generated string data-packs to produce +localized string files appropriate for iOS. + +For each locale, it generates the following: + +<locale>.lproj/ + Localizable.strings + InfoPlist.strings + +The strings in Localizable.strings are specified in a file containing a list of +IDS. E.g.: + +Given: Localizable_ids.txt: +IDS_PRODUCT_NAME +IDS_SIGN_IN_BUTTON +IDS_CANCEL + +Produces: Localizable.strings: +"IDS_PRODUCT_NAME" = "Remote Desktop"; +"IDS_SIGN_IN_BUTTON" = "Sign In"; +"IDS_CANCEL" = "Cancel"; + +The InfoPlist.strings is formatted using a Jinja2 template where the "ids" +variable is a dictionary of id -> string. E.g.: + +Given: InfoPlist.strings.jinja2: +"CFBundleName" = "{{ ids.IDS_PRODUCT_NAME }}" +"CFCopyrightNotice" = "{{ ids.IDS_COPYRIGHT }}" + +Produces: InfoPlist.strings: +"CFBundleName" = "Remote Desktop"; +"CFCopyrightNotice" = "Copyright 2014 The Chromium Authors."; + +Parameters: + --print-inputs + Prints the expected input file list, then exit. This can be used in gyp + input rules. + + --print-outputs + Prints the expected output file list, then exit. This can be used in gyp + output rules. + + --from-dir FROM_DIR + Specify the directory containing the data pack files generated by grit. + Each data pack should be named <locale>.pak. + + --to-dir TO_DIR + Specify the directory to write the <locale>.lproj directories containing + the string files. + + --localizable-list LOCALIZABLE_ID_LIST + Specify the file containing the list of the IDs of the strings that each + Localizable.strings file should contain. + + --infoplist-template INFOPLIST_TEMPLATE + Specify the Jinja2 template to be used to create each InfoPlist.strings + file. + + --resources-header RESOURCES_HEADER + Specifies the grit-generated header file that maps ID names to ID values. + It's required to map the IDs in LOCALIZABLE_ID_LIST and INFOPLIST_TEMPLATE + to strings in the data packs. +""" + + +import codecs +import optparse +import os +import re +import sys + +sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', '..', + 'tools', 'grit')) +from grit.format import data_pack + +sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', '..', + 'third_party')) +import jinja2 + + +LOCALIZABLE_STRINGS = 'Localizable.strings' +INFOPLIST_STRINGS = 'InfoPlist.strings' + + +class LocalizeException(Exception): + pass + + +class LocalizedStringJinja2Adapter: + """Class that maps ID names to localized strings in Jinja2.""" + def __init__(self, id_map, pack): + self.id_map = id_map + self.pack = pack + + def __getattr__(self, name): + id_value = self.id_map.get(name) + if not id_value: + raise LocalizeException('Could not find id %s in resource header' % name) + data = self.pack.resources.get(id_value) + if not data: + raise LocalizeException( + 'Could not find string with id %s (%d) in data pack' % + (name, id_value)) + return decode_and_escape(data) + + +def get_inputs(from_dir, locales): + """Returns the list of files that would be required to run the tool.""" + inputs = [] + for locale in locales: + inputs.append(os.path.join(from_dir, '%s.pak' % locale)) + return format_quoted_list(inputs) + + +def get_outputs(to_dir, locales): + """Returns the list of files that would be produced by the tool.""" + outputs = [] + for locale in locales: + lproj_dir = format_lproj_dir(to_dir, locale) + outputs.append(os.path.join(lproj_dir, LOCALIZABLE_STRINGS)) + outputs.append(os.path.join(lproj_dir, INFOPLIST_STRINGS)) + return format_quoted_list(outputs) + + +def format_quoted_list(items): + """Formats a list as a string, with items space-separated and quoted.""" + return " ".join(['"%s"' % x for x in items]) + + +def format_lproj_dir(to_dir, locale): + """Formats the name of the lproj directory for a given locale.""" + locale = locale.replace('-', '_') + return os.path.join(to_dir, '%s.lproj' % locale) + + +def read_resources_header(resources_header_path): + """Reads and parses a grit-generated resource header file. + + This function will parse lines like the following: + + #define IDS_PRODUCT_NAME 28531 + #define IDS_CANCEL 28542 + + And return a dictionary like the following: + + { 'IDS_PRODUCT_NAME': 28531, 'IDS_CANCEL': 28542 } + """ + regex = re.compile(r'^#define\s+(\w+)\s+(\d+)$') + id_map = {} + try: + with open(resources_header_path, 'r') as f: + for line in f: + match = regex.match(line) + if match: + id_str = match.group(1) + id_value = int(match.group(2)) + id_map[id_str] = id_value + except: + sys.stderr.write('Error while reading header file %s\n' + % resources_header_path) + raise + + return id_map + + +def read_id_list(id_list_path): + """Read a text file with ID names. + + Names are stripped of leading and trailing spaces. Empty lines are ignored. + """ + with open(id_list_path, 'r') as f: + stripped_lines = [x.strip() for x in f] + non_empty_lines = [x for x in stripped_lines if x] + return non_empty_lines + + +def read_jinja2_template(template_path): + """Reads a Jinja2 template.""" + (template_dir, template_name) = os.path.split(template_path) + env = jinja2.Environment(loader = jinja2.FileSystemLoader(template_dir)) + template = env.get_template(template_name) + return template + + +def decode_and_escape(data): + """Decodes utf-8 data, and escapes it appropriately to use in *.strings.""" + u_string = codecs.decode(data, 'utf-8') + u_string = u_string.replace('\\', '\\\\') + u_string = u_string.replace('"', '\\"') + return u_string + + +def generate(from_dir, to_dir, localizable_list_path, infoplist_template_path, + resources_header_path, locales): + """Generates the <locale>.lproj directories and files.""" + + id_map = read_resources_header(resources_header_path) + localizable_ids = read_id_list(localizable_list_path) + infoplist_template = read_jinja2_template(infoplist_template_path) + + # Generate string files for each locale + for locale in locales: + pack = data_pack.ReadDataPack( + os.path.join(os.path.join(from_dir, '%s.pak' % locale))) + + lproj_dir = format_lproj_dir(to_dir, locale) + if not os.path.exists(lproj_dir): + os.makedirs(lproj_dir) + + # Generate Localizable.strings + localizable_strings_path = os.path.join(lproj_dir, LOCALIZABLE_STRINGS) + try: + with codecs.open(localizable_strings_path, 'w', 'utf-16') as f: + for id_str in localizable_ids: + id_value = id_map.get(id_str) + if not id_value: + raise LocalizeException('Could not find "%s" in %s' % + (id_str, resources_header_path)) + + localized_data = pack.resources.get(id_value) + if not localized_data: + raise LocalizeException( + 'Could not find localized string in %s for %s (%d)' % + (localizable_strings_path, id_str, id_value)) + + f.write(u'"%s" = "%s";\n' % + (id_str, decode_and_escape(localized_data))) + except: + sys.stderr.write('Error while creating %s\n' % localizable_strings_path) + raise + + # Generate InfoPlist.strings + infoplist_strings_path = os.path.join(lproj_dir, INFOPLIST_STRINGS) + try: + with codecs.open(infoplist_strings_path, 'w', 'utf-16') as f: + infoplist = infoplist_template.render( + ids = LocalizedStringJinja2Adapter(id_map, pack)) + f.write(infoplist) + except: + sys.stderr.write('Error while creating %s\n' % infoplist_strings_path) + raise + + +def DoMain(args): + """Entrypoint used by gyp's pymod_do_main.""" + parser = optparse.OptionParser("usage: %prog [options] locales") + parser.add_option("--print-inputs", action="store_true", dest="print_input", + default=False, + help="Print the expected input file list, then exit.") + parser.add_option("--print-outputs", action="store_true", dest="print_output", + default=False, + help="Print the expected output file list, then exit.") + parser.add_option("--from-dir", action="store", dest="from_dir", + help="Source data pack directory.") + parser.add_option("--to-dir", action="store", dest="to_dir", + help="Destination data pack directory.") + parser.add_option("--localizable-list", action="store", + dest="localizable_list", + help="File with list of IDS to build Localizable.strings") + parser.add_option("--infoplist-template", action="store", + dest="infoplist_template", + help="File with list of IDS to build InfoPlist.strings") + parser.add_option("--resources-header", action="store", + dest="resources_header", + help="Auto-generated header with resource ids.") + options, locales = parser.parse_args(args) + + if not locales: + parser.error('At least one locale is required.') + + if options.print_input and options.print_output: + parser.error('Only one of --print-inputs or --print-outputs is allowed') + + if options.print_input: + if not options.from_dir: + parser.error('--from-dir is required.') + return get_inputs(options.from_dir, locales) + + if options.print_output: + if not options.to_dir: + parser.error('--to-dir is required.') + return get_outputs(options.to_dir, locales) + + if not (options.from_dir and options.to_dir and options.localizable_list and + options.infoplist_template and options.resources_header): + parser.error('--from-dir, --to-dir, --localizable-list, ' + + '--infoplist-template and --resources-header are required.') + + try: + generate(options.from_dir, options.to_dir, options.localizable_list, + options.infoplist_template, options.resources_header, locales) + except LocalizeException as e: + sys.stderr.write('Error: %s\n' % str(e)) + sys.exit(1) + + return "" + + +def main(args): + print DoMain(args[1:]) + + +if __name__ == '__main__': + main(sys.argv)
diff --git a/remoting/webapp/base/js/auth_init.js b/remoting/webapp/base/js/auth_init.js new file mode 100644 index 0000000..4e849b5 --- /dev/null +++ b/remoting/webapp/base/js/auth_init.js
@@ -0,0 +1,81 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +'use strict'; + +/** @suppress {duplicate} */ +var remoting = remoting || {}; + +remoting.initIdentity = function() { + + /** + * Show the authorization consent UI and register a one-shot event handler to + * continue the authorization process. + * + * @param {function():void} authContinue Callback to invoke when the user + * clicks "Continue". + */ + function promptForConsent(authContinue) { + /** @type {HTMLElement} */ + var dialog = document.getElementById('auth-dialog'); + /** @type {HTMLElement} */ + var button = document.getElementById('auth-button'); + var consentGranted = function(event) { + dialog.hidden = true; + button.removeEventListener('click', consentGranted, false); + authContinue(); + remoting.windowShape.updateClientWindowShape(); + }; + dialog.hidden = false; + + /** @type {HTMLElement} */ + var dialog_border = document.getElementById('auth-dialog-border'); + remoting.authDialog = new remoting.AuthDialog(dialog_border); + remoting.windowShape.addCallback(remoting.authDialog); + + button.addEventListener('click', consentGranted, false); + } + + if (base.isAppsV2()) { + remoting.identity = new remoting.Identity(promptForConsent); + } else { + // TODO(garykac) Remove this and replace with identity. + remoting.oauth2 = new remoting.OAuth2(); + if (!remoting.oauth2.isAuthenticated()) { + document.getElementById('auth-dialog').hidden = false; + } + remoting.identity = remoting.oauth2; + } +} + +/** @param {remoting.Error} error */ +remoting.onGetIdentityInfoError = function(error) { + // No need to show the error message for NOT_AUTHENTICATED + // because we will show "auth-dialog". + if (error != remoting.Error.NOT_AUTHENTICATED) { + remoting.showErrorMessage(error); + } +} + +/** + * @param {function(string):void} onEmailAvailable Callback invoked when the + * email address is available. + * @return {void} Nothing. + */ +remoting.initIdentityEmail = function(onEmailAvailable) { + remoting.identity.getEmail(onEmailAvailable, + remoting.onGetIdentityInfoError); +} + +/** + * Get the user's email address and full name. + * + * @param {function(string,string):void} onUserInfoAvailable Callback invoked + * when the user's email address and full name are available. + * @return {void} Nothing. + */ +remoting.initIdentityUserInfo = function(onUserInfoAvailable) { + remoting.identity.getUserInfo(onUserInfoAvailable, + remoting.onGetIdentityInfoError); +}
diff --git a/remoting/webapp/crd/js/crd_main.js b/remoting/webapp/crd/js/crd_main.js new file mode 100644 index 0000000..e15020b8 --- /dev/null +++ b/remoting/webapp/crd/js/crd_main.js
@@ -0,0 +1,236 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +'use strict'; + +/** @suppress {duplicate} */ +var remoting = remoting || {}; + +/** + * Entry point ('load' handler) for Chromoting webapp. + */ +remoting.initChromoting = function() { + remoting.initGlobalObjects(); + remoting.initIdentity(); + remoting.initIdentityEmail(remoting.onEmailAvailable); + + remoting.initEventHandlers(); + + if (base.isAppsV2()) { + remoting.fullscreen = new remoting.FullscreenAppsV2(); + remoting.windowFrame = new remoting.WindowFrame( + document.getElementById('title-bar')); + remoting.optionsMenu = remoting.windowFrame.createOptionsMenu(); + } else { + remoting.fullscreen = new remoting.FullscreenAppsV1(); + remoting.toolbar = new remoting.Toolbar( + document.getElementById('session-toolbar')); + remoting.optionsMenu = remoting.toolbar.createOptionsMenu(); + } + + remoting.initHostlist_(); + + var homeFeedback = new remoting.MenuButton( + document.getElementById('help-feedback-main')); + var toolbarFeedback = new remoting.MenuButton( + document.getElementById('help-feedback-toolbar')); + remoting.manageHelpAndFeedback( + document.getElementById('title-bar')); + remoting.manageHelpAndFeedback( + document.getElementById('help-feedback-toolbar')); + remoting.manageHelpAndFeedback( + document.getElementById('help-feedback-main')); + + remoting.windowShape.updateClientWindowShape(); + + remoting.showOrHideIT2MeUi(); + remoting.showOrHideMe2MeUi(); + + // For Apps v1, check the tab type to warn the user if they are not getting + // the best keyboard experience. + if (!base.isAppsV2() && !remoting.platformIsMac()) { + /** @param {boolean} isWindowed */ + var onIsWindowed = function(isWindowed) { + if (!isWindowed) { + document.getElementById('startup-mode-box-me2me').hidden = false; + document.getElementById('startup-mode-box-it2me').hidden = false; + } + }; + isWindowed_(onIsWindowed); + } + + remoting.ClientPlugin.factory.preloadPlugin(); + +} + +/** + * Display the user's email address and allow access to the rest of the app, + * including parsing URL parameters. + * + * @param {string} email The user's email address. + * @return {void} Nothing. + */ +remoting.onEmailAvailable = function(email, fullName) { + document.getElementById('current-email').innerText = email; + document.getElementById('get-started-it2me').disabled = false; + document.getElementById('get-started-me2me').disabled = false; +}; + +/** + * Initialize the host list. + */ +remoting.initHostlist_ = function() { + remoting.hostList = new remoting.HostList( + document.getElementById('host-list'), + document.getElementById('host-list-empty'), + document.getElementById('host-list-error-message'), + document.getElementById('host-list-refresh-failed-button'), + document.getElementById('host-list-loading-indicator')); + + isHostModeSupported_().then( + /** @param {Boolean} supported */ + function(supported){ + if (supported) { + var noShare = document.getElementById('chrome-os-no-share'); + noShare.parentNode.removeChild(noShare); + } else { + var button = document.getElementById('share-button'); + button.disabled = true; + } + }); + + /** + * @return {Promise} A promise that resolves to the id of the current + * containing tab/window. + */ + var getCurrentId = function () { + if (base.isAppsV2()) { + return Promise.resolve(chrome.app.window.current().id); + } + + /** + * @param {function(*=):void} resolve + * @param {function(*=):void} reject + */ + return new Promise(function(resolve, reject) { + /** @param {chrome.Tab} tab */ + chrome.tabs.getCurrent(function(tab){ + if (tab) { + resolve(String(tab.id)); + } + reject('Cannot retrieve the current tab.'); + }); + }); + }; + + var onLoad = function() { + // Parse URL parameters. + var urlParams = getUrlParameters_(); + if ('mode' in urlParams) { + if (urlParams['mode'] === 'me2me') { + var hostId = urlParams['hostId']; + remoting.connectMe2Me(hostId); + return; + } else if (urlParams['mode'] === 'hangout') { + /** @param {*} id */ + getCurrentId().then(function(id) { + /** @type {string} */ + var accessCode = urlParams['accessCode']; + remoting.ensureSessionConnector_(); + remoting.setMode(remoting.AppMode.CLIENT_CONNECTING); + remoting.connector.connectIT2Me(accessCode); + + document.body.classList.add('hangout-remote-desktop'); + var senderId = /** @type {string} */ String(id); + var hangoutSession = new remoting.HangoutSession(senderId); + hangoutSession.init(); + }); + return; + } + } + // No valid URL parameters, start up normally. + remoting.initHomeScreenUi(); + } + remoting.hostList.load(onLoad); +} + +/** + * initHomeScreenUi is called if the app is not starting up in session mode, + * and also if the user cancels pin entry or the connection in session mode. + */ +remoting.initHomeScreenUi = function() { + remoting.hostController = new remoting.HostController(); + remoting.setMode(remoting.AppMode.HOME); + remoting.hostSetupDialog = + new remoting.HostSetupDialog(remoting.hostController); + var dialog = document.getElementById('paired-clients-list'); + var message = document.getElementById('paired-client-manager-message'); + var deleteAll = document.getElementById('delete-all-paired-clients'); + var close = document.getElementById('close-paired-client-manager-dialog'); + var working = document.getElementById('paired-client-manager-dialog-working'); + var error = document.getElementById('paired-client-manager-dialog-error'); + var noPairedClients = document.getElementById('no-paired-clients'); + remoting.pairedClientManager = + new remoting.PairedClientManager(remoting.hostController, dialog, message, + deleteAll, close, noPairedClients, + working, error); + // Display the cached host list, then asynchronously update and re-display it. + remoting.updateLocalHostState(); + remoting.hostList.refresh(remoting.updateLocalHostState); + remoting.butterBar = new remoting.ButterBar(); +}; + +/** + * Fetches local host state and updates the DOM accordingly. + */ +remoting.updateLocalHostState = function() { + /** + * @param {remoting.HostController.State} state Host state. + */ + var onHostState = function(state) { + if (state == remoting.HostController.State.STARTED) { + remoting.hostController.getLocalHostId(onHostId.bind(null, state)); + } else { + onHostId(state, null); + } + }; + + /** + * @param {remoting.HostController.State} state Host state. + * @param {string?} hostId Host id. + */ + var onHostId = function(state, hostId) { + remoting.hostList.setLocalHostStateAndId(state, hostId); + remoting.hostList.display(); + }; + + /** + * @param {boolean} response True if the feature is present. + */ + var onHasFeatureResponse = function(response) { + /** + * @param {remoting.Error} error + */ + var onError = function(error) { + console.error('Failed to get pairing status: ' + error); + remoting.pairedClientManager.setPairedClients([]); + }; + + if (response) { + remoting.hostController.getPairedClients( + remoting.pairedClientManager.setPairedClients.bind( + remoting.pairedClientManager), + onError); + } else { + console.log('Pairing registry not supported by host.'); + remoting.pairedClientManager.setPairedClients([]); + } + }; + + remoting.hostController.hasFeature( + remoting.HostController.Feature.PAIRING_REGISTRY, onHasFeatureResponse); + remoting.hostController.getLocalHostState(onHostState); +}; + +window.addEventListener('load', remoting.initChromoting, false);
diff --git a/remoting/webapp/crd/js/event_handlers.js b/remoting/webapp/crd/js/event_handlers.js index 91040b4..4348e13 100644 --- a/remoting/webapp/crd/js/event_handlers.js +++ b/remoting/webapp/crd/js/event_handlers.js
@@ -7,7 +7,7 @@ /** @suppress {duplicate} */ var remoting = remoting || {}; -function onLoad() { +remoting.initEventHandlers = function() { var goHome = function() { remoting.setMode(remoting.AppMode.HOME); }; @@ -115,7 +115,6 @@ registerEventListeners(me2me_actions); registerEventListeners(host_actions); registerEventListeners(auth_actions); - remoting.init(); window.addEventListener('resize', remoting.onResize, false); // When a window goes full-screen, a resize event is triggered, but the @@ -157,5 +156,3 @@ ': element not found.'); } } - -window.addEventListener('load', onLoad, false);
diff --git a/remoting/webapp/crd/js/remoting.js b/remoting/webapp/crd/js/remoting.js index c2bedd1..01044a40 100644 --- a/remoting/webapp/crd/js/remoting.js +++ b/remoting/webapp/crd/js/remoting.js
@@ -17,39 +17,9 @@ remoting.testEvents; /** - * Show the authorization consent UI and register a one-shot event handler to - * continue the authorization process. - * - * @param {function():void} authContinue Callback to invoke when the user - * clicks "Continue". + * Initialization tasks that are common to all remoting apps. */ -function consentRequired_(authContinue) { - /** @type {HTMLElement} */ - var dialog = document.getElementById('auth-dialog'); - /** @type {HTMLElement} */ - var button = document.getElementById('auth-button'); - var consentGranted = function(event) { - dialog.hidden = true; - button.removeEventListener('click', consentGranted, false); - authContinue(); - remoting.windowShape.updateClientWindowShape(); - }; - dialog.hidden = false; - - /** @type {HTMLElement} */ - var dialog_border = document.getElementById('auth-dialog-border'); - // TODO(garykac): Refactor to remove auth dialog from the main html file - // and place in a separate window. - remoting.authDialog = new remoting.AuthDialog(dialog_border); - remoting.windowShape.addCallback(remoting.authDialog); - - button.addEventListener('click', consentGranted, false); -} - -/** - * Entry point for app initialization. - */ -remoting.init = function() { +remoting.initGlobalObjects = function() { if (base.isAppsV2()) { var htmlNode = /** @type {HTMLElement} */ (document.body.parentNode); htmlNode.classList.add('apps-v2'); @@ -65,61 +35,21 @@ remoting.SessionConnector.factory = new remoting.DefaultSessionConnectorFactory(); remoting.settings = new remoting.Settings(); + if (base.isAppsV2()) { - remoting.identity = new remoting.Identity(consentRequired_); remoting.fullscreen = new remoting.FullscreenAppsV2(); - remoting.windowFrame = new remoting.WindowFrame( - document.getElementById('title-bar')); - remoting.optionsMenu = remoting.windowFrame.createOptionsMenu(); } else { - remoting.oauth2 = new remoting.OAuth2(); - if (!remoting.oauth2.isAuthenticated()) { - document.getElementById('auth-dialog').hidden = false; - } - remoting.identity = remoting.oauth2; remoting.fullscreen = new remoting.FullscreenAppsV1(); - remoting.toolbar = new remoting.Toolbar( - document.getElementById('session-toolbar')); - remoting.optionsMenu = remoting.toolbar.createOptionsMenu(); } + remoting.stats = new remoting.ConnectionStats( document.getElementById('statistics')); remoting.formatIq = new remoting.FormatIq(); - remoting.hostList = new remoting.HostList( - document.getElementById('host-list'), - document.getElementById('host-list-empty'), - document.getElementById('host-list-error-message'), - document.getElementById('host-list-refresh-failed-button'), - document.getElementById('host-list-loading-indicator')); + remoting.clipboard = new remoting.Clipboard(); var sandbox = /** @type {HTMLIFrameElement} */ document.getElementById('wcs-sandbox'); remoting.wcsSandbox = new remoting.WcsSandboxContainer(sandbox.contentWindow); - var homeFeedback = new remoting.MenuButton( - document.getElementById('help-feedback-main')); - var toolbarFeedback = new remoting.MenuButton( - document.getElementById('help-feedback-toolbar')); - remoting.manageHelpAndFeedback( - document.getElementById('title-bar')); - remoting.manageHelpAndFeedback( - document.getElementById('help-feedback-toolbar')); - remoting.manageHelpAndFeedback( - document.getElementById('help-feedback-main')); - - /** @param {remoting.Error} error */ - var onGetEmailError = function(error) { - // No need to show the error message for NOT_AUTHENTICATED - // because we will show "auth-dialog". - if (error != remoting.Error.NOT_AUTHENTICATED) { - remoting.showErrorMessage(error); - } - } - remoting.identity.getEmail(remoting.onEmail, onGetEmailError); - - remoting.windowShape.updateClientWindowShape(); - - remoting.showOrHideIT2MeUi(); - remoting.showOrHideMe2MeUi(); // The plugin's onFocus handler sends a paste command to |window|, because // it can't send one to the plugin element itself. @@ -128,95 +58,13 @@ remoting.initModalDialogs(); - isHostModeSupported_().then( - /** @param {Boolean} supported */ - function(supported){ - if (supported) { - var noShare = document.getElementById('chrome-os-no-share'); - noShare.parentNode.removeChild(noShare); - } else { - var button = document.getElementById('share-button'); - button.disabled = true; - } - }); - - /** - * @return {Promise} A promise that resolves to the id of the current - * containing tab/window. - */ - var getCurrentId = function () { - if (base.isAppsV2()) { - return Promise.resolve(chrome.app.window.current().id); - } - - /** - * @param {function(*=):void} resolve - * @param {function(*=):void} reject - */ - return new Promise(function(resolve, reject) { - /** @param {chrome.Tab} tab */ - chrome.tabs.getCurrent(function(tab){ - if (tab) { - resolve(String(tab.id)); - } - reject('Cannot retrieve the current tab.'); - }); - }); - }; - - var onLoad = function() { - // Parse URL parameters. - var urlParams = getUrlParameters_(); - if ('mode' in urlParams) { - if (urlParams['mode'] === 'me2me') { - var hostId = urlParams['hostId']; - remoting.connectMe2Me(hostId); - return; - } else if (urlParams['mode'] === 'hangout') { - /** @param {*} id */ - getCurrentId().then(function(id) { - /** @type {string} */ - var accessCode = urlParams['accessCode']; - remoting.ensureSessionConnector_(); - remoting.setMode(remoting.AppMode.CLIENT_CONNECTING); - remoting.connector.connectIT2Me(accessCode); - - document.body.classList.add('hangout-remote-desktop'); - var senderId = /** @type {string} */ String(id); - var hangoutSession = new remoting.HangoutSession(senderId); - hangoutSession.init(); - }); - return; - } - } - // No valid URL parameters, start up normally. - remoting.initHomeScreenUi(); - } - remoting.hostList.load(onLoad); - - // For Apps v1, check the tab type to warn the user if they are not getting - // the best keyboard experience. - if (!base.isAppsV2() && !remoting.platformIsMac()) { - /** @param {boolean} isWindowed */ - var onIsWindowed = function(isWindowed) { - if (!isWindowed) { - document.getElementById('startup-mode-box-me2me').hidden = false; - document.getElementById('startup-mode-box-it2me').hidden = false; - } - }; - isWindowed_(onIsWindowed); - } - remoting.testEvents = new base.EventSource(); - /** @enum {string} */ remoting.testEvents.Names = { uiModeChanged: 'uiModeChanged' }; remoting.testEvents.defineEvents(base.values(remoting.testEvents.Names)); - - remoting.ClientPlugin.factory.preloadPlugin(); -}; +} /** * Returns true if the current platform is fully supported. It's only used when @@ -236,97 +84,6 @@ } /** - * Display the user's email address and allow access to the rest of the app, - * including parsing URL parameters. - * - * @param {string} email The user's email address. - * @return {void} Nothing. - */ -remoting.onEmail = function(email) { - document.getElementById('current-email').innerText = email; - document.getElementById('get-started-it2me').disabled = false; - document.getElementById('get-started-me2me').disabled = false; -}; - -/** - * initHomeScreenUi is called if the app is not starting up in session mode, - * and also if the user cancels pin entry or the connection in session mode. - */ -remoting.initHomeScreenUi = function() { - remoting.hostController = new remoting.HostController(); - remoting.setMode(remoting.AppMode.HOME); - remoting.hostSetupDialog = - new remoting.HostSetupDialog(remoting.hostController); - var dialog = document.getElementById('paired-clients-list'); - var message = document.getElementById('paired-client-manager-message'); - var deleteAll = document.getElementById('delete-all-paired-clients'); - var close = document.getElementById('close-paired-client-manager-dialog'); - var working = document.getElementById('paired-client-manager-dialog-working'); - var error = document.getElementById('paired-client-manager-dialog-error'); - var noPairedClients = document.getElementById('no-paired-clients'); - remoting.pairedClientManager = - new remoting.PairedClientManager(remoting.hostController, dialog, message, - deleteAll, close, noPairedClients, - working, error); - // Display the cached host list, then asynchronously update and re-display it. - remoting.updateLocalHostState(); - remoting.hostList.refresh(remoting.updateLocalHostState); - remoting.butterBar = new remoting.ButterBar(); -}; - -/** - * Fetches local host state and updates the DOM accordingly. - */ -remoting.updateLocalHostState = function() { - /** - * @param {remoting.HostController.State} state Host state. - */ - var onHostState = function(state) { - if (state == remoting.HostController.State.STARTED) { - remoting.hostController.getLocalHostId(onHostId.bind(null, state)); - } else { - onHostId(state, null); - } - }; - - /** - * @param {remoting.HostController.State} state Host state. - * @param {string?} hostId Host id. - */ - var onHostId = function(state, hostId) { - remoting.hostList.setLocalHostStateAndId(state, hostId); - remoting.hostList.display(); - }; - - /** - * @param {boolean} response True if the feature is present. - */ - var onHasFeatureResponse = function(response) { - /** - * @param {remoting.Error} error - */ - var onError = function(error) { - console.error('Failed to get pairing status: ' + error); - remoting.pairedClientManager.setPairedClients([]); - }; - - if (response) { - remoting.hostController.getPairedClients( - remoting.pairedClientManager.setPairedClients.bind( - remoting.pairedClientManager), - onError); - } else { - console.log('Pairing registry not supported by host.'); - remoting.pairedClientManager.setPairedClients([]); - } - }; - - remoting.hostController.hasFeature( - remoting.HostController.Feature.PAIRING_REGISTRY, onHasFeatureResponse); - remoting.hostController.getLocalHostState(onHostState); -}; - -/** * @return {string} Information about the current extension. */ remoting.getExtensionInfo = function() {
diff --git a/sandbox/linux/seccomp-bpf/codegen.cc b/sandbox/linux/seccomp-bpf/codegen.cc index 3ed06cb..df967601 100644 --- a/sandbox/linux/seccomp-bpf/codegen.cc +++ b/sandbox/linux/seccomp-bpf/codegen.cc
@@ -49,7 +49,7 @@ const CodeGen::Node CodeGen::kNullNode; -CodeGen::CodeGen() : program_(), memos_() { +CodeGen::CodeGen() : program_(), equivalent_(), memos_() { } CodeGen::~CodeGen() { @@ -81,11 +81,11 @@ if (BPF_CLASS(code) == BPF_JMP) { CHECK_NE(BPF_JA, BPF_OP(code)) << "CodeGen inserts JAs as needed"; - // We need to check |jt| twice because it might get pushed - // out-of-range by appending a jump for |jf|. - jt = WithinRange(jt, kBranchRange); + // Optimally adding jumps is rather tricky, so we use a quick + // approximation: by artificially reducing |jt|'s range, |jt| will + // stay within its true range even if we add a jump for |jf|. + jt = WithinRange(jt, kBranchRange - 1); jf = WithinRange(jf, kBranchRange); - jt = WithinRange(jt, kBranchRange); return Append(code, k, Offset(jt), Offset(jf)); } @@ -97,24 +97,26 @@ // proceeds to the next instruction; so we need to arrange for // that to be |jt|. jt = WithinRange(jt, 0); + CHECK_EQ(0U, Offset(jt)) << "ICE: Failed to setup next instruction"; } return Append(code, k, 0, 0); } CodeGen::Node CodeGen::WithinRange(Node target, size_t range) { - if (Offset(target) > range) { - // TODO(mdempsky): If |range > 0|, we might be able to reuse an - // existing instruction within that range. - - // TODO(mdempsky): If |target| is a branch or return, it might be - // possible to duplicate that instruction rather than jump to it. - - // Fall back to emitting a jump instruction. - target = Append(BPF_JMP | BPF_JA, Offset(target), 0, 0); + // Just use |target| if it's already within range. + if (Offset(target) <= range) { + return target; } - CHECK_LE(Offset(target), range) << "ICE: Failed to bring target within range"; - return target; + // Alternatively, look for an equivalent instruction within range. + if (Offset(equivalent_.at(target)) <= range) { + return equivalent_.at(target); + } + + // Otherwise, fall back to emitting a jump instruction. + Node jump = Append(BPF_JMP | BPF_JA, Offset(target), 0, 0); + equivalent_.at(target) = jump; + return jump; } CodeGen::Node CodeGen::Append(uint16_t code, uint32_t k, size_t jt, size_t jf) { @@ -127,8 +129,12 @@ } CHECK_LT(program_.size(), static_cast<size_t>(BPF_MAXINSNS)); + CHECK_EQ(program_.size(), equivalent_.size()); + + Node res = program_.size(); program_.push_back(sock_filter{code, jt, jf, k}); - return program_.size() - 1; + equivalent_.push_back(res); + return res; } size_t CodeGen::Offset(Node target) const {
diff --git a/sandbox/linux/seccomp-bpf/codegen.h b/sandbox/linux/seccomp-bpf/codegen.h index bca40469..e67966471 100644 --- a/sandbox/linux/seccomp-bpf/codegen.h +++ b/sandbox/linux/seccomp-bpf/codegen.h
@@ -106,6 +106,13 @@ // indices remain stable as we add instructions. Program program_; + // equivalent_ stores the most recent semantically-equivalent node for each + // instruction in program_. A node is defined as semantically-equivalent to N + // if it has the same instruction code and constant as N and its successor + // nodes (if any) are semantically-equivalent to N's successor nodes, or + // if it's an unconditional jump to a node semantically-equivalent to N. + std::vector<Node> equivalent_; + std::map<MemoKey, Node, MemoKeyLess> memos_; DISALLOW_COPY_AND_ASSIGN(CodeGen);
diff --git a/sandbox/linux/seccomp-bpf/codegen_unittest.cc b/sandbox/linux/seccomp-bpf/codegen_unittest.cc index a001668b..8d4bf5d 100644 --- a/sandbox/linux/seccomp-bpf/codegen_unittest.cc +++ b/sandbox/linux/seccomp-bpf/codegen_unittest.cc
@@ -367,5 +367,37 @@ } } +TEST_F(ProgramTest, JumpReuse) { + // As a code size optimization, we try to reuse jumps when possible + // instead of emitting new ones. Here we make sure that optimization + // is working as intended. + // + // NOTE: To simplify testing, we rely on implementation details + // about what CodeGen::Node values indicate (i.e., vector indices), + // but CodeGen users should treat them as opaque values. + + // Populate with 260 initial instruction nodes. + std::vector<CodeGen::Node> nodes; + nodes.push_back(MakeInstruction(BPF_RET + BPF_K, 0)); + for (size_t i = 1; i < 260; ++i) { + nodes.push_back( + MakeInstruction(BPF_ALU + BPF_ADD + BPF_K, i, nodes.back())); + } + + // Branching to nodes[0] and nodes[1] should require 3 new + // instructions: two far jumps plus the branch itself. + CodeGen::Node one = + MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 0, nodes[0], nodes[1]); + EXPECT_EQ(nodes.back() + 3, one); // XXX: Implementation detail! + RunTest(one); + + // Branching again to the same target nodes should require only one + // new instruction, as we can reuse the previous branch's jumps. + CodeGen::Node two = + MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, nodes[0], nodes[1]); + EXPECT_EQ(one + 1, two); // XXX: Implementation detail! + RunTest(two); +} + } // namespace } // namespace sandbox
diff --git a/sandbox/linux/syscall_broker/broker_file_permission_unittest.cc b/sandbox/linux/syscall_broker/broker_file_permission_unittest.cc index 4fcea8e..28530214 100644 --- a/sandbox/linux/syscall_broker/broker_file_permission_unittest.cc +++ b/sandbox/linux/syscall_broker/broker_file_permission_unittest.cc
@@ -46,8 +46,6 @@ BrokerFilePermission perm = BrokerFilePermission::ReadOnlyRecursive(kPath); } -#if !defined(OS_CHROMEOS) -// These tests failed on ChromeOS. See crbug.com/437312 SANDBOX_DEATH_TEST( BrokerFilePermission, CreateBad, @@ -79,7 +77,6 @@ const char kPath[] = ""; BrokerFilePermission perm = BrokerFilePermission::ReadOnly(kPath); } -#endif // CheckPerm tests |path| against |perm| given |access_flags|. // If |create| is true then file creation is tested for success.
diff --git a/sandbox/linux/tests/unit_tests.cc b/sandbox/linux/tests/unit_tests.cc index b7c3af67..5872e940 100644 --- a/sandbox/linux/tests/unit_tests.cc +++ b/sandbox/linux/tests/unit_tests.cc
@@ -263,6 +263,16 @@ bool subprocess_exited_without_matching_message = msg.find(expected_msg) == std::string::npos; + +// In official builds CHECK messages are dropped, so look for SIGABRT. +// See https://code.google.com/p/chromium/issues/detail?id=437312 +#if defined(OFFICIAL_BUILD) && defined(NDEBUG) && !defined(OS_ANDROID) + if (subprocess_exited_without_matching_message) { + static const char kSigAbortMessage[] = "Received signal 6"; + subprocess_exited_without_matching_message = + msg.find(kSigAbortMessage) == std::string::npos; + } +#endif EXPECT_FALSE(subprocess_exited_without_matching_message) << details; }
diff --git a/skia/ext/analysis_canvas.cc b/skia/ext/analysis_canvas.cc index ca19170..48a09d1 100644 --- a/skia/ext/analysis_canvas.cc +++ b/skia/ext/analysis_canvas.cc
@@ -15,6 +15,23 @@ const int kNoLayer = -1; +bool ActsLikeClear(SkXfermode::Mode mode, unsigned src_alpha) { + switch (mode) { + case SkXfermode::kClear_Mode: + return true; + case SkXfermode::kSrc_Mode: + case SkXfermode::kSrcIn_Mode: + case SkXfermode::kDstIn_Mode: + case SkXfermode::kSrcOut_Mode: + case SkXfermode::kDstATop_Mode: + return src_alpha == 0; + case SkXfermode::kDstOut_Mode: + return src_alpha == 0xFF; + default: + return false; + } +} + bool IsSolidColorPaint(const SkPaint& paint) { SkXfermode::Mode xfermode; @@ -90,14 +107,9 @@ } void AnalysisCanvas::drawPaint(const SkPaint& paint) { - // This check is in SkCanvas::drawPaint(), and some of our unittests rely on - // on this, so we reproduce it here. - if (isClipEmpty()) - return; - - is_solid_color_ = false; - is_transparent_ = false; - ++draw_op_count_; + SkRect rect; + getClipBounds(&rect); + drawRect(rect, paint); } void AnalysisCanvas::drawPoints(SkCanvas::PointMode mode, @@ -137,7 +149,7 @@ // In all other cases, we keep the current transparent value if (does_cover_canvas && !is_forced_not_transparent_ && - xfermode == SkXfermode::kClear_Mode) { + ActsLikeClear(xfermode, paint.getAlpha())) { is_transparent_ = true; } else if (paint.getAlpha() != 0 || xfermode != SkXfermode::kSrc_Mode) { is_transparent_ = false;
diff --git a/skia/ext/analysis_canvas_unittest.cc b/skia/ext/analysis_canvas_unittest.cc index 378d27d..16a0390 100644 --- a/skia/ext/analysis_canvas_unittest.cc +++ b/skia/ext/analysis_canvas_unittest.cc
@@ -78,8 +78,7 @@ canvas.drawPaint(paint); SkColor outputColor; - //TODO(vmpstr): This should return true. (crbug.com/180597) - EXPECT_FALSE(canvas.GetColorIfSolid(&outputColor)); + EXPECT_TRUE(canvas.GetColorIfSolid(&outputColor)); // Draw points test. SkPoint points[4] = {
diff --git a/skia/ext/pixel_ref_utils_unittest.cc b/skia/ext/pixel_ref_utils_unittest.cc index 656ef5c..08e5d3e 100644 --- a/skia/ext/pixel_ref_utils_unittest.cc +++ b/skia/ext/pixel_ref_utils_unittest.cc
@@ -53,11 +53,9 @@ SkBitmap bitmap_; }; -#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING SkFlattenable* TestDiscardableShader::CreateProc(SkReadBuffer&) { return new TestDiscardableShader; } -#endif void CreateBitmap(gfx::Size size, const char* uri, SkBitmap* bitmap) { bitmap->allocN32Pixels(size.width(), size.height());
diff --git a/sync/internal_api/attachments/attachment_store_test_template.h b/sync/internal_api/attachments/attachment_store_test_template.h index cd1c016..b47f07ec 100644 --- a/sync/internal_api/attachments/attachment_store_test_template.h +++ b/sync/internal_api/attachments/attachment_store_test_template.h
@@ -16,6 +16,7 @@ #include "sync/api/attachments/attachment.h" #include "sync/internal_api/public/attachments/attachment_util.h" #include "sync/protocol/sync.pb.h" +#include "testing/gmock/include/gmock/gmock-matchers.h" #include "testing/gtest/include/gtest/gtest.h" // AttachmentStoreTest defines tests for AttachmentStore. To instantiate these @@ -50,17 +51,19 @@ AttachmentStore::Result result; scoped_ptr<AttachmentMap> attachments; scoped_ptr<AttachmentIdList> failed_attachment_ids; + scoped_ptr<AttachmentMetadataList> attachment_metadata; AttachmentStore::ReadCallback read_callback; AttachmentStore::WriteCallback write_callback; AttachmentStore::DropCallback drop_callback; + AttachmentStore::ReadMetadataCallback read_metadata_callback; scoped_refptr<base::RefCountedString> some_data1; scoped_refptr<base::RefCountedString> some_data2; AttachmentStoreTest() {} - virtual void SetUp() { + void SetUp() override { store = attachment_store_factory.CreateAttachmentStore(); Clear(); @@ -72,6 +75,9 @@ write_callback = base::Bind( &AttachmentStoreTest::CopyResult, base::Unretained(this), &result); drop_callback = write_callback; + read_metadata_callback = + base::Bind(&AttachmentStoreTest::CopyResultMetadata, + base::Unretained(this), &result, &attachment_metadata); some_data1 = new base::RefCountedString; some_data1->data() = kTestData1; @@ -80,7 +86,7 @@ some_data2->data() = kTestData2; } - virtual void ClearAndPumpLoop() { + void ClearAndPumpLoop() { Clear(); message_loop.RunUntilIdle(); } @@ -90,6 +96,7 @@ result = AttachmentStore::UNSPECIFIED_ERROR; attachments.reset(); failed_attachment_ids.reset(); + attachment_metadata.reset(); } void CopyResult(AttachmentStore::Result* destination_result, @@ -108,6 +115,15 @@ *destination_attachments = source_attachments.Pass(); *destination_failed_attachment_ids = source_failed_attachment_ids.Pass(); } + + void CopyResultMetadata( + AttachmentStore::Result* destination_result, + scoped_ptr<AttachmentMetadataList>* destination_metadata, + const AttachmentStore::Result& source_result, + scoped_ptr<AttachmentMetadataList> source_metadata) { + CopyResult(destination_result, source_result); + *destination_metadata = source_metadata.Pass(); + } }; TYPED_TEST_CASE_P(AttachmentStoreTest); @@ -126,23 +142,23 @@ some_attachments.push_back(attachment1); this->store->Write(some_attachments, this->write_callback); this->ClearAndPumpLoop(); - EXPECT_EQ(this->result, AttachmentStore::SUCCESS); + EXPECT_EQ(AttachmentStore::SUCCESS, this->result); // Write the second one. some_attachments.clear(); some_attachments.push_back(attachment2); this->store->Write(some_attachments, this->write_callback); this->ClearAndPumpLoop(); - EXPECT_EQ(this->result, AttachmentStore::SUCCESS); + EXPECT_EQ(AttachmentStore::SUCCESS, this->result); // Read it back and see that it was not overwritten. AttachmentIdList some_attachment_ids; some_attachment_ids.push_back(attachment1.GetId()); this->store->Read(some_attachment_ids, this->read_callback); this->ClearAndPumpLoop(); - EXPECT_EQ(this->result, AttachmentStore::SUCCESS); - EXPECT_EQ(this->attachments->size(), 1U); - EXPECT_EQ(this->failed_attachment_ids->size(), 0U); + EXPECT_EQ(AttachmentStore::SUCCESS, this->result); + EXPECT_EQ(1U, this->attachments->size()); + EXPECT_EQ(0U, this->failed_attachment_ids->size()); AttachmentMap::const_iterator a1 = this->attachments->find(attachment1.GetId()); EXPECT_TRUE(a1 != this->attachments->end()); @@ -159,16 +175,16 @@ this->store->Write(some_attachments, this->write_callback); this->ClearAndPumpLoop(); - EXPECT_EQ(this->result, AttachmentStore::SUCCESS); + EXPECT_EQ(AttachmentStore::SUCCESS, this->result); AttachmentIdList some_attachment_ids; some_attachment_ids.push_back(attachment1.GetId()); some_attachment_ids.push_back(attachment2.GetId()); this->store->Read(some_attachment_ids, this->read_callback); this->ClearAndPumpLoop(); - EXPECT_EQ(this->result, AttachmentStore::SUCCESS); - EXPECT_EQ(this->attachments->size(), 2U); - EXPECT_EQ(this->failed_attachment_ids->size(), 0U); + EXPECT_EQ(AttachmentStore::SUCCESS, this->result); + EXPECT_EQ(2U, this->attachments->size()); + EXPECT_EQ(0U, this->failed_attachment_ids->size()); AttachmentMap::const_iterator a1 = this->attachments->find(attachment1.GetId()); @@ -191,7 +207,7 @@ some_attachments.push_back(attachment1); this->store->Write(some_attachments, this->write_callback); this->ClearAndPumpLoop(); - EXPECT_EQ(this->result, AttachmentStore::SUCCESS); + EXPECT_EQ(AttachmentStore::SUCCESS, this->result); // Try to read both attachment1 and attachment2. AttachmentIdList ids; @@ -201,9 +217,9 @@ this->ClearAndPumpLoop(); // See that only attachment1 was read. - EXPECT_EQ(this->result, AttachmentStore::UNSPECIFIED_ERROR); - EXPECT_EQ(this->attachments->size(), 1U); - EXPECT_EQ(this->failed_attachment_ids->size(), 1U); + EXPECT_EQ(AttachmentStore::UNSPECIFIED_ERROR, this->result); + EXPECT_EQ(1U, this->attachments->size()); + EXPECT_EQ(1U, this->failed_attachment_ids->size()); } // Try to drop two attachments when only one exists. Verify that no error occurs @@ -217,22 +233,22 @@ some_attachments.push_back(attachment2); this->store->Write(some_attachments, this->write_callback); this->ClearAndPumpLoop(); - EXPECT_EQ(this->result, AttachmentStore::SUCCESS); + EXPECT_EQ(AttachmentStore::SUCCESS, this->result); // Drop attachment1 only. AttachmentIdList ids; ids.push_back(attachment1.GetId()); this->store->Drop(ids, this->drop_callback); this->ClearAndPumpLoop(); - EXPECT_EQ(this->result, AttachmentStore::SUCCESS); + EXPECT_EQ(AttachmentStore::SUCCESS, this->result); // See that attachment1 is gone. this->store->Read(ids, this->read_callback); this->ClearAndPumpLoop(); - EXPECT_EQ(this->result, AttachmentStore::UNSPECIFIED_ERROR); - EXPECT_EQ(this->attachments->size(), 0U); - EXPECT_EQ(this->failed_attachment_ids->size(), 1U); - EXPECT_EQ((*this->failed_attachment_ids)[0], attachment1.GetId()); + EXPECT_EQ(AttachmentStore::UNSPECIFIED_ERROR, this->result); + EXPECT_EQ(0U, this->attachments->size()); + EXPECT_EQ(1U, this->failed_attachment_ids->size()); + EXPECT_EQ(attachment1.GetId(), (*this->failed_attachment_ids)[0]); // Drop both attachment1 and attachment2. ids.clear(); @@ -240,17 +256,17 @@ ids.push_back(attachment2.GetId()); this->store->Drop(ids, this->drop_callback); this->ClearAndPumpLoop(); - EXPECT_EQ(this->result, AttachmentStore::SUCCESS); + EXPECT_EQ(AttachmentStore::SUCCESS, this->result); // See that attachment2 is now gone. ids.clear(); ids.push_back(attachment2.GetId()); this->store->Read(ids, this->read_callback); this->ClearAndPumpLoop(); - EXPECT_EQ(this->result, AttachmentStore::UNSPECIFIED_ERROR); - EXPECT_EQ(this->attachments->size(), 0U); - EXPECT_EQ(this->failed_attachment_ids->size(), 1U); - EXPECT_EQ((*this->failed_attachment_ids)[0], attachment2.GetId()); + EXPECT_EQ(AttachmentStore::UNSPECIFIED_ERROR, this->result); + EXPECT_EQ(0U, this->attachments->size()); + EXPECT_EQ(1U, this->failed_attachment_ids->size()); + EXPECT_EQ(attachment2.GetId(), (*this->failed_attachment_ids)[0]); } // Verify that attempting to drop an attachment that does not exist is not an @@ -261,29 +277,113 @@ some_attachments.push_back(attachment1); this->store->Write(some_attachments, this->write_callback); this->ClearAndPumpLoop(); - EXPECT_EQ(this->result, AttachmentStore::SUCCESS); + EXPECT_EQ(AttachmentStore::SUCCESS, this->result); // Drop the attachment. AttachmentIdList ids; ids.push_back(attachment1.GetId()); this->store->Drop(ids, this->drop_callback); this->ClearAndPumpLoop(); - EXPECT_EQ(this->result, AttachmentStore::SUCCESS); + EXPECT_EQ(AttachmentStore::SUCCESS, this->result); // See that it's gone. this->store->Read(ids, this->read_callback); this->ClearAndPumpLoop(); - EXPECT_EQ(this->result, AttachmentStore::UNSPECIFIED_ERROR); - EXPECT_EQ(this->attachments->size(), 0U); - EXPECT_EQ(this->failed_attachment_ids->size(), 1U); - EXPECT_EQ((*this->failed_attachment_ids)[0], attachment1.GetId()); + EXPECT_EQ(AttachmentStore::UNSPECIFIED_ERROR, this->result); + EXPECT_EQ(0U, this->attachments->size()); + EXPECT_EQ(1U, this->failed_attachment_ids->size()); + EXPECT_EQ(attachment1.GetId(), (*this->failed_attachment_ids)[0]); // Drop again, see that no error occurs. ids.clear(); ids.push_back(attachment1.GetId()); this->store->Drop(ids, this->drop_callback); this->ClearAndPumpLoop(); - EXPECT_EQ(this->result, AttachmentStore::SUCCESS); + EXPECT_EQ(AttachmentStore::SUCCESS, this->result); +} + +// Verify getting metadata for specific attachments. +TYPED_TEST_P(AttachmentStoreTest, ReadMetadata) { + Attachment attachment1 = Attachment::Create(this->some_data1); + Attachment attachment2 = Attachment::Create(this->some_data2); + + AttachmentList some_attachments; + // Write attachment1 only. + some_attachments.push_back(attachment1); + this->store->Write(some_attachments, this->write_callback); + this->ClearAndPumpLoop(); + EXPECT_EQ(AttachmentStore::SUCCESS, this->result); + + // Try to read metadata for both attachment1 and attachment2. + AttachmentIdList ids; + ids.push_back(attachment1.GetId()); + ids.push_back(attachment2.GetId()); + this->store->ReadMetadata(ids, this->read_metadata_callback); + this->ClearAndPumpLoop(); + + // See that only one entry was read. + EXPECT_EQ(AttachmentStore::UNSPECIFIED_ERROR, this->result); + EXPECT_EQ(1U, this->attachment_metadata->size()); + + // Now write attachment2. + some_attachments[0] = attachment2; + this->store->Write(some_attachments, this->write_callback); + this->ClearAndPumpLoop(); + EXPECT_EQ(AttachmentStore::SUCCESS, this->result); + + // Try to read metadata for both attachment1 and attachment2 again. + this->store->ReadMetadata(ids, this->read_metadata_callback); + this->ClearAndPumpLoop(); + EXPECT_EQ(AttachmentStore::SUCCESS, this->result); + EXPECT_EQ(2U, this->attachment_metadata->size()); + + // Verify that we've got both entries back in the right order. + AttachmentMetadataList::const_iterator iter = + this->attachment_metadata->begin(); + EXPECT_EQ(attachment1.GetId(), iter->GetId()); + ++iter; + EXPECT_EQ(attachment2.GetId(), iter->GetId()); +} + +// Verify getting metadata for all attachments. +TYPED_TEST_P(AttachmentStoreTest, ReadAllMetadata) { + // Try to read all metadata from an empty store. + this->store->ReadAllMetadata(this->read_metadata_callback); + this->ClearAndPumpLoop(); + EXPECT_EQ(AttachmentStore::SUCCESS, this->result); + EXPECT_EQ(0U, this->attachment_metadata->size()); + + // Create and write two attachments. + Attachment attachment1 = Attachment::Create(this->some_data1); + Attachment attachment2 = Attachment::Create(this->some_data2); + + AttachmentList some_attachments; + some_attachments.push_back(attachment1); + some_attachments.push_back(attachment2); + this->store->Write(some_attachments, this->write_callback); + this->ClearAndPumpLoop(); + EXPECT_EQ(AttachmentStore::SUCCESS, this->result); + + // Read all metadata again. + this->store->ReadAllMetadata(this->read_metadata_callback); + this->ClearAndPumpLoop(); + EXPECT_EQ(AttachmentStore::SUCCESS, this->result); + EXPECT_EQ(2U, this->attachment_metadata->size()); + + // Verify that we get all attachments back (the order is undefined). + AttachmentIdSet ids; + ids.insert(attachment1.GetId()); + ids.insert(attachment2.GetId()); + + AttachmentMetadataList::const_iterator iter = + this->attachment_metadata->begin(); + const AttachmentMetadataList::const_iterator end = + this->attachment_metadata->end(); + for (; iter != end; ++iter) { + EXPECT_THAT(ids, testing::Contains(iter->GetId())); + ids.erase(iter->GetId()); + } + EXPECT_TRUE(ids.empty()); } REGISTER_TYPED_TEST_CASE_P(AttachmentStoreTest, @@ -291,7 +391,9 @@ Write_RoundTrip, Read_OneNotFound, Drop_DropTwoButOnlyOneExists, - Drop_DoesNotExist); + Drop_DoesNotExist, + ReadMetadata, + ReadAllMetadata); } // namespace syncer
diff --git a/sync/internal_api/attachments/in_memory_attachment_store.cc b/sync/internal_api/attachments/in_memory_attachment_store.cc index f5000c7e..9ce6c3e 100644 --- a/sync/internal_api/attachments/in_memory_attachment_store.cc +++ b/sync/internal_api/attachments/in_memory_attachment_store.cc
@@ -11,6 +11,16 @@ namespace syncer { +namespace { + +void AppendMetadata(AttachmentMetadataList* list, + const Attachment& attachment) { + list->push_back( + AttachmentMetadata(attachment.GetId(), attachment.GetData()->size())); +} + +} // namespace + InMemoryAttachmentStore::InMemoryAttachmentStore( const scoped_refptr<base::SingleThreadTaskRunner>& callback_task_runner) : callback_task_runner_(callback_task_runner) { @@ -85,14 +95,40 @@ void InMemoryAttachmentStore::ReadMetadata( const AttachmentIdList& ids, const ReadMetadataCallback& callback) { - // TODO(stanisc): implement this. - NOTIMPLEMENTED(); + DCHECK(CalledOnValidThread()); + Result result_code = SUCCESS; + scoped_ptr<AttachmentMetadataList> metadata_list( + new AttachmentMetadataList()); + AttachmentIdList::const_iterator ids_iter = ids.begin(); + AttachmentIdList::const_iterator ids_end = ids.end(); + + for (; ids_iter != ids_end; ++ids_iter) { + AttachmentMap::iterator attachments_iter = attachments_.find(*ids_iter); + if (attachments_iter != attachments_.end()) { + AppendMetadata(metadata_list.get(), attachments_iter->second); + } else { + result_code = UNSPECIFIED_ERROR; + } + } + callback_task_runner_->PostTask( + FROM_HERE, + base::Bind(callback, result_code, base::Passed(&metadata_list))); } void InMemoryAttachmentStore::ReadAllMetadata( const ReadMetadataCallback& callback) { - // TODO(stanisc): implement this. - NOTIMPLEMENTED(); + DCHECK(CalledOnValidThread()); + Result result_code = SUCCESS; + scoped_ptr<AttachmentMetadataList> metadata_list( + new AttachmentMetadataList()); + + for (AttachmentMap::const_iterator iter = attachments_.begin(); + iter != attachments_.end(); ++iter) { + AppendMetadata(metadata_list.get(), iter->second); + } + callback_task_runner_->PostTask( + FROM_HERE, + base::Bind(callback, result_code, base::Passed(&metadata_list))); } } // namespace syncer
diff --git a/sync/internal_api/attachments/on_disk_attachment_store.cc b/sync/internal_api/attachments/on_disk_attachment_store.cc index 16fa0c0b..309e610 100644 --- a/sync/internal_api/attachments/on_disk_attachment_store.cc +++ b/sync/internal_api/attachments/on_disk_attachment_store.cc
@@ -41,16 +41,14 @@ return write_options; } -leveldb::ReadOptions MakeDataReadOptions() { +leveldb::ReadOptions MakeNonCachingReadOptions() { leveldb::ReadOptions read_options; - // Attachment content is typically large and only read once. Don't cache it on - // db level. read_options.fill_cache = false; read_options.verify_checksums = true; return read_options; } -leveldb::ReadOptions MakeMetadataReadOptions() { +leveldb::ReadOptions MakeCachingReadOptions() { leveldb::ReadOptions read_options; read_options.fill_cache = true; read_options.verify_checksums = true; @@ -63,7 +61,7 @@ std::string data_str; leveldb::Status status = - db->Get(MakeMetadataReadOptions(), kDatabaseMetadataKey, &data_str); + db->Get(MakeCachingReadOptions(), kDatabaseMetadataKey, &data_str); if (!status.ok()) return status; if (!metadata->ParseFromString(data_str)) @@ -177,14 +175,72 @@ void OnDiskAttachmentStore::ReadMetadata(const AttachmentIdList& ids, const ReadMetadataCallback& callback) { - // TODO(stanisc): implement this. - NOTIMPLEMENTED(); + DCHECK(CalledOnValidThread()); + Result result_code = STORE_INITIALIZATION_FAILED; + scoped_ptr<AttachmentMetadataList> metadata_list( + new AttachmentMetadataList()); + if (db_) { + result_code = SUCCESS; + AttachmentIdList::const_iterator iter = ids.begin(); + const AttachmentIdList::const_iterator end = ids.end(); + for (; iter != end; ++iter) { + attachment_store_pb::RecordMetadata record_metadata; + if (ReadSingleRecordMetadata(*iter, &record_metadata)) { + metadata_list->push_back( + MakeAttachmentMetadata(*iter, record_metadata)); + } else { + result_code = UNSPECIFIED_ERROR; + } + } + } + callback_task_runner_->PostTask( + FROM_HERE, + base::Bind(callback, result_code, base::Passed(&metadata_list))); } void OnDiskAttachmentStore::ReadAllMetadata( const ReadMetadataCallback& callback) { - // TODO(stanisc): implement this. - NOTIMPLEMENTED(); + DCHECK(CalledOnValidThread()); + Result result_code = STORE_INITIALIZATION_FAILED; + scoped_ptr<AttachmentMetadataList> metadata_list( + new AttachmentMetadataList()); + + if (db_) { + result_code = SUCCESS; + scoped_ptr<leveldb::Iterator> db_iterator( + db_->NewIterator(MakeNonCachingReadOptions())); + DCHECK(db_iterator); + for (db_iterator->Seek(kMetadataPrefix); db_iterator->Valid(); + db_iterator->Next()) { + leveldb::Slice key = db_iterator->key(); + if (!key.starts_with(kMetadataPrefix)) { + break; + } + // Make AttachmentId from levelDB key. + key.remove_prefix(strlen(kMetadataPrefix)); + sync_pb::AttachmentIdProto id_proto; + id_proto.set_unique_id(key.ToString()); + AttachmentId id = AttachmentId::CreateFromProto(id_proto); + // Parse metadata record. + attachment_store_pb::RecordMetadata record_metadata; + if (!record_metadata.ParseFromString(db_iterator->value().ToString())) { + DVLOG(1) << "RecordMetadata::ParseFromString failed"; + result_code = UNSPECIFIED_ERROR; + continue; + } + metadata_list->push_back(MakeAttachmentMetadata(id, record_metadata)); + } + + if (!db_iterator->status().ok()) { + DVLOG(1) << "DB Iterator failed: status=" + << db_iterator->status().ToString(); + result_code = UNSPECIFIED_ERROR; + } + } + + callback_task_runner_->PostTask( + FROM_HERE, + base::Bind(callback, result_code, base::Passed(&metadata_list))); } AttachmentStore::Result OnDiskAttachmentStore::OpenOrCreate( @@ -239,24 +295,14 @@ scoped_ptr<Attachment> OnDiskAttachmentStore::ReadSingleAttachment( const AttachmentId& attachment_id) { scoped_ptr<Attachment> attachment; - - const std::string key = MakeDataKeyFromAttachmentId(attachment_id); - const std::string metadata_key = - MakeMetadataKeyFromAttachmentId(attachment_id); - leveldb::Status status; - std::string metadata_str; - status = db_->Get(MakeMetadataReadOptions(), metadata_key, &metadata_str); - if (!status.ok()) { - DVLOG(1) << "DB::Get for metadata failed: status=" << status.ToString(); - return attachment.Pass(); - } attachment_store_pb::RecordMetadata record_metadata; - if (!record_metadata.ParseFromString(metadata_str)) { - DVLOG(1) << "RecordMetadata::ParseFromString failed"; + if (!ReadSingleRecordMetadata(attachment_id, &record_metadata)) { return attachment.Pass(); } + const std::string key = MakeDataKeyFromAttachmentId(attachment_id); std::string data_str; - status = db_->Get(MakeDataReadOptions(), key, &data_str); + leveldb::Status status = db_->Get( + MakeNonCachingReadOptions(), key, &data_str); if (!status.ok()) { DVLOG(1) << "DB::Get for data failed: status=" << status.ToString(); return attachment.Pass(); @@ -281,7 +327,7 @@ std::string metadata_str; leveldb::Status status = - db_->Get(MakeMetadataReadOptions(), metadata_key, &metadata_str); + db_->Get(MakeCachingReadOptions(), metadata_key, &metadata_str); if (status.ok()) { // Entry exists, don't overwrite. return true; @@ -313,6 +359,26 @@ return true; } +bool OnDiskAttachmentStore::ReadSingleRecordMetadata( + const AttachmentId& attachment_id, + attachment_store_pb::RecordMetadata* record_metadata) { + DCHECK(record_metadata); + const std::string metadata_key = + MakeMetadataKeyFromAttachmentId(attachment_id); + std::string metadata_str; + leveldb::Status status = + db_->Get(MakeCachingReadOptions(), metadata_key, &metadata_str); + if (!status.ok()) { + DVLOG(1) << "DB::Get for metadata failed: status=" << status.ToString(); + return false; + } + if (!record_metadata->ParseFromString(metadata_str)) { + DVLOG(1) << "RecordMetadata::ParseFromString failed"; + return false; + } + return true; +} + std::string OnDiskAttachmentStore::MakeDataKeyFromAttachmentId( const AttachmentId& attachment_id) { std::string key = kDataPrefix + attachment_id.GetProto().unique_id(); @@ -325,4 +391,10 @@ return key; } +AttachmentMetadata OnDiskAttachmentStore::MakeAttachmentMetadata( + const AttachmentId& attachment_id, + const attachment_store_pb::RecordMetadata& record_metadata) { + return AttachmentMetadata(attachment_id, record_metadata.attachment_size()); +} + } // namespace syncer
diff --git a/sync/internal_api/attachments/on_disk_attachment_store_unittest.cc b/sync/internal_api/attachments/on_disk_attachment_store_unittest.cc index 620ff743..e46f060 100644 --- a/sync/internal_api/attachments/on_disk_attachment_store_unittest.cc +++ b/sync/internal_api/attachments/on_disk_attachment_store_unittest.cc
@@ -62,11 +62,18 @@ class OnDiskAttachmentStoreSpecificTest : public testing::Test { public: base::ScopedTempDir temp_dir_; + base::FilePath db_path_; base::MessageLoop message_loop_; scoped_refptr<AttachmentStore> store_; OnDiskAttachmentStoreSpecificTest() {} + void SetUp() override { + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + db_path_ = temp_dir_.path().Append(FILE_PATH_LITERAL("leveldb")); + base::CreateDirectory(db_path_); + } + void CopyResult(AttachmentStore::Result* destination_result, const AttachmentStore::Result& source_result) { *destination_result = source_result; @@ -82,25 +89,44 @@ *destination_failed_attachment_ids = *source_failed_attachment_ids; } - scoped_ptr<leveldb::DB> OpenLevelDB(const base::FilePath& path) { + void CopyResultMetadata( + AttachmentStore::Result* destination_result, + scoped_ptr<AttachmentMetadataList>* destination_metadata, + const AttachmentStore::Result& source_result, + scoped_ptr<AttachmentMetadataList> source_metadata) { + CopyResult(destination_result, source_result); + *destination_metadata = source_metadata.Pass(); + } + + scoped_ptr<leveldb::DB> OpenLevelDB() { leveldb::DB* db; leveldb::Options options; options.create_if_missing = true; - leveldb::Status s = leveldb::DB::Open(options, path.AsUTF8Unsafe(), &db); + leveldb::Status s = + leveldb::DB::Open(options, db_path_.AsUTF8Unsafe(), &db); EXPECT_TRUE(s.ok()); return make_scoped_ptr(db); } - void UpdateStoreMetadataRecord(const base::FilePath& path, - const std::string& content) { - scoped_ptr<leveldb::DB> db = OpenLevelDB(path); - leveldb::Status s = - db->Put(leveldb::WriteOptions(), "database-metadata", content); + void UpdateRecord(const std::string& key, const std::string& content) { + scoped_ptr<leveldb::DB> db = OpenLevelDB(); + leveldb::Status s = db->Put(leveldb::WriteOptions(), key, content); EXPECT_TRUE(s.ok()); } - std::string ReadStoreMetadataRecord(const base::FilePath& path) { - scoped_ptr<leveldb::DB> db = OpenLevelDB(path); + void UpdateStoreMetadataRecord(const std::string& content) { + UpdateRecord("database-metadata", content); + } + + void UpdateAttachmentMetadataRecord(const AttachmentId& attachment_id, + const std::string& content) { + std::string metadata_key = + OnDiskAttachmentStore::MakeMetadataKeyFromAttachmentId(attachment_id); + UpdateRecord(metadata_key, content); + } + + std::string ReadStoreMetadataRecord() { + scoped_ptr<leveldb::DB> db = OpenLevelDB(); std::string content; leveldb::Status s = db->Get(leveldb::ReadOptions(), "database-metadata", &content); @@ -108,10 +134,9 @@ return content; } - void VerifyAttachmentRecordsPresent(const base::FilePath& path, - const AttachmentId& attachment_id, + void VerifyAttachmentRecordsPresent(const AttachmentId& attachment_id, bool expect_records_present) { - scoped_ptr<leveldb::DB> db = OpenLevelDB(path); + scoped_ptr<leveldb::DB> db = OpenLevelDB(); std::string metadata_key = OnDiskAttachmentStore::MakeMetadataKeyFromAttachmentId(attachment_id); @@ -139,7 +164,6 @@ // Ensure that store can be closed and reopen while retaining stored // attachments. TEST_F(OnDiskAttachmentStoreSpecificTest, CloseAndReopen) { - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); AttachmentStore::Result result; result = AttachmentStore::UNSPECIFIED_ERROR; @@ -186,16 +210,10 @@ // Ensure loading corrupt attachment store fails. TEST_F(OnDiskAttachmentStoreSpecificTest, FailToOpen) { - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - base::FilePath db_path = - temp_dir_.path().Append(FILE_PATH_LITERAL("leveldb")); - base::CreateDirectory(db_path); - // To simulate corrupt database write empty CURRENT file. std::string current_file_content = ""; - base::WriteFile(db_path.Append(FILE_PATH_LITERAL("CURRENT")), - current_file_content.c_str(), - current_file_content.size()); + base::WriteFile(db_path_.Append(FILE_PATH_LITERAL("CURRENT")), + current_file_content.c_str(), current_file_content.size()); AttachmentStore::Result result = AttachmentStore::SUCCESS; store_ = AttachmentStore::CreateOnDiskStore( @@ -208,13 +226,8 @@ // Ensure that attachment store works correctly when store metadata is missing, // corrupt or has unknown schema version. TEST_F(OnDiskAttachmentStoreSpecificTest, StoreMetadata) { - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - base::FilePath db_path = - temp_dir_.path().Append(FILE_PATH_LITERAL("leveldb")); - base::CreateDirectory(db_path); - // Create and close empty database. - OpenLevelDB(db_path); + OpenLevelDB(); // Open database with AttachmentStore. AttachmentStore::Result result = AttachmentStore::UNSPECIFIED_ERROR; store_ = AttachmentStore::CreateOnDiskStore( @@ -227,7 +240,7 @@ RunLoop(); // AttachmentStore should create metadata record. - std::string data = ReadStoreMetadataRecord(db_path); + std::string data = ReadStoreMetadataRecord(); attachment_store_pb::StoreMetadata metadata; EXPECT_TRUE(metadata.ParseFromString(data)); EXPECT_EQ(1, metadata.schema_version()); @@ -235,7 +248,7 @@ // Set unknown future schema version. metadata.set_schema_version(2); data = metadata.SerializeAsString(); - UpdateStoreMetadataRecord(db_path, data); + UpdateStoreMetadataRecord(data); // AttachmentStore should fail to load. result = AttachmentStore::SUCCESS; @@ -246,7 +259,7 @@ EXPECT_EQ(AttachmentStore::UNSPECIFIED_ERROR, result); // Write garbage into metadata record. - UpdateStoreMetadataRecord(db_path, "abra.cadabra"); + UpdateStoreMetadataRecord("abra.cadabra"); // AttachmentStore should fail to load. result = AttachmentStore::SUCCESS; @@ -260,10 +273,6 @@ // Ensure that attachment store correctly maintains metadata records for // attachments. TEST_F(OnDiskAttachmentStoreSpecificTest, RecordMetadata) { - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - base::FilePath db_path = - temp_dir_.path().Append(FILE_PATH_LITERAL("leveldb")); - // Create attachment store. AttachmentStore::Result create_result = AttachmentStore::UNSPECIFIED_ERROR; store_ = AttachmentStore::CreateOnDiskStore( @@ -298,14 +307,12 @@ EXPECT_EQ(AttachmentStore::SUCCESS, drop_result); // Verify that attachment store contains only records for second attachment. - VerifyAttachmentRecordsPresent(db_path, attachments[0].GetId(), false); - VerifyAttachmentRecordsPresent(db_path, attachments[1].GetId(), true); + VerifyAttachmentRecordsPresent(attachments[0].GetId(), false); + VerifyAttachmentRecordsPresent(attachments[1].GetId(), true); } // Ensure that attachment store fails to load attachment with mismatched crc. TEST_F(OnDiskAttachmentStoreSpecificTest, MismatchedCrc) { - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - // Create attachment store. AttachmentStore::Result create_result = AttachmentStore::UNSPECIFIED_ERROR; store_ = AttachmentStore::CreateOnDiskStore( @@ -344,14 +351,9 @@ // Ensure that after store initialization failure ReadWrite/Drop operations fail // with correct error. TEST_F(OnDiskAttachmentStoreSpecificTest, OpsAfterInitializationFailed) { - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - base::FilePath db_path = - temp_dir_.path().Append(FILE_PATH_LITERAL("leveldb")); - base::CreateDirectory(db_path); - // To simulate corrupt database write empty CURRENT file. std::string current_file_content = ""; - base::WriteFile(db_path.Append(FILE_PATH_LITERAL("CURRENT")), + base::WriteFile(db_path_.Append(FILE_PATH_LITERAL("CURRENT")), current_file_content.c_str(), current_file_content.size()); AttachmentStore::Result create_result = AttachmentStore::SUCCESS; @@ -397,4 +399,79 @@ EXPECT_EQ(AttachmentStore::STORE_INITIALIZATION_FAILED, write_result); } +// Ensure that attachment store handles the case of having an unexpected +// record at the end without crashing. +TEST_F(OnDiskAttachmentStoreSpecificTest, ReadAllMetadataWithUnexpectedRecord) { + // Write a bogus entry at the end of the database. + UpdateRecord("zzz", "foobar"); + + // Create attachment store. + AttachmentStore::Result create_result = AttachmentStore::UNSPECIFIED_ERROR; + store_ = AttachmentStore::CreateOnDiskStore( + temp_dir_.path(), base::ThreadTaskRunnerHandle::Get(), + base::Bind(&AttachmentStoreCreated, &create_result)); + + // Read all metadata. Should be getting no error and zero entries. + AttachmentStore::Result metadata_result = AttachmentStore::UNSPECIFIED_ERROR; + scoped_ptr<AttachmentMetadataList> metadata_list; + store_->ReadAllMetadata( + base::Bind(&OnDiskAttachmentStoreSpecificTest::CopyResultMetadata, + base::Unretained(this), &metadata_result, &metadata_list)); + RunLoop(); + EXPECT_EQ(AttachmentStore::SUCCESS, create_result); + EXPECT_EQ(AttachmentStore::SUCCESS, metadata_result); + EXPECT_EQ(0U, metadata_list->size()); + metadata_list.reset(); + + // Write 3 attachments to the store + AttachmentList attachments; + + for (int i = 0; i < 3; i++) { + std::string some_data = "data"; + Attachment attachment = + Attachment::Create(base::RefCountedString::TakeString(&some_data)); + attachments.push_back(attachment); + } + AttachmentStore::Result write_result = AttachmentStore::UNSPECIFIED_ERROR; + store_->Write(attachments, + base::Bind(&OnDiskAttachmentStoreSpecificTest::CopyResult, + base::Unretained(this), &write_result)); + + // Read all metadata back. We should be getting 3 entries. + store_->ReadAllMetadata( + base::Bind(&OnDiskAttachmentStoreSpecificTest::CopyResultMetadata, + base::Unretained(this), &metadata_result, &metadata_list)); + RunLoop(); + EXPECT_EQ(AttachmentStore::SUCCESS, write_result); + EXPECT_EQ(AttachmentStore::SUCCESS, metadata_result); + EXPECT_EQ(3U, metadata_list->size()); + // Get Id of the attachment in the middle. + AttachmentId id = (*metadata_list.get())[1].GetId(); + metadata_list.reset(); + + // Close the store. + store_ = nullptr; + RunLoop(); + + // Modify the middle attachment metadata entry so that it isn't valid anymore. + UpdateAttachmentMetadataRecord(id, "foobar"); + + // Reopen the store. + create_result = AttachmentStore::UNSPECIFIED_ERROR; + metadata_result = AttachmentStore::UNSPECIFIED_ERROR; + store_ = AttachmentStore::CreateOnDiskStore( + temp_dir_.path(), base::ThreadTaskRunnerHandle::Get(), + base::Bind(&AttachmentStoreCreated, &create_result)); + + // Read all metadata back. We should be getting a failure and + // only 2 entries now. + store_->ReadAllMetadata( + base::Bind(&OnDiskAttachmentStoreSpecificTest::CopyResultMetadata, + base::Unretained(this), &metadata_result, &metadata_list)); + RunLoop(); + EXPECT_EQ(AttachmentStore::SUCCESS, create_result); + EXPECT_EQ(AttachmentStore::UNSPECIFIED_ERROR, metadata_result); + EXPECT_EQ(2U, metadata_list->size()); +} + } // namespace syncer
diff --git a/sync/internal_api/public/attachments/on_disk_attachment_store.h b/sync/internal_api/public/attachments/on_disk_attachment_store.h index ed6eefb..cb809a0 100644 --- a/sync/internal_api/public/attachments/on_disk_attachment_store.h +++ b/sync/internal_api/public/attachments/on_disk_attachment_store.h
@@ -13,6 +13,10 @@ #include "sync/api/attachments/attachment_store.h" #include "sync/base/sync_export.h" +namespace attachment_store_pb { +class RecordMetadata; +} // namespace attachment_store_pb + namespace base { class SequencedTaskRunner; } // namespace base @@ -56,11 +60,19 @@ const AttachmentId& attachment_id); // Writes single attachment to store. Returns false in case of errors. bool WriteSingleAttachment(const Attachment& attachment); + // Reads single store_pb::RecordMetadata from levelDB into the provided + // buffer. Returns false in case of an error. + bool ReadSingleRecordMetadata( + const AttachmentId& attachment_id, + attachment_store_pb::RecordMetadata* record_metadata); static std::string MakeDataKeyFromAttachmentId( const AttachmentId& attachment_id); static std::string MakeMetadataKeyFromAttachmentId( const AttachmentId& attachment_id); + static AttachmentMetadata MakeAttachmentMetadata( + const AttachmentId& attachment_id, + const attachment_store_pb::RecordMetadata& record_metadata); scoped_refptr<base::SequencedTaskRunner> callback_task_runner_; const base::FilePath path_;
diff --git a/third_party/cython/cython_compiler.gypi b/third_party/cython/cython_compiler.gypi deleted file mode 100644 index ca974a27..0000000 --- a/third_party/cython/cython_compiler.gypi +++ /dev/null
@@ -1,64 +0,0 @@ -# Copyright 2014 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -{ - 'variables': { - 'python_flags': '<(DEPTH)/third_party/cython/python_flags.py', - }, - 'conditions': [ - ['OS=="mac"', { - 'variables': { - 'module_prefix': '', - 'module_suffix': '.so', - }, - }, { - 'variables': { - 'module_prefix': '<(SHARED_LIB_PREFIX)', - 'module_suffix': '<(SHARED_LIB_SUFFIX)', - }, - }], - ], - 'type': 'loadable_module', - 'rules': [ - { - 'rule_name': '<(_target_name)_cython_compiler', - 'extension': 'pyx', - 'variables': { - 'cython_compiler': '<(DEPTH)/third_party/cython/src/cython.py', - }, - 'inputs': [ - '<(cython_compiler)', - ], - 'outputs': [ - '<(SHARED_INTERMEDIATE_DIR)/cython/<(python_base_module)/<(RULE_INPUT_ROOT).cc', - ], - 'action': [ - 'python', '<(cython_compiler)', - '--cplus', - '-I<(DEPTH)', - '-o', '<@(_outputs)', - '<(RULE_INPUT_PATH)', - ], - 'message': 'Generating C++ source from <(RULE_INPUT_PATH)', - 'process_outputs_as_sources': 1, - } - ], - 'include_dirs': [ - '<!@(python <(python_flags) --includes)', - '<(DEPTH)', - ], - 'libraries': [ - '<!@(python <(python_flags) --libraries)', - ], - 'cflags': [ - '-Wno-unused-function', - ], - 'xcode_settings': { - 'WARNING_CFLAGS': [ '-Wno-unused-function' ], - }, - 'library_dirs': [ - '<!@(python <(python_flags) --library_dirs)', - ], - 'hard_dependency': 1, -}
diff --git a/third_party/cython/python_flags.py b/third_party/cython/python_flags.py index b10aece..492c9a9 100644 --- a/third_party/cython/python_flags.py +++ b/third_party/cython/python_flags.py
@@ -16,9 +16,6 @@ """ parser = argparse.ArgumentParser( description='Retrieves compilation options for python modules.') - parser.add_argument('--gn', - help='Returns all values in a format suitable for gn', - action='store_true') parser.add_argument('--libraries', help='Returns libraries', action='store_true') parser.add_argument('--includes', help='Returns includes', @@ -36,11 +33,6 @@ libraries = b.get_libraries(ext) if sys.platform == 'darwin': libraries.append('python%s' % sys.version[:3]) - if not opts.gn and sys.platform in ['darwin', 'linux2']: - # In case of GYP output for darwin and linux prefix all - # libraries (if there are any) so the result can be used as a - # compiler argument. GN handles platform-appropriate prefixing itself. - libraries = ['-l%s' % library for library in libraries] result.extend(libraries) if opts.includes: result = result + b.include_dirs @@ -48,11 +40,8 @@ if sys.platform == 'darwin': result.append('%s/lib' % sysconfig.get_config_vars('prefix')[0]) - if opts.gn: - for x in result: - print x - else: - print ''.join(['"%s"' % x for x in result]) + for x in result: + print x if __name__ == '__main__': main()
diff --git a/third_party/cython/rules.gni b/third_party/cython/rules.gni index efd9ca3..1d2ccfb3 100644 --- a/third_party/cython/rules.gni +++ b/third_party/cython/rules.gni
@@ -2,31 +2,19 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -template("python_binary_module") { +template("python_binary_module_sources") { # Only available on linux for now. assert(is_linux) assert(defined(invoker.sources)) - assert(defined(invoker.python_base_module)) cython_root = "//third_party/cython" cython_script = "$cython_root/src/cython.py" cython_output = "${target_out_dir}/${target_name}.cc" generator_target_name = target_name + "_cython_compiler" - shared_library_name = target_name + "_shared_library" config_name = target_name + "_python_config" - if (is_linux) { - shared_library_prefix = "lib" - shared_library_suffix = ".so" - python_module_suffix = ".so" - } - - target_visibility = [ - ":$generator_target_name", - ":$shared_library_name", - ":$target_name", - ] + target_visibility = [ ":$target_name" ] action(generator_target_name) { visibility = target_visibility @@ -35,8 +23,10 @@ outputs = [ cython_output ] args = [ "--cplus", - "-I", rebase_path("//", root_build_dir), - "-o", rebase_path(cython_output, root_build_dir), + "-I", + rebase_path("//", root_build_dir), + "-o", + rebase_path(cython_output, root_build_dir), ] + rebase_path(sources, root_build_dir) } @@ -44,27 +34,25 @@ visibility = target_visibility python_flags = "//third_party/cython/python_flags.py" include_dirs = exec_script(python_flags, - [ "--gn", "--includes" ], + [ "--includes" ], "list lines") libs = exec_script(python_flags, - [ "--gn", "--libraries" ], + [ "--libraries" ], "list lines") lib_dirs = exec_script(python_flags, - [ "--gn", "--library_dirs" ], + [ "--library_dirs" ], "list lines") if (!is_win) { # Generated code includes static utility functions that often go unused. - cflags = [ - "-Wno-unused-function", - ] + cflags = [ "-Wno-unused-function" ] } } - shared_library(shared_library_name) { - visibility = target_visibility - deps = [ - ":$generator_target_name", - ] + source_set(target_name) { + deps = [ ":$generator_target_name" ] + if (defined(invoker.visibility)) { + visibility = invoker.visibility + } if (defined(invoker.deps)) { deps += invoker.deps } @@ -75,7 +63,48 @@ if (defined(invoker.additional_sources)) { sources += invoker.additional_sources } - configs += [ ":$config_name" ] + all_dependent_configs = [ ":$config_name" ] + } +} + +template("python_binary_module") { + # Only available on linux for now. + assert(is_linux) + assert(defined(invoker.sources)) + assert(defined(invoker.python_base_module)) + + sources_target_name = target_name + "_cython_sources" + shared_library_name = target_name + "_shared_library" + + if (is_linux) { + shared_library_prefix = "lib" + shared_library_suffix = ".so" + python_module_suffix = ".so" + } + + target_visibility = [ + ":$sources_target_name", + ":$shared_library_name", + ":$target_name", + ] + + python_binary_module_sources(sources_target_name) { + visibility = target_visibility + sources = invoker.sources + } + + shared_library(shared_library_name) { + visibility = target_visibility + deps = [ ":$sources_target_name" ] + if (defined(invoker.deps)) { + deps += invoker.deps + } + if (defined(invoker.datadeps)) { + datadeps = invoker.datadeps + } + if (defined(invoker.additional_sources)) { + sources = invoker.additional_sources + } if (defined(invoker.configs)) { configs += invoker.configs } @@ -89,8 +118,6 @@ outputs = [ "$root_out_dir/python/$python_base_module/${target_name}${python_module_suffix}" ] - deps = [ - ":$shared_library_name" - ] + deps = [ ":$shared_library_name" ] } }
diff --git a/third_party/drmemory/README.chromium b/third_party/drmemory/README.chromium index ffa17cc..b07f6b5 100644 --- a/third_party/drmemory/README.chromium +++ b/third_party/drmemory/README.chromium
@@ -1,6 +1,6 @@ Name: Dr. Memory Short Name: drmemory -URL: http://code.google.com/p/drmemory +URL: http://drmemory.org Version: 1.8.2075 License: LGPL 2.1 License File: NOT_SHIPPED @@ -40,5 +40,6 @@ checked in, or whether the MFYI bot was red at the same revision. === -Dr. Memory is hosted at http://code.google.com/p/drmemory under LGPL -http://code.google.com/p/drmemory/source/browse/trunk/license.txt +Dr. Memory is hosted at http://drmemory.org and +https://github.com/DynamoRIO/drmemory under LGPL +https://github.com/DynamoRIO/drmemory/blob/master/license.txt
diff --git a/third_party/eyesfree/BUILD.gn b/third_party/eyesfree/BUILD.gn deleted file mode 100644 index c435ece..0000000 --- a/third_party/eyesfree/BUILD.gn +++ /dev/null
@@ -1,18 +0,0 @@ -import("//build/config/android/config.gni") -import("//build/config/android/rules.gni") - -android_library("eyesfree_java") { - srcjar_deps = [ ":eyesfree_aidl" ] - DEPRECATED_java_in_dir = "src/android/java/src" -} - -android_aidl("eyesfree_aidl") { - import_include = "src/android/java/src" - sources = [ - "src/android/java/src/com/googlecode/eyesfree/braille/display/IBrailleService.aidl", - "src/android/java/src/com/googlecode/eyesfree/braille/display/IBrailleServiceCallback.aidl", - "src/android/java/src/com/googlecode/eyesfree/braille/selfbraille/ISelfBrailleService.aidl", - "src/android/java/src/com/googlecode/eyesfree/braille/translate/ITranslatorService.aidl", - "src/android/java/src/com/googlecode/eyesfree/braille/translate/ITranslatorServiceCallback.aidl", - ] -}
diff --git a/third_party/eyesfree/LICENSE b/third_party/eyesfree/LICENSE deleted file mode 100644 index c61423c..0000000 --- a/third_party/eyesfree/LICENSE +++ /dev/null
@@ -1,203 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2011 Google Inc. All Rights Reserved. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -
diff --git a/third_party/eyesfree/OWNERS b/third_party/eyesfree/OWNERS deleted file mode 100644 index 6a341af5..0000000 --- a/third_party/eyesfree/OWNERS +++ /dev/null
@@ -1,2 +0,0 @@ -dtrainor@chromium.org -dmazzoni@chromium.org
diff --git a/third_party/eyesfree/README.chromium b/third_party/eyesfree/README.chromium deleted file mode 100644 index 27ec015..0000000 --- a/third_party/eyesfree/README.chromium +++ /dev/null
@@ -1,13 +0,0 @@ -Name: eyesfree -Short Name: eyesfree -URL: https://code.google.com/p/eyes-free/ -Version: r798 -License: Apache 2.0 -Security Critical: yes - -Description: -Speech Enabled Eyes-Free Android Applications. Used for Braille Keyboard -integration. - -Local Modifications: -None.
diff --git a/third_party/eyesfree/eyesfree.gyp b/third_party/eyesfree/eyesfree.gyp deleted file mode 100644 index f403ec3c..0000000 --- a/third_party/eyesfree/eyesfree.gyp +++ /dev/null
@@ -1,38 +0,0 @@ -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. -{ - 'conditions': [ - ['OS == "android" and android_webview_build == 0', { - 'targets': [ - { - 'target_name': 'eyesfree_java', - 'type': 'none', - 'dependencies': [ - 'eyesfree_aidl', - ], - 'variables': { - 'java_in_dir': 'src/android/java', - }, - 'includes': [ '../../build/java.gypi' ], - }, - { - 'target_name': 'eyesfree_aidl', - 'type': 'none', - 'variables': { - 'aidl_interface_file': '<(android_sdk)/framework.aidl', - 'aidl_import_include': 'src/android/java/src', - }, - 'sources': [ - 'src/android/java/src/com/googlecode/eyesfree/braille/display/IBrailleService.aidl', - 'src/android/java/src/com/googlecode/eyesfree/braille/display/IBrailleServiceCallback.aidl', - 'src/android/java/src/com/googlecode/eyesfree/braille/selfbraille/ISelfBrailleService.aidl', - 'src/android/java/src/com/googlecode/eyesfree/braille/translate/ITranslatorService.aidl', - 'src/android/java/src/com/googlecode/eyesfree/braille/translate/ITranslatorServiceCallback.aidl', - ], - 'includes': [ '../../build/java_aidl.gypi' ], - }, - ], - }], - ], -}
diff --git a/third_party/instrumented_libraries/download_build_install.py b/third_party/instrumented_libraries/download_build_install.py index 73ba2d0..ddaed773 100755 --- a/third_party/instrumented_libraries/download_build_install.py +++ b/third_party/instrumented_libraries/download_build_install.py
@@ -96,7 +96,9 @@ # files below. destdir = '%s/debian/instrumented_build' % os.getcwd() # Some makefiles use BUILDROOT instead of DESTDIR. - make_command = 'make DESTDIR=%s BUILDROOT=%s' % (destdir, destdir) + make_command = 'make DESTDIR=%s BUILDROOT=%s INSTALL_ROOT=%s' % (destdir, + destdir, + destdir) build_and_install_in_destdir = [ configure_command, '%s -j%s' % (make_command, parsed_arguments.jobs),
diff --git a/third_party/instrumented_libraries/install-build-deps.sh b/third_party/instrumented_libraries/install-build-deps.sh index 214fbc6..a7dfb552 100755 --- a/third_party/instrumented_libraries/install-build-deps.sh +++ b/third_party/instrumented_libraries/install-build-deps.sh
@@ -63,7 +63,8 @@ pango1.0 \ pulseaudio \ udev \ -zlib1g" +zlib1g \ +brltty" precise_specific_packages="libtasn1-3" trusty_specific_packages="\
diff --git a/third_party/instrumented_libraries/instrumented_libraries.gyp b/third_party/instrumented_libraries/instrumented_libraries.gyp index ebb19e64..339565ea 100644 --- a/third_party/instrumented_libraries/instrumented_libraries.gyp +++ b/third_party/instrumented_libraries/instrumented_libraries.gyp
@@ -156,6 +156,12 @@ '<(_sanitizer_type)-libpng12-0', ], }], + ['chromeos==1', { + 'dependencies': [ + '<(_sanitizer_type)-brltty', + '<(_sanitizer_type)-libva1', + ], + }] ], 'direct_dependent_settings': { 'target_conditions': [ @@ -668,5 +674,34 @@ 'dependencies=': [], 'includes': ['standard_instrumented_package_target.gypi'], }, + { + 'package_name': 'brltty', + 'extra_configure_flags': [ + # From debian/rules. + '--without-viavoice', + '--without-theta', + '--without-swift', + '--bindir=/sbin', + '--with-curses=ncursesw', + '--disable-stripping', + # We don't need any of those. + '--disable-java-bindings', + '--disable-lisp-bindings', + '--disable-ocaml-bindings', + '--disable-python-bindings', + '--disable-tcl-bindings' + ], + 'dependencies=': [], + 'includes': ['standard_instrumented_package_target.gypi'], + }, + { + 'package_name': 'libva1', + 'dependencies=': [], + # Backport a use-after-free fix: + # http://cgit.freedesktop.org/libva/diff/va/va.c?h=staging&id=d4988142a3f2256e38c5c5cdcdfc1b4f5f3c1ea9 + 'patch': 'patches/libva1.diff', + 'run_before_build': 'scripts/libva1.sh', + 'includes': ['standard_instrumented_package_target.gypi'], + }, ], }
diff --git a/third_party/instrumented_libraries/patches/libva1.diff b/third_party/instrumented_libraries/patches/libva1.diff new file mode 100644 index 0000000..2e4ca735 --- /dev/null +++ b/third_party/instrumented_libraries/patches/libva1.diff
@@ -0,0 +1,22 @@ +diff --git a/va/va.c b/va/va.c +index 6cb17ef..0ba595b 100644 +--- a/va/va.c ++++ b/va/va.c +@@ -515,15 +515,15 @@ VAStatus vaTerminate ( + free(old_ctx->vtable_vpp); + old_ctx->vtable_vpp = NULL; + +- if (VA_STATUS_SUCCESS == vaStatus) +- pDisplayContext->vaDestroy(pDisplayContext); +- + VA_TRACE_LOG(va_TraceTerminate, dpy); + + va_TraceEnd(dpy); + + va_FoolEnd(dpy); + ++ if (VA_STATUS_SUCCESS == vaStatus) ++ pDisplayContext->vaDestroy(pDisplayContext); ++ + return vaStatus; + }
diff --git a/third_party/instrumented_libraries/scripts/libva1.sh b/third_party/instrumented_libraries/scripts/libva1.sh new file mode 100755 index 0000000..d28002a --- /dev/null +++ b/third_party/instrumented_libraries/scripts/libva1.sh
@@ -0,0 +1,11 @@ +#!/bin/bash +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# This script does some preparations before build of instrumented libva1. + +# autogen is only required on Precise. +NOCONFIGURE=1 ./autogen.sh + +sed -i "s|-no-undefined -Wl,--no-undefined||g" dummy_drv_video/Makefile.in
diff --git a/third_party/leveldatabase/env_chromium.cc b/third_party/leveldatabase/env_chromium.cc index beb29d7..17b1c70 100644 --- a/third_party/leveldatabase/env_chromium.cc +++ b/third_party/leveldatabase/env_chromium.cc
@@ -84,7 +84,7 @@ while ((readdir_result = readdir_r(dir, &dent_buf, &dent)) == 0 && dent) { if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) continue; - result->push_back(ChromiumEnv::CreateFilePath(dent->d_name)); + result->push_back(FilePath::FromUTF8Unsafe(dent->d_name)); } int saved_errno = errno; closedir(dir); @@ -256,7 +256,7 @@ file_type_ = kTable; if (file_type_ != kManifest) tracker_->DidCreateNewFile(filename_); - parent_dir_ = ChromiumEnv::CreateFilePath(fname).DirName().AsUTF8Unsafe(); + parent_dir_ = FilePath::FromUTF8Unsafe(fname).DirName().AsUTF8Unsafe(); } Status ChromiumWritableFile::SyncParent() { @@ -520,12 +520,8 @@ return result != leveldb_env::NONE; } -FilePath ChromiumEnv::CreateFilePath(const std::string& file_path) { - return FilePath::FromUTF8Unsafe(file_path); -} - bool ChromiumEnv::MakeBackup(const std::string& fname) { - FilePath original_table_name = CreateFilePath(fname); + FilePath original_table_name = FilePath::FromUTF8Unsafe(fname); FilePath backup_table_name = original_table_name.ReplaceExtension(backup_table_extension); return base::CopyFile(original_table_name, backup_table_name); @@ -550,7 +546,7 @@ } bool ChromiumEnv::FileExists(const std::string& fname) { - return ::base::PathExists(CreateFilePath(fname)); + return ::base::PathExists(FilePath::FromUTF8Unsafe(fname)); } const char* ChromiumEnv::FileErrorString(::base::File::Error error) { @@ -614,7 +610,7 @@ for (std::vector<std::string>::iterator it = result->begin(); it != result->end(); ++it) { - FilePath current = CreateFilePath(*it); + FilePath current = FilePath::FromUTF8Unsafe(*it); if (current.MatchesExtension(table_extension)) tables_found.insert(current.RemoveExtension()); if (current.MatchesExtension(backup_table_extension)) @@ -647,7 +643,7 @@ std::vector<std::string>* result) { std::vector<FilePath> entries; base::File::Error error = - GetDirectoryEntries(CreateFilePath(dir_string), &entries); + GetDirectoryEntries(FilePath::FromUTF8Unsafe(dir_string), &entries); if (error != base::File::FILE_OK) { RecordOSError(kGetChildren, error); return MakeIOError( @@ -666,7 +662,7 @@ Status ChromiumEnv::DeleteFile(const std::string& fname) { Status result; - FilePath fname_filepath = CreateFilePath(fname); + FilePath fname_filepath = FilePath::FromUTF8Unsafe(fname); // TODO(jorlow): Should we assert this is a file? if (!::base::DeleteFile(fname_filepath, false)) { result = MakeIOError(fname, "Could not delete file.", kDeleteFile); @@ -684,7 +680,8 @@ base::File::Error error = base::File::FILE_OK; Retrier retrier(kCreateDir, this); do { - if (base::CreateDirectoryAndGetError(CreateFilePath(name), &error)) + if (base::CreateDirectoryAndGetError(FilePath::FromUTF8Unsafe(name), + &error)) return result; } while (retrier.ShouldKeepTrying(error)); result = MakeIOError(name, "Could not create directory.", kCreateDir, error); @@ -695,7 +692,7 @@ Status ChromiumEnv::DeleteDir(const std::string& name) { Status result; // TODO(jorlow): Should we assert this is a directory? - if (!::base::DeleteFile(CreateFilePath(name), false)) { + if (!::base::DeleteFile(FilePath::FromUTF8Unsafe(name), false)) { result = MakeIOError(name, "Could not delete directory.", kDeleteDir); RecordErrorAt(kDeleteDir); } @@ -705,7 +702,7 @@ Status ChromiumEnv::GetFileSize(const std::string& fname, uint64_t* size) { Status s; int64_t signed_size; - if (!::base::GetFileSize(CreateFilePath(fname), &signed_size)) { + if (!::base::GetFileSize(FilePath::FromUTF8Unsafe(fname), &signed_size)) { *size = 0; s = MakeIOError(fname, "Could not determine file size.", kGetFileSize); RecordErrorAt(kGetFileSize); @@ -717,10 +714,10 @@ Status ChromiumEnv::RenameFile(const std::string& src, const std::string& dst) { Status result; - FilePath src_file_path = CreateFilePath(src); + FilePath src_file_path = FilePath::FromUTF8Unsafe(src); if (!::base::PathExists(src_file_path)) return result; - FilePath destination = CreateFilePath(dst); + FilePath destination = FilePath::FromUTF8Unsafe(dst); Retrier retrier(kRenameFile, this); base::File::Error error = base::File::FILE_OK; @@ -749,14 +746,14 @@ ::base::File file; Retrier retrier(kLockFile, this); do { - file.Initialize(CreateFilePath(fname), flags); + file.Initialize(FilePath::FromUTF8Unsafe(fname), flags); if (!file.IsValid()) error_code = file.error_details(); } while (!file.IsValid() && retrier.ShouldKeepTrying(error_code)); if (!file.IsValid()) { if (error_code == ::base::File::FILE_ERROR_NOT_FOUND) { - FilePath parent = CreateFilePath(fname).DirName(); + FilePath parent = FilePath::FromUTF8Unsafe(fname).DirName(); FilePath last_parent; int num_missing_ancestors = 0; do { @@ -835,7 +832,7 @@ Status ChromiumEnv::NewLogger(const std::string& fname, leveldb::Logger** result) { - FilePath path = CreateFilePath(fname); + FilePath path = FilePath::FromUTF8Unsafe(fname); scoped_ptr<base::File> f(new base::File( path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE)); if (!f->IsValid()) { @@ -851,7 +848,7 @@ Status ChromiumEnv::NewSequentialFile(const std::string& fname, leveldb::SequentialFile** result) { - FilePath path = CreateFilePath(fname); + FilePath path = FilePath::FromUTF8Unsafe(fname); scoped_ptr<base::File> f( new base::File(path, base::File::FLAG_OPEN | base::File::FLAG_READ)); if (!f->IsValid()) { @@ -878,7 +875,7 @@ Status ChromiumEnv::NewRandomAccessFile(const std::string& fname, leveldb::RandomAccessFile** result) { int flags = ::base::File::FLAG_READ | ::base::File::FLAG_OPEN; - ::base::File file(ChromiumEnv::CreateFilePath(fname), flags); + ::base::File file(FilePath::FromUTF8Unsafe(fname), flags); if (file.IsValid()) { *result = new ChromiumRandomAccessFile(fname, file.Pass(), this); RecordOpenFilesLimit("Success"); @@ -898,7 +895,7 @@ Status ChromiumEnv::NewWritableFile(const std::string& fname, leveldb::WritableFile** result) { *result = NULL; - FilePath path = CreateFilePath(fname); + FilePath path = FilePath::FromUTF8Unsafe(fname); scoped_ptr<base::File> f(new base::File( path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE)); if (!f->IsValid()) {
diff --git a/third_party/leveldatabase/env_chromium.h b/third_party/leveldatabase/env_chromium.h index 87b3a877..a210d396 100644 --- a/third_party/leveldatabase/env_chromium.h +++ b/third_party/leveldatabase/env_chromium.h
@@ -103,8 +103,6 @@ typedef void(ScheduleFunc)(void*); static bool MakeBackup(const std::string& fname); - static base::FilePath CreateFilePath(const std::string& file_path); - static const char* FileErrorString(::base::File::Error error); static bool HasTableExtension(const base::FilePath& path); virtual ~ChromiumEnv(); @@ -142,6 +140,8 @@ bool make_backup_; private: + static const char* FileErrorString(::base::File::Error error); + virtual void DidCreateNewFile(const std::string& fname); virtual bool DoesDirNeedSync(const std::string& fname); virtual void RecordErrorAt(MethodID method) const;
diff --git a/third_party/sqlite/sqlite.gyp b/third_party/sqlite/sqlite.gyp index e6a0faf..3e55b11 100644 --- a/third_party/sqlite/sqlite.gyp +++ b/third_party/sqlite/sqlite.gyp
@@ -137,7 +137,7 @@ 'SQLITE_DEFAULT_AUTOVACUUM=1', 'SQLITE_TEMP_STORE=3', 'SQLITE_ENABLE_FTS3_BACKWARDS', - 'DSQLITE_DEFAULT_FILE_FORMAT=4', + 'SQLITE_DEFAULT_FILE_FORMAT=4', ], }], ['os_posix == 1 and OS != "mac" and OS != "android"', {
diff --git a/third_party/stp/BUILD.gn b/third_party/stp/BUILD.gn new file mode 100644 index 0000000..22e40f3 --- /dev/null +++ b/third_party/stp/BUILD.gn
@@ -0,0 +1,401 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +config("stp_config") { + include_dirs = [ + "config", + "src/include", + "src/lib", + "src/lib/Sat", + "src/lib/Sat/cryptominisat2/mtl", + "src/lib/extlib-abc", + "$target_gen_dir/src/include", + ] + cflags = [ + "-U_DEBUG", + "-Wno-dangling-else", + "-Wno-empty-body", + "-Wno-header-guard", + "-Wno-implicit-function-declaration", + "-Wno-mismatched-tags", + "-Wno-overloaded-virtual", + "-Wno-parentheses-equality", + "-Wno-return-type", + "-Wno-sign-compare", + "-Wno-sometimes-uninitialized", + "-Wno-string-conversion", + "-Wno-tautological-constant-out-of-range-compare", + "-Wno-unused-const-variable", + "-Wno-unused-function", + "-Wno-unused-private-field", + ] + cflags_cc = [ + "-fexceptions", + ] +} + +config("stp_public_config") { + include_dirs = [ + "src/include", + ] +} + +component("stp") { + configs += [ ":stp_config" ] + public_configs = [ ":stp_public_config" ] + + # Generated with: + # find src/include src/lib -name '*.[ch]' -o -name '*.cc' \ + # -o -name '*.cpp' -o -name 'MemoryPool.tcc' \ + # | grep -v -e /CryptoMinisat4 -e /TestAST/ -e /Util/ \ + # | sort + sources = [ + "config/stp/config.h", + "src/include/stp/AbsRefineCounterExample/AbsRefine_CounterExample.h", + "src/include/stp/AST/ArrayTransformer.h", + "src/include/stp/AST/ASTBVConst.h", + "src/include/stp/AST/AST.h", + "src/include/stp/AST/ASTInterior.h", + "src/include/stp/AST/ASTInternal.h", + "src/include/stp/AST/ASTInternalWithChildren.h", + "src/include/stp/AST/ASTNode.h", + "src/include/stp/AST/ASTSymbol.h", + "src/include/stp/AST/NodeFactory/HashingNodeFactory.h", + "src/include/stp/AST/NodeFactory/NodeFactory.h", + "src/include/stp/AST/NodeFactory/SimplifyingNodeFactory.h", + "src/include/stp/AST/NodeFactory/TypeChecker.h", + "src/include/stp/AST/RunTimes.h", + "src/include/stp/AST/STLport_config.h", + "src/include/stp/AST/UsefulDefs.h", + "src/include/stp/c_interface.h", + "src/include/stp/cpp_interface.h", + "src/include/stp/Globals/Globals.h", + "src/include/stp/Interface/fdstream.h", + "src/include/stp/Parser/LetMgr.h", + "src/include/stp/Parser/parser.h", + "src/include/stp/Printer/AssortedPrinters.h", + "src/include/stp/Printer/printers.h", + "src/include/stp/Printer/SMTLIBPrinter.h", + "src/include/stp/Sat/CryptoMinisat.h", + "src/include/stp/Sat/MinisatCore.h", + "src/include/stp/Sat/MinisatCore_prop.h", + "src/include/stp/Sat/SATSolver.h", + "src/include/stp/Sat/SimplifyingMinisat.h", + "src/include/stp/Simplifier/AIGSimplifyPropositionalCore.h", + "src/include/stp/Simplifier/AlwaysTrue.h", + "src/include/stp/Simplifier/bvsolver.h", + "src/include/stp/Simplifier/constantBitP/ConstantBitP_MaxPrecision.h", + "src/include/stp/Simplifier/constantBitP/ConstantBitPropagation.h", + "src/include/stp/Simplifier/constantBitP/ConstantBitP_TransferFunctions.h", + "src/include/stp/Simplifier/constantBitP/ConstantBitP_Utility.h", + "src/include/stp/Simplifier/constantBitP/Dependencies.h", + "src/include/stp/Simplifier/constantBitP/FixedBits.h", + "src/include/stp/Simplifier/constantBitP/MersenneTwister.h", + "src/include/stp/Simplifier/constantBitP/multiplication/ColumnCounts.h", + "src/include/stp/Simplifier/constantBitP/multiplication/ColumnStats.h", + "src/include/stp/Simplifier/constantBitP/MultiplicationStats.h", + "src/include/stp/Simplifier/constantBitP/NodeToFixedBitsMap.h", + "src/include/stp/Simplifier/constantBitP/WorkList.h", + "src/include/stp/Simplifier/EstablishIntervals.h", + "src/include/stp/Simplifier/FindPureLiterals.h", + "src/include/stp/Simplifier/MutableASTNode.h", + "src/include/stp/Simplifier/PropagateEqualities.h", + "src/include/stp/Simplifier/RemoveUnconstrained.h", + "src/include/stp/Simplifier/simplifier.h", + "src/include/stp/Simplifier/SubstitutionMap.h", + "src/include/stp/Simplifier/Symbols.h", + "src/include/stp/Simplifier/UseITEContext.h", + "src/include/stp/Simplifier/VariablesInExpression.h", + "src/include/stp/STPManager/DifficultyScore.h", + "src/include/stp/STPManager/NodeIterator.h", + "src/include/stp/STPManager/STP.h", + "src/include/stp/STPManager/STPManager.h", + "src/include/stp/STPManager/UserDefinedFlags.h", + "src/include/stp/ToSat/AIG/BBNodeAIG.h", + "src/include/stp/ToSat/AIG/BBNodeManagerAIG.h", + "src/include/stp/ToSat/AIG/ToCNFAIG.h", + "src/include/stp/ToSat/AIG/ToSATAIG.h", + "src/include/stp/ToSat/ASTNode/BBNodeManagerASTNode.h", + "src/include/stp/ToSat/ASTNode/ClauseList.h", + "src/include/stp/ToSat/ASTNode/ToCNF.h", + "src/include/stp/ToSat/ASTNode/ToSAT.h", + "src/include/stp/ToSat/BitBlaster.h", + "src/include/stp/ToSat/ToSATBase.h", + "src/lib/AbsRefineCounterExample/AbstractionRefinement.cpp", + "src/lib/AbsRefineCounterExample/CounterExample.cpp", + "src/lib/AST/ArrayTransformer.cpp", + "src/lib/AST/ASTBVConst.cpp", + "src/lib/AST/ASTInterior.cpp", + "src/lib/AST/ASTmisc.cpp", + "src/lib/AST/ASTNode.cpp", + "src/lib/AST/ASTSymbol.cpp", + "src/lib/AST/ASTUtil.cpp", + "src/lib/AST/NodeFactory/HashingNodeFactory.cpp", + "src/lib/AST/NodeFactory/NodeFactory.cpp", + "src/lib/AST/NodeFactory/SimplifyingNodeFactory.cpp", + "src/lib/AST/NodeFactory/TypeChecker.cpp", + "src/lib/AST/RunTimes.cpp", + "src/lib/extlib-abc/aig/aig/aigCheck.c", + "src/lib/extlib-abc/aig/aig/aigDfs.c", + "src/lib/extlib-abc/aig/aig/aigFanout.c", + "src/lib/extlib-abc/aig/aig/aigMan.c", + "src/lib/extlib-abc/aig/aig/aigMem.c", + "src/lib/extlib-abc/aig/aig/aigMffc.c", + "src/lib/extlib-abc/aig/aig/aigObj.c", + "src/lib/extlib-abc/aig/aig/aigOper.c", + "src/lib/extlib-abc/aig/aig/aigOrder.c", + "src/lib/extlib-abc/aig/aig/aigPart.c", + "src/lib/extlib-abc/aig/aig/aigRepr.c", + "src/lib/extlib-abc/aig/aig/aigRet.c", + "src/lib/extlib-abc/aig/aig/aigScl.c", + "src/lib/extlib-abc/aig/aig/aigSeq.c", + "src/lib/extlib-abc/aig/aig/aigShow.c", + "src/lib/extlib-abc/aig/aig/aigTable.c", + "src/lib/extlib-abc/aig/aig/aigTime.c", + "src/lib/extlib-abc/aig/aig/aigTiming.c", + "src/lib/extlib-abc/aig/aig/aigTruth.c", + "src/lib/extlib-abc/aig/aig/aigTsim.c", + "src/lib/extlib-abc/aig/aig/aigUtil.c", + "src/lib/extlib-abc/aig/aig/aigWin.c", + "src/lib/extlib-abc/aig/cnf/cnfCore.c", + "src/lib/extlib-abc/aig/cnf/cnfCut.c", + "src/lib/extlib-abc/aig/cnf/cnfData.c", + "src/lib/extlib-abc/aig/cnf/cnfMan.c", + "src/lib/extlib-abc/aig/cnf/cnfMap.c", + "src/lib/extlib-abc/aig/cnf/cnfPost.c", + "src/lib/extlib-abc/aig/cnf/cnfUtil.c", + "src/lib/extlib-abc/aig/cnf/cnfWrite.c", + "src/lib/extlib-abc/aig/dar/darBalance.c", + "src/lib/extlib-abc/aig/dar/darCore.c", + "src/lib/extlib-abc/aig/dar/darCut.c", + "src/lib/extlib-abc/aig/dar/darData.c", + "src/lib/extlib-abc/aig/dar/darLib.c", + "src/lib/extlib-abc/aig/dar/darMan.c", + "src/lib/extlib-abc/aig/dar/darPrec.c", + "src/lib/extlib-abc/aig/dar/darRefact.c", + "src/lib/extlib-abc/aig/dar/darScript.c", + "src/lib/extlib-abc/aig.h", + "src/lib/extlib-abc/aig/kit/kitAig.c", + "src/lib/extlib-abc/aig/kit/kitGraph.c", + "src/lib/extlib-abc/aig/kit/kitIsop.c", + "src/lib/extlib-abc/aig/kit/kitSop.c", + "src/lib/extlib-abc/aig/kit/kitTruth.c", + "src/lib/extlib-abc/cnf.h", + "src/lib/extlib-abc/cnf_short.h", + "src/lib/extlib-abc/dar.h", + "src/lib/extlib-abc/darInt.h", + "src/lib/extlib-abc/kit.h", + "src/lib/extlib-abc/leaks.h", + "src/lib/extlib-abc/vecFlt.h", + "src/lib/extlib-abc/vec.h", + "src/lib/extlib-abc/vecInt.h", + "src/lib/extlib-abc/vecPtr.h", + "src/lib/extlib-abc/vecStr.h", + "src/lib/extlib-abc/vecVec.h", + "src/lib/extlib-constbv/constantbv.cpp", + "src/lib/extlib-constbv/constantbv.h", + "src/lib/Globals/Globals.cpp", + "src/lib/Interface/c_interface.cpp", + "src/lib/Interface/cpp_interface.cpp", + "src/lib/Parser/LetMgr.cpp", + "src/lib/Printer/AssortedPrinters.cpp", + "src/lib/Printer/BenchPrinter.cpp", + "src/lib/Printer/CPrinter.cpp", + "src/lib/Printer/dotPrinter.cpp", + "src/lib/Printer/GDLPrinter.cpp", + "src/lib/Printer/LispPrinter.cpp", + "src/lib/Printer/PLPrinter.cpp", + "src/lib/Printer/SMTLIB1Printer.cpp", + "src/lib/Printer/SMTLIB2Printer.cpp", + "src/lib/Printer/SMTLIBPrinter.cpp", + "src/lib/Sat/cryptominisat2/BitArray.h", + "src/lib/Sat/cryptominisat2/BoundedQueue.h", + "src/lib/Sat/cryptominisat2/ClauseAllocator.cpp", + "src/lib/Sat/cryptominisat2/ClauseAllocator.h", + "src/lib/Sat/cryptominisat2/ClauseCleaner.cpp", + "src/lib/Sat/cryptominisat2/ClauseCleaner.h", + "src/lib/Sat/cryptominisat2/Clause.h", + "src/lib/Sat/cryptominisat2/constants.h", + "src/lib/Sat/cryptominisat2/CSet.h", + "src/lib/Sat/cryptominisat2/FailedVarSearcher.cpp", + "src/lib/Sat/cryptominisat2/FailedVarSearcher.h", + "src/lib/Sat/cryptominisat2/FindUndef.cpp", + "src/lib/Sat/cryptominisat2/FindUndef.h", + "src/lib/Sat/cryptominisat2/GaussianConfig.h", + "src/lib/Sat/cryptominisat2/Gaussian.cpp", + "src/lib/Sat/cryptominisat2/Gaussian.h", + "src/lib/Sat/cryptominisat2/Logger.cpp", + "src/lib/Sat/cryptominisat2/Logger.h", + "src/lib/Sat/cryptominisat2/MatrixFinder.cpp", + "src/lib/Sat/cryptominisat2/MatrixFinder.h", + "src/lib/Sat/cryptominisat2/MemoryPool/MemoryPool.h", + "src/lib/Sat/cryptominisat2/MemoryPool/MemoryPool.tcc", + "src/lib/Sat/cryptominisat2/MersenneTwister.h", + "src/lib/Sat/cryptominisat2/msvc/stdint.h", + "src/lib/Sat/cryptominisat2/mtl/Alg.h", + "src/lib/Sat/cryptominisat2/mtl/BasicHeap.h", + "src/lib/Sat/cryptominisat2/mtl/BoxedVec.h", + "src/lib/Sat/cryptominisat2/mtl/Heap.h", + "src/lib/Sat/cryptominisat2/mtl/Map.h", + "src/lib/Sat/cryptominisat2/mtl/Queue.h", + "src/lib/Sat/cryptominisat2/mtl/Vec.h", + "src/lib/Sat/cryptominisat2/OnlyNonLearntBins.cpp", + "src/lib/Sat/cryptominisat2/OnlyNonLearntBins.h", + "src/lib/Sat/cryptominisat2/PackedMatrix.h", + "src/lib/Sat/cryptominisat2/PackedRow.cpp", + "src/lib/Sat/cryptominisat2/PackedRow.h", + "src/lib/Sat/cryptominisat2/PartFinder.cpp", + "src/lib/Sat/cryptominisat2/PartFinder.h", + "src/lib/Sat/cryptominisat2/PartHandler.cpp", + "src/lib/Sat/cryptominisat2/PartHandler.h", + "src/lib/Sat/cryptominisat2/RestartTypeChooser.cpp", + "src/lib/Sat/cryptominisat2/RestartTypeChooser.h", + "src/lib/Sat/cryptominisat2/Solver.cpp", + "src/lib/Sat/cryptominisat2/Solver.h", + "src/lib/Sat/cryptominisat2/SolverTypes.h", + "src/lib/Sat/cryptominisat2/StateSaver.cpp", + "src/lib/Sat/cryptominisat2/StateSaver.h", + "src/lib/Sat/cryptominisat2/Subsumer.cpp", + "src/lib/Sat/cryptominisat2/Subsumer.h", + "src/lib/Sat/cryptominisat2/time_mem.cpp", + "src/lib/Sat/cryptominisat2/time_mem.h", + "src/lib/Sat/cryptominisat2/UselessBinRemover.cpp", + "src/lib/Sat/cryptominisat2/UselessBinRemover.h", + "src/lib/Sat/cryptominisat2/VarReplacer.cpp", + "src/lib/Sat/cryptominisat2/VarReplacer.h", + "src/lib/Sat/cryptominisat2/XorFinder.cpp", + "src/lib/Sat/cryptominisat2/XorFinder.h", + "src/lib/Sat/cryptominisat2/XorSubsumer.cpp", + "src/lib/Sat/cryptominisat2/XorSubsumer.h", + "src/lib/Sat/cryptominisat2/XSet.h", + "src/lib/Sat/CryptoMinisat.cpp", + "src/lib/Sat/MinisatCore.cpp", + "src/lib/Sat/minisat/core/Dimacs.h", + "src/lib/Sat/MinisatCore_prop.cpp", + "src/lib/Sat/minisat/core_prop/Solver_prop.cc", + "src/lib/Sat/minisat/core_prop/Solver_prop.h", + "src/lib/Sat/minisat/core/Solver.cc", + "src/lib/Sat/minisat/core/Solver.h", + "src/lib/Sat/minisat/core/SolverTypes.h", + "src/lib/Sat/minisat/mtl/Alg.h", + "src/lib/Sat/minisat/mtl/Alloc.h", + "src/lib/Sat/minisat/mtl/BasicHeap.h", + "src/lib/Sat/minisat/mtl/BoxedVec.h", + "src/lib/Sat/minisat/mtl/Heap.h", + "src/lib/Sat/minisat/mtl/IntTypesMtl.h", + "src/lib/Sat/minisat/mtl/Map.h", + "src/lib/Sat/minisat/mtl/Queue.h", + "src/lib/Sat/minisat/mtl/Sort.h", + "src/lib/Sat/minisat/mtl/Vec.h", + "src/lib/Sat/minisat/mtl/XAlloc.h", + "src/lib/Sat/minisat/simp/SimpSolver.cc", + "src/lib/Sat/minisat/simp/SimpSolver.h", + "src/lib/Sat/minisat/utils/Options.h", + "src/lib/Sat/minisat/utils/ParseUtils.h", + "src/lib/Sat/minisat/utils/System.cc", + "src/lib/Sat/minisat/utils/System.h", + "src/lib/Sat/SimplifyingMinisat.cpp", + "src/lib/Simplifier/bvsolver.cpp", + "src/lib/Simplifier/constantBitP/ConstantBitP_Arithmetic.cpp", + "src/lib/Simplifier/constantBitP/ConstantBitP_Boolean.cpp", + "src/lib/Simplifier/constantBitP/ConstantBitP_Comparison.cpp", + "src/lib/Simplifier/constantBitP/ConstantBitP_Division.cpp", + "src/lib/Simplifier/constantBitP/ConstantBitP_MaxPrecision.cpp", + "src/lib/Simplifier/constantBitP/ConstantBitP_Multiplication.cpp", + "src/lib/Simplifier/constantBitP/ConstantBitPropagation.cpp", + "src/lib/Simplifier/constantBitP/ConstantBitP_Shifting.cpp", + "src/lib/Simplifier/constantBitP/ConstantBitP_TransferFunctions.cpp", + "src/lib/Simplifier/constantBitP/ConstantBitP_Utility.cpp", + "src/lib/Simplifier/constantBitP/FixedBits.cpp", + "src/lib/Simplifier/consteval.cpp", + "src/lib/Simplifier/MutableASTNode.cpp", + "src/lib/Simplifier/PropagateEqualities.cpp", + "src/lib/Simplifier/RemoveUnconstrained.cpp", + "src/lib/Simplifier/simplifier.cpp", + "src/lib/Simplifier/SubstitutionMap.cpp", + "src/lib/Simplifier/VariablesInExpression.cpp", + "src/lib/STPManager/STP.cpp", + "src/lib/STPManager/STPManager.cpp", + "src/lib/ToSat/AIG/BBNodeManagerAIG.cpp", + "src/lib/ToSat/AIG/ToCNFAIG.cpp", + "src/lib/ToSat/AIG/ToSATAIG.cpp", + "src/lib/ToSat/ASTNode/ClauseList.cpp", + "src/lib/ToSat/ASTNode/SimpBool.cpp", + "src/lib/ToSat/ASTNode/ToCNF.cpp", + "src/lib/ToSat/ASTNode/ToSAT.cpp", + "src/lib/ToSat/BitBlaster.cpp", + "src/lib/ToSat/ToSATBase.cpp", + "$target_gen_dir/src/include/stp/AST/ASTKind.h", + "$target_gen_dir/src/lib/AST/ASTKind.cpp", + "$target_gen_dir/src/lib/Parser/lexcvc.cpp", + "$target_gen_dir/src/lib/Parser/lexsmt.cpp", + "$target_gen_dir/src/lib/Parser/lexsmt2.cpp", + "$target_gen_dir/src/lib/Parser/parsecvc.cpp", + "$target_gen_dir/src/lib/Parser/parsecvc.hpp", + "$target_gen_dir/src/lib/Parser/parsesmt.cpp", + "$target_gen_dir/src/lib/Parser/parsesmt.hpp", + "$target_gen_dir/src/lib/Parser/parsesmt2.cpp", + "$target_gen_dir/src/lib/Parser/parsesmt2.hpp", + ] + + deps = [ + ":generate_astkinds", + ":generate_lexer", + ":generate_parser", + ] +} + +action("generate_astkinds") { + script = "genastkinds.py" + sources = [ + "src/lib/AST/ASTKind.kinds", + ] + inputs = [ + "src/lib/AST/genkinds.pl", + ] + outputs = [ + "$target_gen_dir/src/include/stp/AST/ASTKind.h", + "$target_gen_dir/src/lib/AST/ASTKind.cpp", + ] + args = [ + rebase_path("src/lib/AST/genkinds.pl", root_build_dir), + rebase_path("src/lib/AST/ASTKind.kinds", root_build_dir), + rebase_path(target_gen_dir, root_build_dir), + ] +} + +action_foreach("generate_lexer") { + script = "flex.py" + sources = [ + "src/lib/Parser/cvc.lex", + "src/lib/Parser/smt.lex", + "src/lib/Parser/smt2.lex", + ] + outputs = [ + "{{source_gen_dir}}/lex{{source_name_part}}.cpp", + ] + args = [ + "{{source}}", + "{{source_name_part}}", + "{{source_gen_dir}}/lex{{source_name_part}}", + ] +} + +action_foreach("generate_parser") { + script = "bison.py" + sources = [ + "src/lib/Parser/cvc.y", + "src/lib/Parser/smt.y", + "src/lib/Parser/smt2.y", + ] + outputs = [ + "{{source_gen_dir}}/parse{{source_name_part}}.cpp", + "{{source_gen_dir}}/parse{{source_name_part}}.hpp", + ] + args = [ + "{{source}}", + "{{source_name_part}}", + "{{source_gen_dir}}/parse{{source_name_part}}", + ] +}
diff --git a/third_party/stp/LICENSE b/third_party/stp/LICENSE new file mode 100644 index 0000000..d3d803c --- /dev/null +++ b/third_party/stp/LICENSE
@@ -0,0 +1,331 @@ +/******************************************************************** + * PROGRAM NAME: STP (Simple Theorem Prover) + * + * AUTHORS: Vijay Ganesh + * + * BEGIN DATE: November, 2005 + ********************************************************************/ + +The MIT License + +Copyright (c) 2008 Vijay Ganesh + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +STP links to copyrighted librarys: + * Minisat Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson. + * Bit::Vector Copyright (c) 1995 - 2004 by Steffen Beyer. + * CVC's SMT-LIB Parser Copyright (C) 2004 by the Board of Trustees + of Leland Stanford Junior University and by New York University. + * CryptoMinisat Copyright (c) 2009 Mate Soos + * ABC by Alan Mishchenko + * Boost by various: http://www.boost.org/ + * CryptoMiniSat4 in case it's installed + +MINISAT + MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson + + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + associated documentation files (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, publish, distribute, + sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT + OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Bit::Vector + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, || (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY || FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + || download a copy from ftp://ftp.gnu.org/pub/gnu/COPYING.LIB-2.0 + +CVC's SMT-LIB Parser + \file smtlib.y + + Author: Sergey Berezin, Clark Barrett + + Created: Apr 30 2005 + + Copyright (C) 2004 by the Board of Trustees of Leland Stanford + Junior University and by New York University. + + License to use, copy, modify, sell and/or distribute this software + and its documentation for any purpose is hereby granted without + royalty, subject to the terms and conditions defined in the \ref + LICENSE file provided with this distribution. In particular: + + - The above copyright notice and this permission notice must appear + in all copies of the software and related documentation. + + - THE SOFTWARE IS PROVIDED "AS-IS", WITHOUT ANY WARRANTIES, + EXPRESSED OR IMPLIED. USE IT AT YOUR OWN RISK. + +Cryptominisat2 + CryptoMiniSat -- Copyright (c) 2009 Mate Soos + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Cryptominisat4 + Copyright (c) 2009-2014, Mate Soos. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.0 of the License. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA + +ABC + Copyright (c) The Regents of the University of California. All rights reserved. + + Permission is hereby granted, without written agreement and without license or + royalty fees, to use, copy, modify, and distribute this software and its + documentation for any purpose, provided that the above copyright notice and + the following two paragraphs appear in all copies of this software. + + IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR + DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF + THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF + CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, + AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, + SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +Boost + Boost Software License - Version 1.0 - August 17th, 2003 + + Permission is hereby granted, free of charge, to any person or organization + obtaining a copy of the software and accompanying documentation covered by + this license (the "Software") to use, reproduce, display, distribute, + execute, and transmit the Software, and to prepare derivative works of the + Software, and to permit third-parties to whom the Software is furnished to + do so, all subject to the following: + + The copyright notices in the Software and this entire statement, including + the above license grant, this restriction and the following disclaimer, + must be included in all copies of the Software, in whole or in part, and + all derivative works of the Software, unless such copies or derivative + works are solely in the form of machine-executable object code generated by + a source language processor. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT + SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE + FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + +Windows msc99hdr + Copyright (c) 2006-2008 Alexander Chemeris + Copyright (c) 2000 Jeroen Ruigrok van der Werven <asmodai@FreeBSD.org> + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The name of the author may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +LLVM integration tester (llvm-lit) + University of Illinois/NCSA + Open Source License + + Copyright (c) 2003-2014 University of Illinois at Urbana-Champaign. + All rights reserved. + + Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal with + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished to do + so, subject to the following conditions: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the LLVM Team, University of Illinois at + Urbana-Champaign, nor the names of its contributors may be used to + endorse or promote products derived from this Software without specific + prior written permission. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE + SOFTWARE. + +OutputCheck + Copyright (c) 2014, Daniel Liew All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +GoogleTest framework + Copyright 2008, Google Inc. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +MemoryPool + Copyright (c) 2013 Cosku Acay, http://www.coskuacay.com + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE.
diff --git a/third_party/stp/OWNERS b/third_party/stp/OWNERS new file mode 100644 index 0000000..8f9b21c --- /dev/null +++ b/third_party/stp/OWNERS
@@ -0,0 +1,2 @@ +mdempsky@chromium.org +jln@chromium.org
diff --git a/third_party/stp/README.chromium b/third_party/stp/README.chromium new file mode 100644 index 0000000..46123223 --- /dev/null +++ b/third_party/stp/README.chromium
@@ -0,0 +1,18 @@ +Name: STP Constraint Solver +Short Name: stp +URL: https://sites.google.com/site/stpfastprover +Version: 0 +Date: 2014-11-14 +Revision: fc94a599207752ab4d64048204f0c88494811b62 +License: MIT, LGPL +License File: LICENSE +Security Critical: no + +Description: +STP is a constraint solver (also referred to as a decision procedure +or automated prover) aimed at solving constraints generated by program +analysis tools, theorem provers, automated bug finders, biology, +cryptography, intelligent fuzzers and model checkers. + +Local Modifications: +None.
diff --git a/third_party/stp/README.security b/third_party/stp/README.security new file mode 100644 index 0000000..2f0502f --- /dev/null +++ b/third_party/stp/README.security
@@ -0,0 +1,4 @@ +This code is not considered security critical because it is used only +for unit testing, and is not linked into chrome. + +Contact security@chromium.org before adding new uses.
diff --git a/third_party/stp/bison.py b/third_party/stp/bison.py new file mode 100644 index 0000000..947ea3f4 --- /dev/null +++ b/third_party/stp/bison.py
@@ -0,0 +1,18 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import subprocess +import sys + +(source, name, out,) = sys.argv[1:] + +subprocess.check_call([ + "bison", + "--debug", + "-Wnone", + "-o", out + ".cpp", + "--defines=" + out + ".hpp", + "-p", name, + source, +])
diff --git a/third_party/stp/config/stp/config.h b/third_party/stp/config/stp/config.h new file mode 100644 index 0000000..d1f2fc3f4 --- /dev/null +++ b/third_party/stp/config/stp/config.h
@@ -0,0 +1,50 @@ +/*********** +AUTHORS: Ryan Govostes, Dan Liew + +BEGIN DATE: Sept, 2013 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECT +**********************/ + + +#ifndef _CONFIG_H_ +#define _CONFIG_H_ + +#if __cplusplus + +/* Where to find <hash_set> or <unordered_set>, if available. */ +#define HAVE_HASH_SET 0 +#define HASH_SET_H <unordered_set> +#define HASH_SET_CLASS unordered_set +#define HASH_SET_NAMESPACE std + +/* Where to find <hash_multiset> or <unordered_multiset>, if available. */ +#define HAVE_HASH_MULTISET 0 +#define HASH_MULTISET_H <unordered_set> +#define HASH_MULTISET_CLASS unordered_multiset +#define HASH_MULTISET_NAMESPACE std + +/* Where to find <hash_map> or <unordered_map>, if available. */ +#define HAVE_HASH_MAP 0 +#define HASH_MAP_H <unordered_map> +#define HASH_MAP_CLASS unordered_map +#define HASH_MAP_NAMESPACE std + +#endif + +#endif
diff --git a/third_party/stp/flex.py b/third_party/stp/flex.py new file mode 100644 index 0000000..8eac4e0b --- /dev/null +++ b/third_party/stp/flex.py
@@ -0,0 +1,16 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import subprocess +import sys + +(source, name, out,) = sys.argv[1:] + +subprocess.check_call([ + "flex", + "-Cfe", + "-o", out + ".cpp", + "--prefix=" + name, + source, +])
diff --git a/third_party/stp/genastkinds.py b/third_party/stp/genastkinds.py new file mode 100644 index 0000000..93eb9893 --- /dev/null +++ b/third_party/stp/genastkinds.py
@@ -0,0 +1,17 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import os +import os.path +import subprocess +import sys + +(script, source, out,) = sys.argv[1:] + +subprocess.check_call([ + "perl", script, + "--file", source, +]) +os.rename("ASTKind.cpp", os.path.join(out, "src/lib/AST/ASTKind.cpp")) +os.rename("ASTKind.h", os.path.join(out, "src/include/stp/AST/ASTKind.h"))
diff --git a/third_party/stp/stp.gyp b/third_party/stp/stp.gyp new file mode 100644 index 0000000..e938a02e --- /dev/null +++ b/third_party/stp/stp.gyp
@@ -0,0 +1,415 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +{ + 'variables': { + 'shared_generated_dir': '<(SHARED_INTERMEDIATE_DIR)/third_party/stp', + }, + 'targets': [ + { + 'target_name': 'stp', + 'type': '<(component)', + 'cflags': [ + '-U_DEBUG', + '-Wno-dangling-else', + '-Wno-empty-body', + '-Wno-header-guard', + '-Wno-implicit-function-declaration', + '-Wno-mismatched-tags', + '-Wno-overloaded-virtual', + '-Wno-parentheses-equality', + '-Wno-return-type', + '-Wno-sign-compare', + '-Wno-sometimes-uninitialized', + '-Wno-string-conversion', + '-Wno-tautological-constant-out-of-range-compare', + '-Wno-unused-const-variable', + '-Wno-unused-function', + '-Wno-unused-private-field', + ], + 'cflags_cc': [ + '-fexceptions', + ], + 'direct_dependent_settings': { + 'include_dirs': [ + 'src/include', + ], + }, + 'include_dirs': [ + 'config', + 'src/include', + 'src/lib', + 'src/lib/Sat', + 'src/lib/Sat/cryptominisat2/mtl', + 'src/lib/extlib-abc', + '<(shared_generated_dir)/src/include', + ], + 'sources': [ + 'config/stp/config.h', + 'src/include/stp/AbsRefineCounterExample/AbsRefine_CounterExample.h', + 'src/include/stp/AST/ArrayTransformer.h', + 'src/include/stp/AST/ASTBVConst.h', + 'src/include/stp/AST/AST.h', + 'src/include/stp/AST/ASTInterior.h', + 'src/include/stp/AST/ASTInternal.h', + 'src/include/stp/AST/ASTInternalWithChildren.h', + 'src/include/stp/AST/ASTNode.h', + 'src/include/stp/AST/ASTSymbol.h', + 'src/include/stp/AST/NodeFactory/HashingNodeFactory.h', + 'src/include/stp/AST/NodeFactory/NodeFactory.h', + 'src/include/stp/AST/NodeFactory/SimplifyingNodeFactory.h', + 'src/include/stp/AST/NodeFactory/TypeChecker.h', + 'src/include/stp/AST/RunTimes.h', + 'src/include/stp/AST/STLport_config.h', + 'src/include/stp/AST/UsefulDefs.h', + 'src/include/stp/c_interface.h', + 'src/include/stp/cpp_interface.h', + 'src/include/stp/Globals/Globals.h', + 'src/include/stp/Interface/fdstream.h', + 'src/include/stp/Parser/LetMgr.h', + 'src/include/stp/Parser/parser.h', + 'src/include/stp/Printer/AssortedPrinters.h', + 'src/include/stp/Printer/printers.h', + 'src/include/stp/Printer/SMTLIBPrinter.h', + 'src/include/stp/Sat/CryptoMinisat.h', + 'src/include/stp/Sat/MinisatCore.h', + 'src/include/stp/Sat/MinisatCore_prop.h', + 'src/include/stp/Sat/SATSolver.h', + 'src/include/stp/Sat/SimplifyingMinisat.h', + 'src/include/stp/Simplifier/AIGSimplifyPropositionalCore.h', + 'src/include/stp/Simplifier/AlwaysTrue.h', + 'src/include/stp/Simplifier/bvsolver.h', + 'src/include/stp/Simplifier/constantBitP/ConstantBitP_MaxPrecision.h', + 'src/include/stp/Simplifier/constantBitP/ConstantBitPropagation.h', + 'src/include/stp/Simplifier/constantBitP/ConstantBitP_TransferFunctions.h', + 'src/include/stp/Simplifier/constantBitP/ConstantBitP_Utility.h', + 'src/include/stp/Simplifier/constantBitP/Dependencies.h', + 'src/include/stp/Simplifier/constantBitP/FixedBits.h', + 'src/include/stp/Simplifier/constantBitP/MersenneTwister.h', + 'src/include/stp/Simplifier/constantBitP/multiplication/ColumnCounts.h', + 'src/include/stp/Simplifier/constantBitP/multiplication/ColumnStats.h', + 'src/include/stp/Simplifier/constantBitP/MultiplicationStats.h', + 'src/include/stp/Simplifier/constantBitP/NodeToFixedBitsMap.h', + 'src/include/stp/Simplifier/constantBitP/WorkList.h', + 'src/include/stp/Simplifier/EstablishIntervals.h', + 'src/include/stp/Simplifier/FindPureLiterals.h', + 'src/include/stp/Simplifier/MutableASTNode.h', + 'src/include/stp/Simplifier/PropagateEqualities.h', + 'src/include/stp/Simplifier/RemoveUnconstrained.h', + 'src/include/stp/Simplifier/simplifier.h', + 'src/include/stp/Simplifier/SubstitutionMap.h', + 'src/include/stp/Simplifier/Symbols.h', + 'src/include/stp/Simplifier/UseITEContext.h', + 'src/include/stp/Simplifier/VariablesInExpression.h', + 'src/include/stp/STPManager/DifficultyScore.h', + 'src/include/stp/STPManager/NodeIterator.h', + 'src/include/stp/STPManager/STP.h', + 'src/include/stp/STPManager/STPManager.h', + 'src/include/stp/STPManager/UserDefinedFlags.h', + 'src/include/stp/ToSat/AIG/BBNodeAIG.h', + 'src/include/stp/ToSat/AIG/BBNodeManagerAIG.h', + 'src/include/stp/ToSat/AIG/ToCNFAIG.h', + 'src/include/stp/ToSat/AIG/ToSATAIG.h', + 'src/include/stp/ToSat/ASTNode/BBNodeManagerASTNode.h', + 'src/include/stp/ToSat/ASTNode/ClauseList.h', + 'src/include/stp/ToSat/ASTNode/ToCNF.h', + 'src/include/stp/ToSat/ASTNode/ToSAT.h', + 'src/include/stp/ToSat/BitBlaster.h', + 'src/include/stp/ToSat/ToSATBase.h', + 'src/lib/AbsRefineCounterExample/AbstractionRefinement.cpp', + 'src/lib/AbsRefineCounterExample/CounterExample.cpp', + 'src/lib/AST/ArrayTransformer.cpp', + 'src/lib/AST/ASTBVConst.cpp', + 'src/lib/AST/ASTInterior.cpp', + 'src/lib/AST/ASTmisc.cpp', + 'src/lib/AST/ASTNode.cpp', + 'src/lib/AST/ASTSymbol.cpp', + 'src/lib/AST/ASTUtil.cpp', + 'src/lib/AST/NodeFactory/HashingNodeFactory.cpp', + 'src/lib/AST/NodeFactory/NodeFactory.cpp', + 'src/lib/AST/NodeFactory/SimplifyingNodeFactory.cpp', + 'src/lib/AST/NodeFactory/TypeChecker.cpp', + 'src/lib/AST/RunTimes.cpp', + 'src/lib/extlib-abc/aig/aig/aigCheck.c', + 'src/lib/extlib-abc/aig/aig/aigDfs.c', + 'src/lib/extlib-abc/aig/aig/aigFanout.c', + 'src/lib/extlib-abc/aig/aig/aigMan.c', + 'src/lib/extlib-abc/aig/aig/aigMem.c', + 'src/lib/extlib-abc/aig/aig/aigMffc.c', + 'src/lib/extlib-abc/aig/aig/aigObj.c', + 'src/lib/extlib-abc/aig/aig/aigOper.c', + 'src/lib/extlib-abc/aig/aig/aigOrder.c', + 'src/lib/extlib-abc/aig/aig/aigPart.c', + 'src/lib/extlib-abc/aig/aig/aigRepr.c', + 'src/lib/extlib-abc/aig/aig/aigRet.c', + 'src/lib/extlib-abc/aig/aig/aigScl.c', + 'src/lib/extlib-abc/aig/aig/aigSeq.c', + 'src/lib/extlib-abc/aig/aig/aigShow.c', + 'src/lib/extlib-abc/aig/aig/aigTable.c', + 'src/lib/extlib-abc/aig/aig/aigTime.c', + 'src/lib/extlib-abc/aig/aig/aigTiming.c', + 'src/lib/extlib-abc/aig/aig/aigTruth.c', + 'src/lib/extlib-abc/aig/aig/aigTsim.c', + 'src/lib/extlib-abc/aig/aig/aigUtil.c', + 'src/lib/extlib-abc/aig/aig/aigWin.c', + 'src/lib/extlib-abc/aig/cnf/cnfCore.c', + 'src/lib/extlib-abc/aig/cnf/cnfCut.c', + 'src/lib/extlib-abc/aig/cnf/cnfData.c', + 'src/lib/extlib-abc/aig/cnf/cnfMan.c', + 'src/lib/extlib-abc/aig/cnf/cnfMap.c', + 'src/lib/extlib-abc/aig/cnf/cnfPost.c', + 'src/lib/extlib-abc/aig/cnf/cnfUtil.c', + 'src/lib/extlib-abc/aig/cnf/cnfWrite.c', + 'src/lib/extlib-abc/aig/dar/darBalance.c', + 'src/lib/extlib-abc/aig/dar/darCore.c', + 'src/lib/extlib-abc/aig/dar/darCut.c', + 'src/lib/extlib-abc/aig/dar/darData.c', + 'src/lib/extlib-abc/aig/dar/darLib.c', + 'src/lib/extlib-abc/aig/dar/darMan.c', + 'src/lib/extlib-abc/aig/dar/darPrec.c', + 'src/lib/extlib-abc/aig/dar/darRefact.c', + 'src/lib/extlib-abc/aig/dar/darScript.c', + 'src/lib/extlib-abc/aig.h', + 'src/lib/extlib-abc/aig/kit/kitAig.c', + 'src/lib/extlib-abc/aig/kit/kitGraph.c', + 'src/lib/extlib-abc/aig/kit/kitIsop.c', + 'src/lib/extlib-abc/aig/kit/kitSop.c', + 'src/lib/extlib-abc/aig/kit/kitTruth.c', + 'src/lib/extlib-abc/cnf.h', + 'src/lib/extlib-abc/cnf_short.h', + 'src/lib/extlib-abc/dar.h', + 'src/lib/extlib-abc/darInt.h', + 'src/lib/extlib-abc/kit.h', + 'src/lib/extlib-abc/leaks.h', + 'src/lib/extlib-abc/vecFlt.h', + 'src/lib/extlib-abc/vec.h', + 'src/lib/extlib-abc/vecInt.h', + 'src/lib/extlib-abc/vecPtr.h', + 'src/lib/extlib-abc/vecStr.h', + 'src/lib/extlib-abc/vecVec.h', + 'src/lib/extlib-constbv/constantbv.cpp', + 'src/lib/extlib-constbv/constantbv.h', + 'src/lib/Globals/Globals.cpp', + 'src/lib/Interface/c_interface.cpp', + 'src/lib/Interface/cpp_interface.cpp', + 'src/lib/Parser/LetMgr.cpp', + 'src/lib/Printer/AssortedPrinters.cpp', + 'src/lib/Printer/BenchPrinter.cpp', + 'src/lib/Printer/CPrinter.cpp', + 'src/lib/Printer/dotPrinter.cpp', + 'src/lib/Printer/GDLPrinter.cpp', + 'src/lib/Printer/LispPrinter.cpp', + 'src/lib/Printer/PLPrinter.cpp', + 'src/lib/Printer/SMTLIB1Printer.cpp', + 'src/lib/Printer/SMTLIB2Printer.cpp', + 'src/lib/Printer/SMTLIBPrinter.cpp', + 'src/lib/Sat/cryptominisat2/BitArray.h', + 'src/lib/Sat/cryptominisat2/BoundedQueue.h', + 'src/lib/Sat/cryptominisat2/ClauseAllocator.cpp', + 'src/lib/Sat/cryptominisat2/ClauseAllocator.h', + 'src/lib/Sat/cryptominisat2/ClauseCleaner.cpp', + 'src/lib/Sat/cryptominisat2/ClauseCleaner.h', + 'src/lib/Sat/cryptominisat2/Clause.h', + 'src/lib/Sat/cryptominisat2/constants.h', + 'src/lib/Sat/cryptominisat2/CSet.h', + 'src/lib/Sat/cryptominisat2/FailedVarSearcher.cpp', + 'src/lib/Sat/cryptominisat2/FailedVarSearcher.h', + 'src/lib/Sat/cryptominisat2/FindUndef.cpp', + 'src/lib/Sat/cryptominisat2/FindUndef.h', + 'src/lib/Sat/cryptominisat2/GaussianConfig.h', + 'src/lib/Sat/cryptominisat2/Gaussian.cpp', + 'src/lib/Sat/cryptominisat2/Gaussian.h', + 'src/lib/Sat/cryptominisat2/Logger.cpp', + 'src/lib/Sat/cryptominisat2/Logger.h', + 'src/lib/Sat/cryptominisat2/MatrixFinder.cpp', + 'src/lib/Sat/cryptominisat2/MatrixFinder.h', + 'src/lib/Sat/cryptominisat2/MemoryPool/MemoryPool.h', + 'src/lib/Sat/cryptominisat2/MemoryPool/MemoryPool.tcc', + 'src/lib/Sat/cryptominisat2/MersenneTwister.h', + 'src/lib/Sat/cryptominisat2/msvc/stdint.h', + 'src/lib/Sat/cryptominisat2/mtl/Alg.h', + 'src/lib/Sat/cryptominisat2/mtl/BasicHeap.h', + 'src/lib/Sat/cryptominisat2/mtl/BoxedVec.h', + 'src/lib/Sat/cryptominisat2/mtl/Heap.h', + 'src/lib/Sat/cryptominisat2/mtl/Map.h', + 'src/lib/Sat/cryptominisat2/mtl/Queue.h', + 'src/lib/Sat/cryptominisat2/mtl/Vec.h', + 'src/lib/Sat/cryptominisat2/OnlyNonLearntBins.cpp', + 'src/lib/Sat/cryptominisat2/OnlyNonLearntBins.h', + 'src/lib/Sat/cryptominisat2/PackedMatrix.h', + 'src/lib/Sat/cryptominisat2/PackedRow.cpp', + 'src/lib/Sat/cryptominisat2/PackedRow.h', + 'src/lib/Sat/cryptominisat2/PartFinder.cpp', + 'src/lib/Sat/cryptominisat2/PartFinder.h', + 'src/lib/Sat/cryptominisat2/PartHandler.cpp', + 'src/lib/Sat/cryptominisat2/PartHandler.h', + 'src/lib/Sat/cryptominisat2/RestartTypeChooser.cpp', + 'src/lib/Sat/cryptominisat2/RestartTypeChooser.h', + 'src/lib/Sat/cryptominisat2/Solver.cpp', + 'src/lib/Sat/cryptominisat2/Solver.h', + 'src/lib/Sat/cryptominisat2/SolverTypes.h', + 'src/lib/Sat/cryptominisat2/StateSaver.cpp', + 'src/lib/Sat/cryptominisat2/StateSaver.h', + 'src/lib/Sat/cryptominisat2/Subsumer.cpp', + 'src/lib/Sat/cryptominisat2/Subsumer.h', + 'src/lib/Sat/cryptominisat2/time_mem.cpp', + 'src/lib/Sat/cryptominisat2/time_mem.h', + 'src/lib/Sat/cryptominisat2/UselessBinRemover.cpp', + 'src/lib/Sat/cryptominisat2/UselessBinRemover.h', + 'src/lib/Sat/cryptominisat2/VarReplacer.cpp', + 'src/lib/Sat/cryptominisat2/VarReplacer.h', + 'src/lib/Sat/cryptominisat2/XorFinder.cpp', + 'src/lib/Sat/cryptominisat2/XorFinder.h', + 'src/lib/Sat/cryptominisat2/XorSubsumer.cpp', + 'src/lib/Sat/cryptominisat2/XorSubsumer.h', + 'src/lib/Sat/cryptominisat2/XSet.h', + 'src/lib/Sat/CryptoMinisat.cpp', + 'src/lib/Sat/MinisatCore.cpp', + 'src/lib/Sat/minisat/core/Dimacs.h', + 'src/lib/Sat/MinisatCore_prop.cpp', + 'src/lib/Sat/minisat/core_prop/Solver_prop.cc', + 'src/lib/Sat/minisat/core_prop/Solver_prop.h', + 'src/lib/Sat/minisat/core/Solver.cc', + 'src/lib/Sat/minisat/core/Solver.h', + 'src/lib/Sat/minisat/core/SolverTypes.h', + 'src/lib/Sat/minisat/mtl/Alg.h', + 'src/lib/Sat/minisat/mtl/Alloc.h', + 'src/lib/Sat/minisat/mtl/BasicHeap.h', + 'src/lib/Sat/minisat/mtl/BoxedVec.h', + 'src/lib/Sat/minisat/mtl/Heap.h', + 'src/lib/Sat/minisat/mtl/IntTypesMtl.h', + 'src/lib/Sat/minisat/mtl/Map.h', + 'src/lib/Sat/minisat/mtl/Queue.h', + 'src/lib/Sat/minisat/mtl/Sort.h', + 'src/lib/Sat/minisat/mtl/Vec.h', + 'src/lib/Sat/minisat/mtl/XAlloc.h', + 'src/lib/Sat/minisat/simp/SimpSolver.cc', + 'src/lib/Sat/minisat/simp/SimpSolver.h', + 'src/lib/Sat/minisat/utils/Options.h', + 'src/lib/Sat/minisat/utils/ParseUtils.h', + 'src/lib/Sat/minisat/utils/System.cc', + 'src/lib/Sat/minisat/utils/System.h', + 'src/lib/Sat/SimplifyingMinisat.cpp', + 'src/lib/Simplifier/bvsolver.cpp', + 'src/lib/Simplifier/constantBitP/ConstantBitP_Arithmetic.cpp', + 'src/lib/Simplifier/constantBitP/ConstantBitP_Boolean.cpp', + 'src/lib/Simplifier/constantBitP/ConstantBitP_Comparison.cpp', + 'src/lib/Simplifier/constantBitP/ConstantBitP_Division.cpp', + 'src/lib/Simplifier/constantBitP/ConstantBitP_MaxPrecision.cpp', + 'src/lib/Simplifier/constantBitP/ConstantBitP_Multiplication.cpp', + 'src/lib/Simplifier/constantBitP/ConstantBitPropagation.cpp', + 'src/lib/Simplifier/constantBitP/ConstantBitP_Shifting.cpp', + 'src/lib/Simplifier/constantBitP/ConstantBitP_TransferFunctions.cpp', + 'src/lib/Simplifier/constantBitP/ConstantBitP_Utility.cpp', + 'src/lib/Simplifier/constantBitP/FixedBits.cpp', + 'src/lib/Simplifier/consteval.cpp', + 'src/lib/Simplifier/MutableASTNode.cpp', + 'src/lib/Simplifier/PropagateEqualities.cpp', + 'src/lib/Simplifier/RemoveUnconstrained.cpp', + 'src/lib/Simplifier/simplifier.cpp', + 'src/lib/Simplifier/SubstitutionMap.cpp', + 'src/lib/Simplifier/VariablesInExpression.cpp', + 'src/lib/STPManager/STP.cpp', + 'src/lib/STPManager/STPManager.cpp', + 'src/lib/ToSat/AIG/BBNodeManagerAIG.cpp', + 'src/lib/ToSat/AIG/ToCNFAIG.cpp', + 'src/lib/ToSat/AIG/ToSATAIG.cpp', + 'src/lib/ToSat/ASTNode/ClauseList.cpp', + 'src/lib/ToSat/ASTNode/SimpBool.cpp', + 'src/lib/ToSat/ASTNode/ToCNF.cpp', + 'src/lib/ToSat/ASTNode/ToSAT.cpp', + 'src/lib/ToSat/BitBlaster.cpp', + 'src/lib/ToSat/ToSATBase.cpp', + '<(shared_generated_dir)/src/include/stp/AST/ASTKind.h', + '<(shared_generated_dir)/src/lib/AST/ASTKind.cpp', + '<(shared_generated_dir)/src/lib/Parser/lexcvc.cpp', + '<(shared_generated_dir)/src/lib/Parser/lexsmt.cpp', + '<(shared_generated_dir)/src/lib/Parser/lexsmt2.cpp', + '<(shared_generated_dir)/src/lib/Parser/parsecvc.cpp', + '<(shared_generated_dir)/src/lib/Parser/parsecvc.hpp', + '<(shared_generated_dir)/src/lib/Parser/parsesmt.cpp', + '<(shared_generated_dir)/src/lib/Parser/parsesmt.hpp', + '<(shared_generated_dir)/src/lib/Parser/parsesmt2.cpp', + '<(shared_generated_dir)/src/lib/Parser/parsesmt2.hpp', + ], + 'dependencies': [ + 'stp_generated_sources', + ], + }, + { + 'target_name': 'stp_generated_sources', + 'type': 'none', + 'sources': [ + 'src/lib/AST/ASTKind.kinds', + 'src/lib/Parser/cvc.lex', + 'src/lib/Parser/cvc.y', + 'src/lib/Parser/smt.lex', + 'src/lib/Parser/smt.y', + 'src/lib/Parser/smt2.lex', + 'src/lib/Parser/smt2.y', + ], + 'actions': [ + { + 'action_name': 'generate_astkind', + 'inputs': [ + 'genastkinds.py', + 'src/lib/AST/ASTKind.kinds', + 'src/lib/AST/genkinds.pl', + ], + 'outputs': [ + '<(shared_generated_dir)/src/include/stp/AST/ASTKind.h', + '<(shared_generated_dir)/src/lib/AST/ASTKind.cpp', + ], + 'action': [ + 'python', + 'genastkinds.py', + 'src/lib/AST/genkinds.pl', + 'src/lib/AST/ASTKind.kinds', + '<(shared_generated_dir)', + ], + 'message': 'Generating ASTKind ...', + }, + ], + 'rules': [ + { + 'rule_name': 'generate_flex', + 'extension': '.lex', + 'inputs': [ + 'flex.py', + ], + 'outputs': [ + '<(shared_generated_dir)/<(RULE_INPUT_DIRNAME)/lex<(RULE_INPUT_ROOT).cpp', + ], + 'action': [ + 'python', + 'flex.py', + '<(RULE_INPUT_PATH)', + '<(RULE_INPUT_ROOT)', + '<(shared_generated_dir)/<(RULE_INPUT_DIRNAME)/lex<(RULE_INPUT_ROOT)', + ], + 'message': 'Generating <(RULE_INPUT_ROOT) lexer ...', + }, + { + 'rule_name': 'generate_bison', + 'extension': '.y', + 'inputs': [ + 'bison.py', + ], + 'outputs': [ + '<(shared_generated_dir)/<(RULE_INPUT_DIRNAME)/parse<(RULE_INPUT_ROOT).cpp', + '<(shared_generated_dir)/<(RULE_INPUT_DIRNAME)/parse<(RULE_INPUT_ROOT).hpp', + ], + 'action': [ + 'python', + 'bison.py', + '<(RULE_INPUT_PATH)', + '<(RULE_INPUT_ROOT)', + '<(shared_generated_dir)/<(RULE_INPUT_DIRNAME)/parse<(RULE_INPUT_ROOT)', + ], + 'message': 'Generating <(RULE_INPUT_ROOT) parser ...', + }, + ], + }, + ], +}
diff --git a/tools/auto_bisect/bisect_perf_regression.py b/tools/auto_bisect/bisect_perf_regression.py index 9a579d9..8ba9ca9 100755 --- a/tools/auto_bisect/bisect_perf_regression.py +++ b/tools/auto_bisect/bisect_perf_regression.py
@@ -495,14 +495,15 @@ """ error = False # Adding good and bad values to a parameter list. - confidenceParams = [] + confidence_params = [] for l in [known_bad_value['values'], known_good_value['values']]: - # Flatten if needed + # Flatten if needed, by averaging the values in each nested list if isinstance(l, list) and all([isinstance(x, list) for x in l]): - confidenceParams.append(sum(l, [])) + averages = map(math_utils.Mean, l) + confidence_params.append(averages) else: - confidenceParams.append(l) - regression_confidence = BisectResults.ConfidenceScore(*confidenceParams) + confidence_params.append(l) + regression_confidence = BisectResults.ConfidenceScore(*confidence_params) if regression_confidence < REGRESSION_CONFIDENCE: error = REGRESSION_CONFIDENCE_ERROR_TEMPLATE.format( good_rev=good_revision,
diff --git a/tools/auto_bisect/bisect_perf_regression_test.py b/tools/auto_bisect/bisect_perf_regression_test.py index 14e4706..86f1b562 100644 --- a/tools/auto_bisect/bisect_perf_regression_test.py +++ b/tools/auto_bisect/bisect_perf_regression_test.py
@@ -60,6 +60,51 @@ [30.592], [30.72], [34.486], [35.247], [35.253], [35.335], [35.378], [35.934], [36.233], [36.41], [36.947], [37.982]] ] + +# Regression confidence > 95%, taken from: crbug.com/434318 +# Specifically from Builder android_nexus10_perf_bisect Build #1198 +MULTIPLE_VALUES = [ + [ + [18.916000,22.371000,8.527000,5.877000,5.407000,9.476000,8.100000, + 5.334000,4.507000,4.842000,8.485000,8.308000,27.490000,4.560000, + 4.804000,23.068000,17.577000,17.346000,26.738000,60.330000,32.307000, + 5.468000,27.803000,27.373000,17.823000,5.158000,27.439000,5.236000, + 11.413000 + ], + [18.999000,22.642000,8.158000,5.995000,5.495000,9.499000,8.092000, + 5.324000,4.468000,4.788000,8.248000,7.853000,27.533000,4.410000, + 4.622000,22.341000,22.313000,17.072000,26.731000,57.513000,33.001000, + 5.500000,28.297000,27.277000,26.462000,5.009000,27.361000,5.130000, + 10.955000 + ] + ], + [ + [18.238000,22.365000,8.555000,5.939000,5.437000,9.463000,7.047000, + 5.345000,4.517000,4.796000,8.593000,7.901000,27.499000,4.378000, + 5.040000,4.904000,4.816000,4.828000,4.853000,57.363000,34.184000, + 5.482000,28.190000,27.290000,26.694000,5.099000,4.905000,5.290000, + 4.813000 + ], + [18.301000,22.522000,8.035000,6.021000,5.565000,9.037000,6.998000, + 5.321000,4.485000,4.768000,8.397000,7.865000,27.636000,4.640000, + 5.015000,4.962000,4.933000,4.977000,4.961000,60.648000,34.593000, + 5.538000,28.454000,27.297000,26.490000,5.099000,5,5.247000,4.945000 + ], + [18.907000,23.368000,8.100000,6.169000,5.621000,9.971000,8.161000, + 5.331000,4.513000,4.837000,8.255000,7.852000,26.209000,4.388000, + 5.045000,5.029000,5.032000,4.946000,4.973000,60.334000,33.377000, + 5.499000,28.275000,27.550000,26.103000,5.108000,4.951000,5.285000, + 4.910000 + ], + [18.715000,23.748000,8.128000,6.148000,5.691000,9.361000,8.106000, + 5.334000,4.528000,4.965000,8.261000,7.851000,27.282000,4.391000, + 4.949000,4.981000,4.964000,4.935000,4.933000,60.231000,33.361000, + 5.489000,28.106000,27.457000,26.648000,5.108000,4.963000,5.272000, + 4.954000 + ] + ] +] + # Default options for the dry run DEFAULT_OPTIONS = { 'debug_ignore_build': True, @@ -336,6 +381,10 @@ with self.assertRaises(StopIteration): _GenericDryRun(_GetExtendedOptions(0, 0, False)) + _MockResultsGenerator = (rs for rs in MULTIPLE_VALUES) + with self.assertRaises(StopIteration): + _GenericDryRun(_GetExtendedOptions(0, 0, False)) + def testGetCommitPosition(self): cp_git_rev = '7017a81991de983e12ab50dfc071c70e06979531' self.assertEqual(291765, source_control.GetCommitPosition(cp_git_rev))
diff --git a/tools/auto_bisect/bisect_utils.py b/tools/auto_bisect/bisect_utils.py index 99e1cb2..874dbcb 100644 --- a/tools/auto_bisect/bisect_utils.py +++ b/tools/auto_bisect/bisect_utils.py
@@ -483,7 +483,8 @@ # On Windows, use shell=True to get PATH interpretation. shell = IsWindowsHost() - proc = subprocess.Popen(command, shell=shell, stdout=subprocess.PIPE) + proc = subprocess.Popen(command, shell=shell, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) (output, _) = proc.communicate() if cwd:
diff --git a/tools/bisect-builds.py b/tools/bisect-builds.py index 060e0f5c..5273725 100755 --- a/tools/bisect-builds.py +++ b/tools/bisect-builds.py
@@ -32,6 +32,12 @@ # URL template for viewing changelogs between revisions. CHANGELOG_URL = ('https://chromium.googlesource.com/chromium/src/+log/%s..%s') +# GS bucket name for android unsigned official builds. +ANDROID_BUCKET_NAME = 'chrome-unsigned/android-C4MPAR1' + +# The base URL for android official builds. +ANDROID_OFFICIAL_BASE_URL = 'http://%s/%s' % (GOOGLE_APIS_URL, ANDROID_BUCKET_NAME) + # URL to convert SVN revision to git hash. CRREV_URL = ('https://cr-rev.appspot.com/_ah/api/crrev/v1/redirect/') @@ -85,6 +91,15 @@ CREDENTIAL_ERROR_MESSAGE = ('You are attempting to access protected data with ' 'no configured credentials') +# Package name needed to uninstall chrome from Android devices. +ANDROID_CHROME_PACKAGE_NAME = { + 'Chrome.apk': 'com.google.android.apps.chrome', + 'ChromeBeta.apk': 'com.chrome.beta', + 'ChromeCanary.apk': 'com.chrome.canary', + 'ChromeDev.apk': 'com.google.android.apps.chrome_dev', + 'ChromeStable.apk': 'com.android.chrome', +} + ############################################################################### import httplib @@ -109,7 +124,7 @@ paths when dealing with the storage server and archives.""" def __init__(self, base_url, platform, good_revision, bad_revision, is_official, is_asan, use_local_repo, flash_path = None, - pdf_path = None): + pdf_path = None, android_apk = None): super(PathContext, self).__init__() # Store off the input parameters. self.base_url = base_url @@ -126,7 +141,8 @@ # the build. self.githash_svn_dict = {} self.pdf_path = pdf_path - + # android_apk defaults to Chrome.apk + self.android_apk = android_apk if android_apk else 'Chrome.apk' # The name of the ZIP file in a revision directory on the server. self.archive_name = None @@ -136,6 +152,9 @@ # revision number. self.use_local_repo = use_local_repo + # If the script is being used for android builds. + self.android = self.platform.startswith('android') + # Set some internal members: # _listing_platform_dir = Directory that holds revisions. Ends with a '/'. # _archive_extract_dir = Uncompressed directory in the archive_name file. @@ -149,6 +168,8 @@ self.archive_name = 'chrome-win32.zip' self._archive_extract_dir = 'chrome-win32' self._binary_name = 'chrome.exe' + elif self.android: + pass else: raise Exception('Invalid platform: %s' % self.platform) @@ -175,6 +196,18 @@ self._listing_platform_dir = 'win64/' self.archive_name = 'chrome-win64.zip' self._archive_extract_dir = 'chrome-win64' + elif self.platform == 'android-arm': + self._listing_platform_dir = 'arm/' + self.archive_name = self.android_apk + elif self.platform == 'android-arm-64': + self._listing_platform_dir = 'arm_64/' + self.archive_name = self.android_apk + elif self.platform == 'android-x86': + self._listing_platform_dir = 'x86/' + self.archive_name = self.android_apk + elif self.platform == 'android-x64-64': + self._listing_platform_dir = 'x86_64/' + self.archive_name = self.android_apk else: if self.platform in ('linux', 'linux64', 'linux-arm'): self.archive_name = 'chrome-linux.zip' @@ -219,8 +252,12 @@ ASAN_BASE_URL, self.GetASANPlatformDir(), self.build_type, self.GetASANBaseName(), revision) if self.is_official: + if self.android: + official_base_url = ANDROID_OFFICIAL_BASE_URL + else: + official_base_url = OFFICIAL_BASE_URL return '%s/%s/%s%s' % ( - OFFICIAL_BASE_URL, revision, self._listing_platform_dir, + official_base_url, revision, self._listing_platform_dir, self.archive_name) else: if str(revision) in self.githash_svn_dict: @@ -465,7 +502,11 @@ # Download the revlist and filter for just the range between good and bad. minrev = min(self.good_revision, self.bad_revision) maxrev = max(self.good_revision, self.bad_revision) - build_numbers = GsutilList(GS_BUCKET_NAME) + if self.android: + gs_bucket_name = ANDROID_BUCKET_NAME + else: + gs_bucket_name = GS_BUCKET_NAME + build_numbers = GsutilList(gs_bucket_name) revision_re = re.compile(r'(\d\d\.\d\.\d{4}\.\d+)') build_numbers = filter(lambda b: revision_re.search(b), build_numbers) final_list = [] @@ -476,7 +517,7 @@ break if build_number < minrev: continue - path = ('/' + GS_BUCKET_NAME + '/' + str(build_number) + '/' + + path = ('/' + gs_bucket_name + '/' + str(build_number) + '/' + self._listing_platform_dir + self.archive_name) connection.request('HEAD', path) response = connection.getresponse() @@ -549,10 +590,56 @@ pass +def IsADBInstalled(): + """Checks if ADB is in the environment path.""" + try: + adb_output = subprocess.check_output(['adb', 'version']) + return ('Android Debug Bridge' in adb_output) + except OSError: + return False + + +def GetAndroidDeviceList(): + """Returns the list of Android devices attached to the host machine.""" + lines = subprocess.check_output(['adb', 'devices']).split('\n')[1:] + devices = [] + for line in lines: + m = re.match('^(.*?)\s+device$', line) + if not m: + continue + devices.append(m.group(1)) + return devices + + +def RunAndroidRevision(context, revision, apk_file): + """Given a Chrome apk, install it on a local device, and launch Chrome.""" + devices = GetAndroidDeviceList() + if len(devices) is not 1: + sys.exit('Please have 1 Android device plugged in. %d devices found' + % len(devices)) + + devnull = open(os.devnull, 'w') + package_name = ANDROID_CHROME_PACKAGE_NAME[context.android_apk] + + print 'Installing new Chrome version...' + subprocess.call(['adb', 'install', '-r', '-d', apk_file], + stdout=devnull, stderr=devnull) + + print 'Launching Chrome...\n' + subprocess.call(['adb', 'shell', 'am', 'start', '-a', + 'android.intent.action.VIEW', '-n', package_name + + '/com.google.android.apps.chrome.Main'], stdout=devnull, stderr=devnull) + + def RunRevision(context, revision, zip_file, profile, num_runs, command, args): """Given a zipped revision, unzip it and run the test.""" print 'Trying revision %s...' % str(revision) + if context.android: + RunAndroidRevision(context, revision, zip_file) + # TODO(mikecase): Support running command to auto-bisect Android. + return (None, None, None) + # Create a temp directory and unzip the revision into it. cwd = os.getcwd() tempdir = tempfile.mkdtemp(prefix='bisect_tmp') @@ -999,8 +1086,11 @@ 'Tip: add "-- --no-first-run" to bypass the first run prompts.') parser = optparse.OptionParser(usage=usage) # Strangely, the default help output doesn't include the choice list. - choices = ['mac', 'mac64', 'win', 'win64', 'linux', 'linux64', 'linux-arm'] + choices = ['mac', 'mac64', 'win', 'win64', 'linux', 'linux64', 'linux-arm', + 'android-arm', 'android-arm-64', 'android-x86', 'android-x86-64'] # linux-chromiumos lacks a continuous archive http://crbug.com/78158 + apk_choices = ['Chrome.apk', 'ChromeBeta.apk', 'ChromeCanary.apk', + 'ChromeDev.apk', 'ChromeStable.apk'] parser.add_option('-a', '--archive', choices=choices, help='The buildbot archive to bisect [%s].' % @@ -1071,6 +1161,16 @@ help='Allow the script to convert git SHA1 to SVN ' 'revision using "git svn find-rev <SHA1>" ' 'command from a Chromium checkout.') + parser.add_option('--adb-path', + dest='adb_path', + help='Absolute path to adb. If you do not have adb in your ' + 'enviroment PATH and want to bisect Android then ' + 'you need to specify the path here.') + parser.add_option('--apk', + dest='apk', + choices=apk_choices, + help='Name of apk you want to bisect. [%s]' % + '|'.join(apk_choices)) (opts, args) = parser.parse_args() @@ -1100,7 +1200,21 @@ # Create the context. Initialize 0 for the revisions as they are set below. context = PathContext(base_url, opts.archive, opts.good, opts.bad, opts.official_builds, opts.asan, opts.use_local_repo, - opts.flash_path, opts.pdf_path) + opts.flash_path, opts.pdf_path, opts.apk) + + # TODO(mikecase): Add support to bisect on nonofficial builds for Android. + if context.android and not opts.official_builds: + sys.exit('Can only bisect on official builds for Android.') + + # If bisecting Android, we make sure we have ADB setup. + if context.android: + if opts.adb_path: + os.environ['PATH'] = '%s:%s' % (os.path.dirname(opts.adb_path), + os.environ['PATH']) + if not IsADBInstalled(): + sys.exit('Please have "adb" in PATH or use adb_path command line option' + 'to bisect Android builds.') + # Pick a starting point, try to get HEAD for this. if not opts.bad: context.bad_revision = '999.0.0.0'
diff --git a/tools/check_git_config.py b/tools/check_git_config.py index 2b5fe58..ecdfc44 100755 --- a/tools/check_git_config.py +++ b/tools/check_git_config.py
@@ -416,7 +416,7 @@ print ( 'It is strongly advised to switch to unmanaged mode. For more ' 'information about managed mode and reasons for its deprecation see:') - print 'http://www.chromium.org/developers/how-tos/get-the-code#Managed_mode' + print 'http://www.chromium.org/developers/how-tos/get-the-code/gclient-managed-mode' print print ( 'There\'s also a large suite of tools to assist managing git '
diff --git a/tools/git/move_source_file.py b/tools/git/move_source_file.py index a60c7e13..2de0b5b1 100755 --- a/tools/git/move_source_file.py +++ b/tools/git/move_source_file.py
@@ -33,7 +33,7 @@ sort_headers = __import__('sort-headers') -HANDLED_EXTENSIONS = ['.cc', '.mm', '.h', '.hh'] +HANDLED_EXTENSIONS = ['.cc', '.mm', '.h', '.hh', '.cpp'] def IsHandledFile(path): @@ -84,7 +84,7 @@ files_with_changed_includes = mffr.MultiFileFindReplace( r'(#(include|import)\s*["<])%s([>"])' % re.escape(from_path), r'\1%s\3' % to_path, - ['*.cc', '*.h', '*.m', '*.mm']) + ['*.cc', '*.h', '*.m', '*.mm', '*.cpp']) # Reorder headers in files that changed. for changed_file in files_with_changed_includes: @@ -100,7 +100,7 @@ mffr.MultiFileFindReplace( r'(//.*)%s' % re.escape(from_path), r'\1%s' % to_path, - ['*.cc', '*.h', '*.m', '*.mm']) + ['*.cc', '*.h', '*.m', '*.mm', '*.cpp']) # Update references in .gyp(i) files. def PathMinusFirstComponent(path):
diff --git a/tools/gn/command_format.cc b/tools/gn/command_format.cc index f30984a1..1ce072d 100644 --- a/tools/gn/command_format.cc +++ b/tools/gn/command_format.cc
@@ -24,22 +24,20 @@ const char kFormat[] = "format"; const char kFormat_HelpShort[] = - "format: Format .gn file. (ALPHA, WILL DESTROY DATA!)"; + "format: Format .gn file."; const char kFormat_Help[] = "gn format [--dump-tree] [--in-place] [--stdin] BUILD.gn\n" "\n" - " Formats .gn file to a standard format. THIS IS NOT FULLY IMPLEMENTED\n" - " YET! IT WILL EAT YOUR BEAUTIFUL .GN FILES. AND YOUR LAUNDRY.\n" - " At a minimum, make sure everything is `git commit`d so you can\n" - " `git checkout -f` to recover.\n" + " Formats .gn file to a standard format.\n" "\n" "Arguments\n" " --dump-tree\n" " For debugging only, dumps the parse tree.\n" "\n" " --in-place\n" - " Instead writing the formatted file to stdout, replace the input\n" - " with the formatted output.\n" + " Instead of writing the formatted file to stdout, replace the input\n" + " file with the formatted output. If no reformatting is required,\n" + " the input file will not be touched, and nothing printed.\n" "\n" " --stdin\n" " Read input from stdin (and write to stdout). Not compatible with\n" @@ -68,8 +66,8 @@ kPrecedenceAnd, kPrecedenceCompare, kPrecedenceAdd, - kPrecedenceSuffix, kPrecedenceUnary, + kPrecedenceSuffix, }; int CountLines(const std::string& str) { @@ -147,6 +145,9 @@ // Generic penalties for exceeding maximum width, adding more lines, etc. int AssessPenalty(const std::string& output); + // Tests if any lines exceed the maximum width. + bool ExceedsMaximumWidth(const std::string& output); + // Format a list of values using the given style. // |end| holds any trailing comments to be printed just before the closing // bracket. @@ -178,15 +179,23 @@ } struct IndentState { - IndentState() : margin(0), continuation_requires_indent(false) {} - IndentState(int margin, bool continuation_requires_indent) + IndentState() + : margin(0), + continuation_requires_indent(false), + parent_is_boolean_or(false) {} + IndentState(int margin, + bool continuation_requires_indent, + bool parent_is_boolean_or) : margin(margin), - continuation_requires_indent(continuation_requires_indent) {} + continuation_requires_indent(continuation_requires_indent), + parent_is_boolean_or(parent_is_boolean_or) {} // The left margin (number of spaces). int margin; bool continuation_requires_indent; + + bool parent_is_boolean_or; }; // Stack used to track std::vector<IndentState> stack_; @@ -239,7 +248,7 @@ // Save the margin, and temporarily set it to where the first comment // starts so that multiple suffix comments are vertically aligned. This // will need to be fancier once we enforce 80 col. - stack_.push_back(IndentState(CurrentColumn(), false)); + stack_.push_back(IndentState(CurrentColumn(), false, false)); int i = 0; for (const auto& c : comments_) { if (i > 0) { @@ -368,6 +377,16 @@ return penalty; } +bool Printer::ExceedsMaximumWidth(const std::string& output) { + std::vector<std::string> lines; + base::SplitStringDontTrim(output, '\n', &lines); + for (const auto& line : lines) { + if (line.size() > kMaximumWidth) + return true; + } + return false; +} + void Printer::AddParen(int prec, int outer_prec, bool* parenthesized) { if (prec < outer_prec) { Print("("); @@ -413,8 +432,26 @@ } else if (const BinaryOpNode* binop = root->AsBinaryOp()) { CHECK(precedence_.find(binop->op().value()) != precedence_.end()); AnnotatePreferedMultilineAssignment(binop); + Precedence prec = precedence_[binop->op().value()]; - AddParen(prec, outer_prec, &parenthesized); + + // Since binary operators format left-to-right, it is ok for the left side + // use the same operator without parentheses, so the left uses prec. For the + // same reason, the right side cannot reuse the same operator, or else "x + + // (y + z)" would format as "x + y + z" which means "(x + y) + z". So, treat + // the right expression as appearing one precedence level higher. + // However, because the source parens are not in the parse tree, as a + // special case for && and || we insert strictly-redundant-but-helpful-for- + // human-readers parentheses. + int prec_left = prec; + int prec_right = prec + 1; + if (binop->op().value() == "&&" && stack_.back().parent_is_boolean_or) { + Print("("); + parenthesized = true; + } else { + AddParen(prec_left, outer_prec, &parenthesized); + } + int start_line = CurrentLine(); int start_column = CurrentColumn(); bool is_assignment = binop->op().value() == "=" || @@ -434,11 +471,12 @@ if (stack_.back().continuation_requires_indent) indent_column += kIndentSize * 2; - stack_.push_back(IndentState(indent_column, false)); + stack_.push_back( + IndentState(indent_column, false, binop->op().value() == "||")); Printer sub_left; InitializeSub(&sub_left); sub_left.Expr(binop->left(), - prec, + prec_left, std::string(" ") + binop->op().value().as_string()); bool left_is_multiline = CountLines(sub_left.String()) > 1; // Avoid walking the whole left redundantly times (see timing of Format.046) @@ -453,7 +491,7 @@ InitializeSub(&sub1); sub1.Print(" "); int penalty_current_line = - sub1.Expr(binop->right(), prec + 1, std::string()); + sub1.Expr(binop->right(), prec_right, std::string()); sub1.Print(suffix); penalty_current_line += AssessPenalty(sub1.String()); if (!is_assignment && left_is_multiline) { @@ -467,19 +505,29 @@ Printer sub2; InitializeSub(&sub2); sub2.Newline(); - int penalty_next_line = sub2.Expr(binop->right(), prec + 1, std::string()); + int penalty_next_line = + sub2.Expr(binop->right(), prec_right, std::string()); sub2.Print(suffix); penalty_next_line += AssessPenalty(sub2.String()); - if (penalty_current_line < penalty_next_line) { + // If in both cases it was forced past 80col, then we don't break to avoid + // breaking after '=' in the case of: + // variable = "... very long string ..." + // as breaking and indenting doesn't make things much more readable, even + // though there's less characters past the maximum width. + bool exceeds_maximum_either_way = ExceedsMaximumWidth(sub1.String()) && + ExceedsMaximumWidth(sub2.String()); + + if (penalty_current_line < penalty_next_line || + exceeds_maximum_either_way) { Print(" "); - Expr(binop->right(), prec + 1, std::string()); + Expr(binop->right(), prec_right, std::string()); } else { // Otherwise, put first argument and op, and indent next. Newline(); penalty += std::abs(CurrentColumn() - start_column) * kPenaltyHorizontalSeparation; - Expr(binop->right(), prec + 1, std::string()); + Expr(binop->right(), prec_right, std::string()); } stack_.pop_back(); penalty += (CurrentLine() - start_line) * GetPenaltyForLineBreak(); @@ -570,8 +618,9 @@ CHECK(!list[0]->comments() || list[0]->comments()->after().empty()); Print(" "); } else { - stack_.push_back( - IndentState(margin() + kIndentSize, style == kSequenceStyleList)); + stack_.push_back(IndentState(margin() + kIndentSize, + style == kSequenceStyleList, + false)); size_t i = 0; for (const auto& x : list) { Newline(); @@ -657,10 +706,18 @@ terminator += " {"; terminator += suffix; + // Special case to make function calls of one arg taking a long list of + // boolean operators not indent. + bool continuation_requires_indent = + list.size() != 1 || !list[0]->AsBinaryOp() || + (list[0]->AsBinaryOp()->op().value() != "||" && + list[0]->AsBinaryOp()->op().value() != "&&"); + // 1: Same line. Printer sub1; InitializeSub(&sub1); - sub1.stack_.push_back(IndentState(CurrentColumn(), true)); + sub1.stack_.push_back( + IndentState(CurrentColumn(), continuation_requires_indent, false)); int penalty_one_line = 0; for (size_t i = 0; i < list.size(); ++i) { penalty_one_line += sub1.Expr(list[i], kPrecedenceLowest, @@ -677,7 +734,8 @@ // 2: Starting on same line, broken at commas. Printer sub2; InitializeSub(&sub2); - sub2.stack_.push_back(IndentState(CurrentColumn(), true)); + sub2.stack_.push_back( + IndentState(CurrentColumn(), continuation_requires_indent, false)); int penalty_multiline_start_same_line = 0; for (size_t i = 0; i < list.size(); ++i) { penalty_multiline_start_same_line += sub2.Expr( @@ -692,7 +750,8 @@ // 3: Starting on next line, broken at commas. Printer sub3; InitializeSub(&sub3); - sub3.stack_.push_back(IndentState(margin() + kIndentSize * 2, true)); + sub3.stack_.push_back(IndentState(margin() + kIndentSize * 2, + continuation_requires_indent, false)); sub3.Newline(); int penalty_multiline_start_next_line = 0; for (size_t i = 0; i < list.size(); ++i) { @@ -728,10 +787,13 @@ // No elements, and not forcing newlines, print nothing. } else { if (penalty_multiline_start_next_line < penalty_multiline_start_same_line) { - stack_.push_back(IndentState(margin() + kIndentSize * 2, true)); + stack_.push_back(IndentState(margin() + kIndentSize * 2, + continuation_requires_indent, + false)); Newline(); } else { - stack_.push_back(IndentState(CurrentColumn(), true)); + stack_.push_back( + IndentState(CurrentColumn(), continuation_requires_indent, false)); } for (size_t i = 0; i < list.size(); ++i) { @@ -915,8 +977,7 @@ Setup setup; SourceDir source_dir = SourceDirForCurrentDirectory(setup.build_settings().root_path()); - SourceFile file = source_dir.ResolveRelativeFile(args[0], - setup.build_settings().root_path_utf8()); + SourceFile file = source_dir.ResolveRelativeFile(args[0]); std::string output_string; if (FormatFileToString(&setup, file, dump_tree, &output_string)) { @@ -924,15 +985,24 @@ base::CommandLine::ForCurrentProcess()->HasSwitch(kSwitchInPlace); if (in_place) { base::FilePath to_write = setup.build_settings().GetFullPath(file); - if (base::WriteFile(to_write, - output_string.data(), - static_cast<int>(output_string.size())) == -1) { - Err(Location(), - std::string("Failed to write formatted output back to \"") + - to_write.AsUTF8Unsafe() + std::string("\".")).PrintToStdout(); + std::string original_contents; + if (!base::ReadFileToString(to_write, &original_contents)) { + Err(Location(), std::string("Couldn't read \"") + + to_write.AsUTF8Unsafe() + + std::string("\" for comparison.")).PrintToStdout(); return 1; } - printf("Wrote formatted to '%s'.\n", to_write.AsUTF8Unsafe().c_str()); + if (original_contents != output_string) { + if (base::WriteFile(to_write, + output_string.data(), + static_cast<int>(output_string.size())) == -1) { + Err(Location(), + std::string("Failed to write formatted output back to \"") + + to_write.AsUTF8Unsafe() + std::string("\".")).PrintToStdout(); + return 1; + } + printf("Wrote formatted to '%s'.\n", to_write.AsUTF8Unsafe().c_str()); + } } else { printf("%s", output_string.c_str()); }
diff --git a/tools/gn/command_format_unittest.cc b/tools/gn/command_format_unittest.cc index fe4c050..73badce 100644 --- a/tools/gn/command_format_unittest.cc +++ b/tools/gn/command_format_unittest.cc
@@ -92,3 +92,7 @@ FORMAT_TEST(054) FORMAT_TEST(055) FORMAT_TEST(056) +FORMAT_TEST(057) +FORMAT_TEST(058) +FORMAT_TEST(059) +FORMAT_TEST(060)
diff --git a/tools/gn/filesystem_utils.cc b/tools/gn/filesystem_utils.cc index ebfb942..700b7b8 100644 --- a/tools/gn/filesystem_utils.cc +++ b/tools/gn/filesystem_utils.cc
@@ -627,7 +627,7 @@ // See if path is inside the source root by looking for each of source root's // components at the beginning of path. bool is_inside_source; - if (path_comp.size() < source_comp.size()) { + if (path_comp.size() < source_comp.size() || source_root.empty()) { // Too small to fit. is_inside_source = false; } else {
diff --git a/tools/gn/filesystem_utils.h b/tools/gn/filesystem_utils.h index f5cf494..52352c6 100644 --- a/tools/gn/filesystem_utils.h +++ b/tools/gn/filesystem_utils.h
@@ -144,8 +144,8 @@ // Returns the "best" SourceDir representing the given path. If it's inside the // given source_root, a source-relative directory will be returned (e.g. -// "//foo/bar.cc". If it's outside of the source root, a system-absolute -// directory will be returned. +// "//foo/bar.cc". If it's outside of the source root or the source root is +// empty, a system-absolute directory will be returned. SourceDir SourceDirForPath(const base::FilePath& source_root, const base::FilePath& path);
diff --git a/tools/gn/filesystem_utils_unittest.cc b/tools/gn/filesystem_utils_unittest.cc index 7bcfd1a..bbf3336 100644 --- a/tools/gn/filesystem_utils_unittest.cc +++ b/tools/gn/filesystem_utils_unittest.cc
@@ -392,6 +392,11 @@ EXPECT_EQ("//bar/", SourceDirForPath(root, base::FilePath(L"/C:/source/foo/bar")).value()); + // Empty source dir. + base::FilePath empty; + EXPECT_EQ( + "/C:/source/foo/", + SourceDirForPath(empty, base::FilePath(L"C:\\source\\foo")).value()); #else base::FilePath root("/source/foo/"); EXPECT_EQ("/foo/bar/", SourceDirForPath(root, @@ -408,6 +413,11 @@ // Should be case-sensitive. EXPECT_EQ("/SOURCE/foo/bar/", SourceDirForPath(root, base::FilePath("/SOURCE/foo/bar/")).value()); + + // Empty source dir. + base::FilePath empty; + EXPECT_EQ("/source/foo/", + SourceDirForPath(empty, base::FilePath("/source/foo")).value()); #endif }
diff --git a/tools/gn/format_test_data/016.golden b/tools/gn/format_test_data/016.golden index 00a79922..3f4f15b 100644 --- a/tools/gn/format_test_data/016.golden +++ b/tools/gn/format_test_data/016.golden
@@ -1 +1 @@ -something = !is_win && is_linux || is_mac && !(is_freebsd || is_ios) +something = (!is_win && is_linux) || (is_mac && !(is_freebsd || is_ios))
diff --git a/tools/gn/format_test_data/043.gn b/tools/gn/format_test_data/043.gn index a2748d5..b95c6a5 100644 --- a/tools/gn/format_test_data/043.gn +++ b/tools/gn/format_test_data/043.gn
@@ -1,6 +1,4 @@ -# We might prefer not to break the first one since it still exceeds the maximum -# width. At the moment, each character past the end is a greater penalty, so -# breaking to +4 is "better". +# Don't break and indent when it's hopeless. # 80 --------------------------------------------------------------------------- android_java_prebuilt("android_support_v13_java") { jar_path = "$android_sdk_root/extras/android/support/v7/appcompat/libs/android-support-v7-appcompat.jar"
diff --git a/tools/gn/format_test_data/043.golden b/tools/gn/format_test_data/043.golden index 5ba421b..336ec2f 100644 --- a/tools/gn/format_test_data/043.golden +++ b/tools/gn/format_test_data/043.golden
@@ -1,10 +1,7 @@ -# We might prefer not to break the first one since it still exceeds the maximum -# width. At the moment, each character past the end is a greater penalty, so -# breaking to +4 is "better". +# Don't break and indent when it's hopeless. # 80 --------------------------------------------------------------------------- android_java_prebuilt("android_support_v13_java") { - jar_path = - "$android_sdk_root/extras/android/support/v7/appcompat/libs/android-support-v7-appcompat.jar" + jar_path = "$android_sdk_root/extras/android/support/v7/appcompat/libs/android-support-v7-appcompat.jar" jar_path = "$android_sdk_root/extras/android/support/v13/android-support-v13.jar" }
diff --git a/tools/gn/format_test_data/057.gn b/tools/gn/format_test_data/057.gn new file mode 100644 index 0000000..858e311 --- /dev/null +++ b/tools/gn/format_test_data/057.gn
@@ -0,0 +1,24 @@ +# 80 --------------------------------------------------------------------------- +# Because there is a difference in precedence level between || and && +# a || b || c && d +# is equivalent to +# a || b || (c && d) +# Because parens are not stored in the parse tree, the formatter recreates the +# minimally required set to maintain meaning. However, this particular case can +# be confusing for human readers, so we special case these ones and add +# strictly-unnecessary parens. + +supports_android = (is_apk || is_android_resources || + (is_java_library && defined(invoker.supports_android) && + invoker.supports_android)) + +enable_one_click_signin = is_win || is_mac || (is_linux && !is_chromeos) +enable_one_click_signin = (is_linux && !is_chromeos) || is_win || is_mac + +x = c || (a&&b) +x = (a&&b) || c +x = a&&b || c + +x = c && (a||b) +x = (a||b) && c +x = a||b && c
diff --git a/tools/gn/format_test_data/057.golden b/tools/gn/format_test_data/057.golden new file mode 100644 index 0000000..d0daa6c --- /dev/null +++ b/tools/gn/format_test_data/057.golden
@@ -0,0 +1,24 @@ +# 80 --------------------------------------------------------------------------- +# Because there is a difference in precedence level between || and && +# a || b || c && d +# is equivalent to +# a || b || (c && d) +# Because parens are not stored in the parse tree, the formatter recreates the +# minimally required set to maintain meaning. However, this particular case can +# be confusing for human readers, so we special case these ones and add +# strictly-unnecessary parens. + +supports_android = is_apk || is_android_resources || + (is_java_library && defined(invoker.supports_android) && + invoker.supports_android) + +enable_one_click_signin = is_win || is_mac || (is_linux && !is_chromeos) +enable_one_click_signin = (is_linux && !is_chromeos) || is_win || is_mac + +x = c || (a && b) +x = (a && b) || c +x = (a && b) || c + +x = c && (a || b) +x = (a || b) && c +x = a || (b && c)
diff --git a/tools/gn/format_test_data/058.gn b/tools/gn/format_test_data/058.gn new file mode 100644 index 0000000..568074a6 --- /dev/null +++ b/tools/gn/format_test_data/058.gn
@@ -0,0 +1,2 @@ +if (!defined(invoker.ignore_libs) || !invoker.ignore_libs) { +}
diff --git a/tools/gn/format_test_data/058.golden b/tools/gn/format_test_data/058.golden new file mode 100644 index 0000000..568074a6 --- /dev/null +++ b/tools/gn/format_test_data/058.golden
@@ -0,0 +1,2 @@ +if (!defined(invoker.ignore_libs) || !invoker.ignore_libs) { +}
diff --git a/tools/gn/format_test_data/059.gn b/tools/gn/format_test_data/059.gn new file mode 100644 index 0000000..ea6fb8e3 --- /dev/null +++ b/tools/gn/format_test_data/059.gn
@@ -0,0 +1,10 @@ +assert(type == "android_apk" || type == "java_library" || + type == "android_resources" || things == stuff && stuff != 432) + +assert(type == "android_apk" || type == "java_library" || + type == "android_resources", + type == "android_apk" || type == "java_library" || + type == "android_resources") + + +if (type == "android_apk" || type == "java_library" || type == "android_resources" || things == stuff && stuff != 432) {}
diff --git a/tools/gn/format_test_data/059.golden b/tools/gn/format_test_data/059.golden new file mode 100644 index 0000000..423e888 --- /dev/null +++ b/tools/gn/format_test_data/059.golden
@@ -0,0 +1,11 @@ +assert(type == "android_apk" || type == "java_library" || + type == "android_resources" || (things == stuff && stuff != 432)) + +assert(type == "android_apk" || type == "java_library" || + type == "android_resources", + type == "android_apk" || type == "java_library" || + type == "android_resources") + +if (type == "android_apk" || type == "java_library" || + type == "android_resources" || (things == stuff && stuff != 432)) { +}
diff --git a/tools/gn/format_test_data/060.gn b/tools/gn/format_test_data/060.gn new file mode 100644 index 0000000..2b0da79 --- /dev/null +++ b/tools/gn/format_test_data/060.gn
@@ -0,0 +1,2 @@ +some_variable = "this is a very long string that is going to exceed 80 col and will never under any circumstance fit" +another_variable = [ "this is a very long string that is going to exceed 80 col and will never under any circumstance fit" ]
diff --git a/tools/gn/format_test_data/060.golden b/tools/gn/format_test_data/060.golden new file mode 100644 index 0000000..2b0da79 --- /dev/null +++ b/tools/gn/format_test_data/060.golden
@@ -0,0 +1,2 @@ +some_variable = "this is a very long string that is going to exceed 80 col and will never under any circumstance fit" +another_variable = [ "this is a very long string that is going to exceed 80 col and will never under any circumstance fit" ]
diff --git a/tools/json_schema_compiler/cpp_util.py b/tools/json_schema_compiler/cpp_util.py index 187d99f..b34a2ab 100644 --- a/tools/json_schema_compiler/cpp_util.py +++ b/tools/json_schema_compiler/cpp_util.py
@@ -77,6 +77,7 @@ """ if param.type_.property_type in (PropertyType.ANY, PropertyType.ARRAY, + PropertyType.BINARY, PropertyType.CHOICES, PropertyType.OBJECT, PropertyType.REF,
diff --git a/tools/lsan/suppressions.txt b/tools/lsan/suppressions.txt index 493ebfc..41f8679 100644 --- a/tools/lsan/suppressions.txt +++ b/tools/lsan/suppressions.txt
@@ -58,6 +58,7 @@ leak:blink::V8PerIsolateData::ensureDomInJSContext leak:gin/object_template_builder.h leak:gin::internal::Dispatcher +leak:blink::LocalDOMWindow::getComputedStyle # http://crbug.com/356785 leak:content::RenderViewImplTest_DecideNavigationPolicyForWebUI_Test::TestBody
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 7b6ef96..f20c9dc 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -6259,7 +6259,7 @@ </histogram> <histogram name="Enterprise.AutoEnrollmentExtraTime" units="milliseconds"> - <owner>joaodasilva@chromium.org</owner> + <owner>mnissler@chromium.org</owner> <summary> Time since the user logged in until the auto-enrollment protocol completed. 0 is sampled when the protocol is done by the time the user logs in. @@ -6267,13 +6267,13 @@ </histogram> <histogram name="Enterprise.AutoEnrollmentProtocolTime" units="milliseconds"> - <owner>joaodasilva@chromium.org</owner> + <owner>mnissler@chromium.org</owner> <summary>Total duration time of the auto-enrollment protocol.</summary> </histogram> <histogram name="Enterprise.AutoEnrollmentRequestNetworkErrorCode" enum="NetErrorCodes"> - <owner>joaodasilva@chromium.org</owner> + <owner>mnissler@chromium.org</owner> <summary> Network error code (if applicable) for auto-enrollment requests. </summary> @@ -6281,7 +6281,7 @@ <histogram name="Enterprise.AutoEnrollmentRequestStatus" enum="EnterpriseDeviceManagementStatus"> - <owner>joaodasilva@chromium.org</owner> + <owner>mnissler@chromium.org</owner> <summary>URL fetcher status for auto-enrollment requests.</summary> </histogram> @@ -6307,7 +6307,7 @@ </histogram> <histogram name="Enterprise.DMToken" enum="EnterpriseDMTokenType"> - <owner>joaodasilva@chromium.org</owner> + <owner>mnissler@chromium.org</owner> <summary> Events related to fetching, saving and loading DM server tokens. These are used to retrieve cloud policies. @@ -6353,7 +6353,7 @@ </histogram> <histogram name="Enterprise.Enrollment" enum="EnterpriseEnrollmentType"> - <owner>joaodasilva@chromium.org</owner> + <owner>mnissler@chromium.org</owner> <summary> Events related to device enrollment on new installs of Chrome OS devices. </summary> @@ -6397,7 +6397,7 @@ </histogram> <histogram name="Enterprise.IOSPolicies"> - <owner>joaodasilva@chromium.org</owner> + <owner>mnissler@chromium.org</owner> <summary> Number of policies loaded at startup on iOS, and when a change is detected at runtime. @@ -6405,12 +6405,12 @@ </histogram> <histogram name="Enterprise.ONC.PolicyValidation" enum="BooleanSuccess"> - <owner>joaodasilva@chromium.org</owner> + <owner>mnissler@chromium.org</owner> <summary>Result of the OpenNetworkConfiguration policy validation.</summary> </histogram> <histogram name="Enterprise.Policies" enum="EnterprisePolicies"> - <owner>joaodasilva@chromium.org</owner> + <owner>mnissler@chromium.org</owner> <summary> A set of enterprise policy rules that are in use. This is recorded every 24 hours and at startup, if the last recording was earlier than a day before. @@ -6418,7 +6418,7 @@ </histogram> <histogram name="Enterprise.Policy" enum="EnterprisePolicyType"> - <owner>joaodasilva@chromium.org</owner> + <owner>mnissler@chromium.org</owner> <summary> Events related to fetching, saving and loading user policies, and also device policies on Chrome OS. @@ -6435,7 +6435,7 @@ <histogram name="Enterprise.PolicyInvalidations" enum="EnterprisePolicyInvalidations"> - <owner>joaodasilva@chromium.org</owner> + <owner>mnissler@chromium.org</owner> <summary> Events for counting user policy invalidations received with and without payloads. Invalidations indicate that a policy has been updated and should @@ -6446,7 +6446,7 @@ <histogram name="Enterprise.PolicyInvalidationsStartupTime" units="milliseconds"> - <owner>joaodasilva@chromium.org</owner> + <owner>mnissler@chromium.org</owner> <summary> Time since startup of the cloud policy code until the policy invalidation service first reported its online status. @@ -6454,7 +6454,7 @@ </histogram> <histogram name="Enterprise.PolicyLoadStatus" enum="EnterprisePolicyLoadStatus"> - <owner>joaodasilva@chromium.org</owner> + <owner>mnissler@chromium.org</owner> <summary> Load status from the policy loaders which pull policy settings from the underlying platform, such as Windows Group Policy. @@ -6462,7 +6462,7 @@ </histogram> <histogram name="Enterprise.PolicyRefresh" enum="EnterprisePolicyRefresh"> - <owner>joaodasilva@chromium.org</owner> + <owner>mnissler@chromium.org</owner> <summary> Events measuring effectiveness of refreshing user policy when invalidations are received from a service. For each refresh, indicates whether the policy @@ -6497,50 +6497,50 @@ <histogram name="Enterprise.UserPolicyChromeOS.DelayInitialization" units="milliseconds"> - <owner>joaodasilva@chromium.org</owner> + <owner>mnissler@chromium.org</owner> <summary>Initialization delay due to loading the user policy cache.</summary> </histogram> <histogram name="Enterprise.UserPolicyChromeOS.InitialFetch.ClientError" enum="EnterpriseDeviceManagementStatus"> - <owner>joaodasilva@chromium.org</owner> + <owner>mnissler@chromium.org</owner> <summary>Policy client error during initial policy fetch.</summary> </histogram> <histogram name="Enterprise.UserPolicyChromeOS.InitialFetch.DelayClientRegister" units="milliseconds"> - <owner>joaodasilva@chromium.org</owner> + <owner>mnissler@chromium.org</owner> <summary>Delay for registering the client with the policy server.</summary> </histogram> <histogram name="Enterprise.UserPolicyChromeOS.InitialFetch.DelayOAuth2Token" units="milliseconds"> - <owner>joaodasilva@chromium.org</owner> + <owner>mnissler@chromium.org</owner> <summary>Delay for minting an OAuth2 acccess token.</summary> </histogram> <histogram name="Enterprise.UserPolicyChromeOS.InitialFetch.DelayPolicyFetch" units="milliseconds"> - <owner>joaodasilva@chromium.org</owner> + <owner>mnissler@chromium.org</owner> <summary>Delay for fetching policy from the policy server.</summary> </histogram> <histogram name="Enterprise.UserPolicyChromeOS.InitialFetch.DelayTotal" units="milliseconds"> - <owner>joaodasilva@chromium.org</owner> + <owner>mnissler@chromium.org</owner> <summary>Total delay for the initial policy fetch.</summary> </histogram> <histogram name="Enterprise.UserPolicyChromeOS.InitialFetch.OAuth2Error" enum="GoogleServiceAuthError"> - <owner>joaodasilva@chromium.org</owner> + <owner>mnissler@chromium.org</owner> <summary>Service error during OAuth2 access token fetch.</summary> </histogram> <histogram name="Enterprise.UserPolicyChromeOS.InitialFetch.OAuth2NetworkError" enum="NetErrorCodes"> - <owner>joaodasilva@chromium.org</owner> + <owner>mnissler@chromium.org</owner> <summary>Network error during OAuth2 access token fetch.</summary> </histogram> @@ -6575,27 +6575,27 @@ <histogram name="Enterprise.WildcardLoginCheck.DelayPolicyTokenFetch" units="milliseconds"> - <owner>joaodasilva@chromium.org</owner> + <owner>mnissler@chromium.org</owner> <summary> Delay incurred by the token fetching step of the wildcard login check. </summary> </histogram> <histogram name="Enterprise.WildcardLoginCheck.DelayTotal" units="milliseconds"> - <owner>joaodasilva@chromium.org</owner> + <owner>mnissler@chromium.org</owner> <summary>Total delay incurred by the wildcard login check.</summary> </histogram> <histogram name="Enterprise.WildcardLoginCheck.DelayUserInfoFetch" units="milliseconds"> - <owner>joaodasilva@chromium.org</owner> + <owner>mnissler@chromium.org</owner> <summary> Delay incurred by the user info fetching step of the wildcard login check. </summary> </histogram> <histogram name="EnterpriseCheck.DomainBindSucceeded" enum="BooleanSuccess"> - <owner>joaodasilva@chromium.org</owner> + <owner>mnissler@chromium.org</owner> <owner>pastarmovj@chromium.org</owner> <summary> Whether we were able to contact the AD Domain Controller. This check is @@ -6604,7 +6604,7 @@ </histogram> <histogram name="EnterpriseCheck.DomainCheckFailed" enum="EnterpriseCheckError"> - <owner>joaodasilva@chromium.org</owner> + <owner>mnissler@chromium.org</owner> <owner>pastarmovj@chromium.org</owner> <summary> Enum of possible things that can fail while checking for enterprise env. @@ -6613,7 +6613,7 @@ </histogram> <histogram name="EnterpriseCheck.InDomain" enum="BooleanEnabled"> - <owner>joaodasilva@chromium.org</owner> + <owner>mnissler@chromium.org</owner> <owner>pastarmovj@chromium.org</owner> <summary> Whether the machine is part of an AD domain. This check is performed once at @@ -6622,7 +6622,7 @@ </histogram> <histogram name="EnterpriseCheck.InvalidPolicies" enum="EnterprisePolicies"> - <owner>joaodasilva@chromium.org</owner> + <owner>mnissler@chromium.org</owner> <summary> A set of policy rules that were ignored due to integrity violations while parsing the policy data which happens on start-up and when the policy has @@ -6632,7 +6632,7 @@ <histogram name="EnterpriseCheck.InvalidPoliciesDetected" units="disabled policies"> - <owner>joaodasilva@chromium.org</owner> + <owner>mnissler@chromium.org</owner> <owner>pastarmovj@chromium.org</owner> <summary> The number of disabled policy entries on Windows due to integrity violations @@ -6642,7 +6642,7 @@ </histogram> <histogram name="EnterpriseCheck.OSType" enum="OsSuite"> - <owner>joaodasilva@chromium.org</owner> + <owner>mnissler@chromium.org</owner> <owner>pastarmovj@chromium.org</owner> <summary> The rough Windows suite we are runnnig on. This check is performed once at @@ -9138,6 +9138,24 @@ </summary> </histogram> +<histogram name="FileBrowser.HardUnpluggedAroundSuspend.TimeSinceResume" + units="milliseconds"> + <owner>hirono@chromium.org</owner> + <summary> + Chrome OS File Browser: time from the SuspendDone event to the DiskRemoved + event. The UMA is added temporarily for crbug.com/433734. + </summary> +</histogram> + +<histogram name="FileBrowser.HardUnpluggedAroundSuspend.TimeUntilSuspend" + units="milliseconds"> + <owner>hirono@chromium.org</owner> + <summary> + Chrome OS File Browser: time from the DiskRemoved event to the Suspend + event. The UMA is added temporarily for crbug.com/433734. + </summary> +</histogram> + <histogram name="FileBrowser.Load" units="milliseconds"> <owner>joshwoodward@google.com</owner> <summary> @@ -12865,7 +12883,8 @@ <owner>kenjibaheux@google.com</owner> <owner>kouhei@chromium.org</owner> <summary> - The count of active chrome:// processes. Recorded once per UMA ping. + The count of active chrome:// renderer processes. Recorded once per UMA + ping. </summary> </histogram> @@ -38664,6 +38683,11 @@ <summary>Time spent in V8 compiler (full codegen).</summary> </histogram> +<histogram name="V8.CompileDeserialize" units="milliseconds"> + <owner>vogelheim@chromium.org</owner> + <summary>Time spent deseriailzing code, used by V8 code caching.</summary> +</histogram> + <histogram name="V8.CompileEval" units="milliseconds"> <owner>jochen@chromium.org</owner> <owner>yangguo@chromium.org</owner> @@ -38678,6 +38702,11 @@ <summary>Time spent compiling functions lazily on first run.</summary> </histogram> +<histogram name="V8.CompileSerialize" units="milliseconds"> + <owner>vogelheim@chromium.org</owner> + <summary>Time spent serializing code, used by V8 code caching.</summary> +</histogram> + <histogram name="V8.DeferredCodeGeneration"> <obsolete> This histogram is no longer present in V8 @@ -41161,6 +41190,12 @@ <int value="9" label="SOURCE_SYSTEM_TRAY"/> <int value="10" label="SOURCE_ABOUT_PAGE"/> <int value="11" label="SOURCE_KEYBOARD"/> + <int value="12" label="SOURCE_EXTENSIONS_PAGE"/> + <int value="13" label="SOURCE_MANAGEMENT_API"/> + <int value="14" label="SOURCE_EPHEMERAL_APP"/> + <int value="15" label="SOURCE_BACKGROUND"/> + <int value="16" label="SOURCE_KIOSK"/> + <int value="17" label="SOURCE_CHROME_INTERNAL"/> </enum> <enum name="AppListEnableSource" type="int"> @@ -44179,6 +44214,8 @@ <int value="280" label="SSL fallback minimum version"/> <int value="281" label="Control the availability of the Contextual Search feature."/> + <int value="282" label="Force Google SafeSearch"/> + <int value="283" label="Force YouTube Safety Mode"/> </enum> <enum name="EnterprisePolicyInvalidations" type="int"> @@ -45400,6 +45437,7 @@ <int value="924" label="HOTWORDPRIVATE_GETLOCALIZEDSTRINGS"/> <int value="925" label="HOTWORDPRIVATE_SETAUDIOHISTORYENABLED"/> <int value="926" label="HOTWORDPRIVATE_GETAUDIOHISTORYENABLED"/> + <int value="927" label="APP_CURRENTWINDOWINTERNAL_SETINTERCEPTALLKEYS"/> </enum> <enum name="ExtensionInstallCause" type="int"> @@ -48793,6 +48831,7 @@ <int value="-1052782474" label="enable-cloud-devices"/> <int value="-1052415111" label="malware-interstitial-v2"/> <int value="-1022971520" label="enable-search-button-in-omnibox-for-str"/> + <int value="-979057409" label="enable-seccomp-filter-sandbox"/> <int value="-979034258" label="disable-ntp-other-sessions-menu"/> <int value="-949178861" label="enable-new-avatar-menu"/> <int value="-926422468" label="disable-embedded-shared-worker"/> @@ -48906,6 +48945,7 @@ <int value="606288133" label="enable-print-preview-register-promos"/> <int value="625273056" label="disable-boot-animation"/> <int value="630947363" label="touch-events"/> + <int value="643725031" label="disable-touch-feedback"/> <int value="689489984" label="disable-zero-suggest"/> <int value="709850261" label="disable-touch-editing"/> <int value="711424932" label="enable-cloud-print-xps"/> @@ -53445,6 +53485,7 @@ <int value="3" label="Registration limit reached"/> <int value="4" label="Permission denied"/> <int value="5" label="Push service error"/> + <int value="6" label="No sender id provided"/> </enum> <enum name="QuicAddressMismatch" type="int"> @@ -56294,26 +56335,28 @@ </enum> <enum name="TrackedPreference" type="int"> - <int value="0" label="prefs::kShowHomeButton"/> - <int value="1" label="prefs::kHomePageIsNewTabPage"/> - <int value="2" label="prefs::kHomePage"/> - <int value="3" label="prefs::kRestoreOnStartup"/> - <int value="4" label="prefs::kURLsToRestoreOnStartup"/> + <int value="0" label="kShowHomeButton"/> + <int value="1" label="kHomePageIsNewTabPage"/> + <int value="2" label="kHomePage"/> + <int value="3" label="kRestoreOnStartup"/> + <int value="4" label="kURLsToRestoreOnStartup"/> <int value="5" label="extensions::pref_names::kExtensions"/> - <int value="6" label="prefs::kGoogleServicesLastUsername"/> - <int value="7" label="prefs::kSearchProviderOverrides"/> - <int value="8" label="prefs::kDefaultSearchProviderSearchURL"/> - <int value="9" label="prefs::kDefaultSearchProviderKeyword"/> - <int value="10" label="prefs::kDefaultSearchProviderName"/> - <int value="11" label="prefs::kPinnedTabs"/> - <int value="12" - label="extensions::pref_names::kKnownDisabled (Obsolete 07/2014)"/> - <int value="13" label="prefs::kProfileResetPromptMemento"/> - <int value="14" - label="DefaultSearchManager::kDefaultSearchProviderDataPrefName"/> - <int value="15" label="prefs::kPreferenceResetTime"/> - <int value="16" label="prefs::kSafeBrowsingIncidentReportSent"/> - <int value="17" label="sync_driver::prefs::kSyncRemainingRollbackTries"/> + <int value="6" label="kGoogleServicesLastUsername"/> + <int value="7" label="kSearchProviderOverrides"/> + <int value="8" label="kDefaultSearchProviderSearchURL"/> + <int value="9" label="kDefaultSearchProviderKeyword"/> + <int value="10" label="kDefaultSearchProviderName"/> + <int value="11" label="kPinnedTabs"/> + <int value="12" label="kKnownDisabled (Obsolete 07/2014)"/> + <int value="13" label="kProfileResetPromptMemento"/> + <int value="14" label="kDefaultSearchProviderDataPrefName"/> + <int value="15" label="kPreferenceResetTime"/> + <int value="16" label="kSafeBrowsingIncidentReportSent"/> + <int value="17" label="kSyncRemainingRollbackTries"/> + <int value="18" label="kSafeBrowsingIncidentsSent"/> + <int value="19" label="kSwReporterPromptVersion"/> + <int value="20" label="kSwReporterPromptReason"/> + <int value="21" label="kGoogleServicesUsername"/> </enum> <enum name="TranslateError" type="int">
diff --git a/tools/perf/benchmarks/smoothness.py b/tools/perf/benchmarks/smoothness.py index 4f4702f..3951e36 100644 --- a/tools/perf/benchmarks/smoothness.py +++ b/tools/perf/benchmarks/smoothness.py
@@ -130,7 +130,29 @@ def CustomizeBrowserOptions(self, options): silk_flags.CustomizeBrowserOptionsForGpuRasterization(options) + class SmoothnessToughFastScrollingCases(benchmark.Benchmark): test = smoothness.Smoothness page_set = page_sets.ToughScrollingCasesPageSet options = {'page_label_filter' : 'fastscrolling'} + + +class SmoothnessImageDecodingCases(benchmark.Benchmark): + """Measures decoding statistics for jpeg images. + """ + test = smoothness.Smoothness + page_set = page_sets.ImageDecodingCasesPageSet + def CustomizeBrowserOptions(self, options): + silk_flags.CustomizeBrowserOptionsForGpuRasterization(options) + + +class SmoothnessGpuImageDecodingCases(benchmark.Benchmark): + """Measures decoding statistics for jpeg images with GPU rasterization + """ + tag = 'gpu_rasterization_and_decoding' + test = smoothness.Smoothness + page_set = page_sets.ImageDecodingCasesPageSet + def CustomizeBrowserOptions(self, options): + silk_flags.CustomizeBrowserOptionsForGpuRasterization(options) + options.AppendExtraBrowserArgs('--enable-accelerated-jpeg-decoding') +
diff --git a/tools/perf/measurements/rasterize_and_record_micro.py b/tools/perf/measurements/rasterize_and_record_micro.py index 4c875bf0..3523a7b 100644 --- a/tools/perf/measurements/rasterize_and_record_micro.py +++ b/tools/perf/measurements/rasterize_and_record_micro.py
@@ -28,17 +28,6 @@ '--enable-gpu-benchmarking' ]) - def DidStartBrowser(self, browser): - # TODO(vmpstr): Remove this temporary workaround when reference build has - # been updated to branch 1713 or later. - backend = browser._browser_backend # pylint: disable=W0212 - self._chrome_branch_number = getattr(backend, 'chrome_branch_number', None) - if (not self._chrome_branch_number or - (sys.platform != 'android' and self._chrome_branch_number < 1713)): - raise page_test.TestNotSupportedOnPlatformFailure( - 'rasterize_and_record_micro requires Chrome branch 1713 ' - 'or later. Skipping measurement.') - def ValidateAndMeasurePage(self, page, tab, results): try: tab.WaitForDocumentReadyStateToBeComplete() @@ -76,28 +65,32 @@ record_time = data['record_time_ms'] pixels_rasterized = data['pixels_rasterized'] rasterize_time = data['rasterize_time_ms'] + # TODO(schenney): Remove this workaround when reference builds get past + # the change that adds this comment. + if ('picture_memory_usage' in data): + picture_memory_usage = data['picture_memory_usage'] + else: + picture_memory_usage = 0 results.AddValue(scalar.ScalarValue( results.current_page, 'pixels_recorded', 'pixels', pixels_recorded)) results.AddValue(scalar.ScalarValue( - results.current_page, 'record_time', 'ms', record_time)) - results.AddValue(scalar.ScalarValue( results.current_page, 'pixels_rasterized', 'pixels', pixels_rasterized)) results.AddValue(scalar.ScalarValue( results.current_page, 'rasterize_time', 'ms', rasterize_time)) - - # TODO(skyostil): Remove this temporary workaround when reference build has - # been updated to branch 1931 or later. - if ((self._chrome_branch_number and self._chrome_branch_number >= 1931) or - sys.platform == 'android'): - record_time_sk_null_canvas = data['record_time_sk_null_canvas_ms'] - record_time_painting_disabled = data['record_time_painting_disabled_ms'] - results.AddValue(scalar.ScalarValue( - results.current_page, 'record_time_sk_null_canvas', 'ms', - record_time_sk_null_canvas)) - results.AddValue(scalar.ScalarValue( - results.current_page, 'record_time_painting_disabled', 'ms', - record_time_painting_disabled)) + results.AddValue(scalar.ScalarValue( + results.current_page, 'viewport_picture_size', 'bytes', + picture_memory_usage)) + results.AddValue(scalar.ScalarValue( + results.current_page, 'record_time', 'ms', record_time)) + record_time_sk_null_canvas = data['record_time_sk_null_canvas_ms'] + record_time_painting_disabled = data['record_time_painting_disabled_ms'] + results.AddValue(scalar.ScalarValue( + results.current_page, 'record_time_sk_null_canvas', 'ms', + record_time_sk_null_canvas)) + results.AddValue(scalar.ScalarValue( + results.current_page, 'record_time_painting_disabled', 'ms', + record_time_painting_disabled)) if self._report_detailed_results: pixels_rasterized_with_non_solid_color = \ @@ -110,8 +103,17 @@ data['total_picture_layers_with_no_content'] total_picture_layers_off_screen = \ data['total_picture_layers_off_screen'] + # TODO(schenney): Remove this workaround when reference builds get past + # the change that adds this comment. + if ('total_pictures_in_pile_size' in data): + total_pictures_in_pile_size = data['total_pictures_in_pile_size'] + else: + total_pictures_in_pile_size = 0 results.AddValue(scalar.ScalarValue( + results.current_page, 'total_size_of_pictures_in_piles', 'bytes', + total_pictures_in_pile_size)) + results.AddValue(scalar.ScalarValue( results.current_page, 'pixels_rasterized_with_non_solid_color', 'pixels', pixels_rasterized_with_non_solid_color)) results.AddValue(scalar.ScalarValue(
diff --git a/tools/perf/measurements/rasterize_and_record_micro_unittest.py b/tools/perf/measurements/rasterize_and_record_micro_unittest.py index 6b2f937..ea92b00 100644 --- a/tools/perf/measurements/rasterize_and_record_micro_unittest.py +++ b/tools/perf/measurements/rasterize_and_record_micro_unittest.py
@@ -89,3 +89,16 @@ self.assertEquals(len(total_picture_layers_off_screen), 1) self.assertEqual( total_picture_layers_off_screen[0].GetRepresentativeNumber(), 0) + + viewport_picture_size = \ + results.FindAllPageSpecificValuesNamed('viewport_picture_size') + self.assertEquals(len(viewport_picture_size), 1) + self.assertGreater( + viewport_picture_size[0].GetRepresentativeNumber(), 0) + + total_size_of_pictures_in_piles = \ + results.FindAllPageSpecificValuesNamed( + 'total_size_of_pictures_in_piles') + self.assertEquals(len(total_size_of_pictures_in_piles), 1) + self.assertGreater( + total_size_of_pictures_in_piles[0].GetRepresentativeNumber(), 0)
diff --git a/tools/perf/measurements/task_execution_time.py b/tools/perf/measurements/task_execution_time.py index 48029ed5..c11f371 100644 --- a/tools/perf/measurements/task_execution_time.py +++ b/tools/perf/measurements/task_execution_time.py
@@ -10,12 +10,13 @@ from telemetry.value import scalar _CATEGORIES = ['webkit.console', - 'blink.console', - 'benchmark', - 'toplevel', - 'blink', - 'cc', - 'v8'] + 'blink.console', + 'benchmark', + 'toplevel', + 'blink', + 'blink_gc', + 'cc', + 'v8'] class TaskExecutionTime(page_test.PageTest):
diff --git a/tools/perf/page_sets/data/key_silk_cases.json b/tools/perf/page_sets/data/key_silk_cases.json index a4bfbce..40b35c9b 100644 --- a/tools/perf/page_sets/data/key_silk_cases.json +++ b/tools/perf/page_sets/data/key_silk_cases.json
@@ -8,9 +8,6 @@ "http://jsfiddle.net/3yDKh/4/embedded/result", "http://jsfiddle.net/3yDKh/6/embedded/result" ], - "key_silk_cases_018.wpr": [ - "http://jsbin.com/gikex/2/quiet" - ], "key_silk_cases_015.wpr": [ "http://jsfiddle.net/bNp2h/3/show/" ], @@ -106,4 +103,4 @@ "http://wiltzius.github.io/shape-shifter/" ] } -} \ No newline at end of file +}
diff --git a/tools/perf/page_sets/data/key_silk_cases_018.wpr.sha1 b/tools/perf/page_sets/data/key_silk_cases_018.wpr.sha1 deleted file mode 100644 index e51cbfb..0000000 --- a/tools/perf/page_sets/data/key_silk_cases_018.wpr.sha1 +++ /dev/null
@@ -1 +0,0 @@ -0e34d3101a9dafc9f33f641dabf1c7026b678495 \ No newline at end of file
diff --git a/tools/perf/page_sets/image_decoding_cases.py b/tools/perf/page_sets/image_decoding_cases.py new file mode 100644 index 0000000..902cabda --- /dev/null +++ b/tools/perf/page_sets/image_decoding_cases.py
@@ -0,0 +1,27 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +from telemetry.page import page as page_module +from telemetry.page import page_set as page_set_module + +class ImageDecodingCasesPage(page_module.Page): + + def __init__(self, url, page_set): + super(ImageDecodingCasesPage, self).__init__(url=url, page_set=page_set) + + def RunSmoothness(self, action_runner): + action_runner.Wait(5) + +class ImageDecodingCasesPageSet(page_set_module.PageSet): + + """ A directed benchmark of accelerated jpeg image decoding performance """ + + def __init__(self): + super(ImageDecodingCasesPageSet, self).__init__() + + urls_list = [ + 'file://image_decoding_cases/yuv_decoding.html' + ] + + for url in urls_list: + self.AddPage(ImageDecodingCasesPage(url, self))
diff --git a/tools/perf/page_sets/image_decoding_cases/yuv_decoding.html b/tools/perf/page_sets/image_decoding_cases/yuv_decoding.html new file mode 100644 index 0000000..12a0e8f3 --- /dev/null +++ b/tools/perf/page_sets/image_decoding_cases/yuv_decoding.html
@@ -0,0 +1,40 @@ +<!DOCTYPE html> +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> + <title>JPEG image decoding</title> +</head> +<body> +<img id="myimg"> +<script> +var image_width = 1024; +var image_height = 1024; +var nb_images = 200; +var urls = []; + +for (i = 0; i < nb_images; ++i) { + var canvas = document.createElement("canvas"); + canvas.width = image_width; + canvas.height = image_height; + var ctx = canvas.getContext("2d"); + ctx.fillStyle = "rgb("+ + Math.floor(Math.random()*256)+","+ + Math.floor(Math.random()*256)+","+ + Math.floor(Math.random()*256)+")"; + ctx.fillRect(0,0,image_width,image_height); + // If quality is 1, then we get YUV 444 encoding + // If quality is <1, then we get YUV 420 encoding + urls[i] = canvas.toDataURL("image/jpeg", 0.99); +} + +var idx = 0; +function redraw() { + document.getElementById("myimg").src = urls[idx]; + idx++; + if (idx >= nb_images) { idx = 0; } + window.setTimeout(redraw, 1); +} +window.setTimeout(redraw, 1); +</script> +</body> +</html>
diff --git a/tools/perf/page_sets/key_silk_cases.py b/tools/perf/page_sets/key_silk_cases.py index 8326c39a..bc257a9 100644 --- a/tools/perf/page_sets/key_silk_cases.py +++ b/tools/perf/page_sets/key_silk_cases.py
@@ -632,21 +632,6 @@ interaction.End() -class TextSizeAnimation(KeySilkCasesPage): - - """ Why: Scale animation with text. """ - - def __init__(self, page_set): - super(TextSizeAnimation, self).__init__( - url='http://jsbin.com/gikex/2/quiet', - page_set=page_set) - - self.gpu_raster = True - - def RunSmoothness(self, action_runner): - action_runner.Wait(4) - - class SilkFinance(KeySilkCasesPage): """ Why: Some effects repaint the page, possibly including plenty of text. """ @@ -704,5 +689,4 @@ self.AddPage(Page26(self)) self.AddPage(SVGIconRaster(self)) self.AddPage(UpdateHistoryState(self)) - self.AddPage(TextSizeAnimation(self)) self.AddPage(SilkFinance(self))
diff --git a/tools/perf/unit-info.json b/tools/perf/unit-info.json index fcba83b..8cfe56a9 100644 --- a/tools/perf/unit-info.json +++ b/tools/perf/unit-info.json
@@ -183,7 +183,7 @@ "seconds": { "improvement_direction": "down" }, - "tasks_per_frame": { + "tasks": { "improvement_direction": "down" }, "us": {
diff --git a/tools/run-bisect-perf-regression.py b/tools/run-bisect-perf-regression.py index 24360152..b1aaceb 100755 --- a/tools/run-bisect-perf-regression.py +++ b/tools/run-bisect-perf-regression.py
@@ -14,6 +14,7 @@ import optparse import os import platform +import re import subprocess import sys import traceback @@ -21,6 +22,7 @@ from auto_bisect import bisect_perf_regression from auto_bisect import bisect_utils from auto_bisect import math_utils +from auto_bisect import source_control CROS_BOARD_ENV = 'BISECT_CROS_BOARD' CROS_IP_ENV = 'BISECT_CROS_IP' @@ -236,97 +238,35 @@ return bisect_perf_regression.BisectOptions.FromDict(opts_dict) -def _ParseCloudLinksFromOutput(output, bucket): - cloud_file_links = [t for t in output.splitlines() - if 'storage.googleapis.com/chromium-telemetry/%s/' % bucket in t] +def _ParseCloudLinksFromOutput(output): + html_results_pattern = re.compile( + r'\s(?P<VALUES>http://storage.googleapis.com/' + + 'chromium-telemetry/html-results/results-[a-z0-9-_]+)\s', + re.MULTILINE) + profiler_pattern = re.compile( + r'\s(?P<VALUES>https://console.developers.google.com/' + + 'm/cloudstorage/b/[a-z-]+/o/profiler-[a-z0-9-_.]+)\s', + re.MULTILINE) - # What we're getting here is basically "View online at http://..." so parse - # out just the URL portion. - for i in xrange(len(cloud_file_links)): - cloud_file_link = cloud_file_links[i] - cloud_file_link = [t for t in cloud_file_link.split(' ') - if 'storage.googleapis.com/chromium-telemetry/%s/' % bucket in t] - assert cloud_file_link, 'Couldn\'t parse URL from output.' - cloud_file_links[i] = cloud_file_link[0] - return cloud_file_links + results = { + 'html-results': html_results_pattern.findall(output), + 'profiler': profiler_pattern.findall(output), + } + + return results -def _RunPerformanceTest(config): - """Runs a performance test with and without the current patch. +def _ParseAndOutputCloudLinks(results_without_patch, results_with_patch): + cloud_links_without_patch = _ParseCloudLinksFromOutput( + results_without_patch[2]) + cloud_links_with_patch = _ParseCloudLinksFromOutput( + results_with_patch[2]) - Args: - config: Contents of the config file, a dictionary. + cloud_file_link = (cloud_links_without_patch['html-results'][0] + if cloud_links_without_patch['html-results'] else '') - Attempts to build and run the current revision with and without the - current patch, with the parameters passed in. - """ - # Bisect script expects to be run from the src directory - os.chdir(SRC_DIR) - - bisect_utils.OutputAnnotationStepStart('Building With Patch') - - opts = _CreateBisectOptionsFromConfig(config) - b = bisect_perf_regression.BisectPerformanceMetrics(opts, os.getcwd()) - - if bisect_utils.RunGClient(['runhooks']): - raise RuntimeError('Failed to run gclient runhooks') - - if not b.ObtainBuild('chromium'): - raise RuntimeError('Patched version failed to build.') - - bisect_utils.OutputAnnotationStepClosed() - bisect_utils.OutputAnnotationStepStart('Running With Patch') - - results_with_patch = b.RunPerformanceTestAndParseResults( - opts.command, - opts.metric, - reset_on_first_run=True, - upload_on_last_run=True, - results_label='Patch') - - if results_with_patch[1]: - raise RuntimeError('Patched version failed to run performance test.') - - bisect_utils.OutputAnnotationStepClosed() - - bisect_utils.OutputAnnotationStepStart('Reverting Patch') - # TODO: When this is re-written to recipes, this should use bot_update's - # revert mechanism to fully revert the client. But for now, since we know that - # the perf try bot currently only supports src/ and src/third_party/WebKit, we - # simply reset those two directories. - bisect_utils.CheckRunGit(['reset', '--hard']) - bisect_utils.CheckRunGit(['reset', '--hard'], - os.path.join('third_party', 'WebKit')) - bisect_utils.OutputAnnotationStepClosed() - - bisect_utils.OutputAnnotationStepStart('Building Without Patch') - - if bisect_utils.RunGClient(['runhooks']): - raise RuntimeError('Failed to run gclient runhooks') - - if not b.ObtainBuild('chromium'): - raise RuntimeError('Unpatched version failed to build.') - - bisect_utils.OutputAnnotationStepClosed() - bisect_utils.OutputAnnotationStepStart('Running Without Patch') - - results_without_patch = b.RunPerformanceTestAndParseResults( - opts.command, opts.metric, upload_on_last_run=True, results_label='ToT') - - if results_without_patch[1]: - raise RuntimeError('Unpatched version failed to run performance test.') - - # Find the link to the cloud stored results file. - cloud_file_link = _ParseCloudLinksFromOutput( - results_without_patch[2], 'html-results') - - cloud_file_link = cloud_file_link[0] if cloud_file_link else '' - - profiler_file_links_with_patch = _ParseCloudLinksFromOutput( - results_with_patch[2], 'profiling-results') - - profiler_file_links_without_patch = _ParseCloudLinksFromOutput( - results_without_patch[2], 'profiling-results') + profiler_file_links_with_patch = cloud_links_with_patch['profiler'] + profiler_file_links_without_patch = cloud_links_without_patch['profiler'] # Calculate the % difference in the means of the 2 runs. percent_diff_in_means = None @@ -338,7 +278,6 @@ std_err = math_utils.PooledStandardError( [results_with_patch[0]['values'], results_without_patch[0]['values']]) - bisect_utils.OutputAnnotationStepClosed() if percent_diff_in_means is not None and std_err is not None: bisect_utils.OutputAnnotationStepStart('Results - %.02f +- %0.02f delta' % (percent_diff_in_means, std_err)) @@ -367,6 +306,129 @@ profiler_file_links_without_patch[i]) +def _ResolveRevisionsFromConfig(config): + if not 'good_revision' in config and not 'bad_revision' in config: + return (None, None) + + bad_revision = source_control.ResolveToRevision( + config['bad_revision'], 'chromium', bisect_utils.DEPOT_DEPS_NAME, 100) + if not bad_revision: + raise RuntimeError('Failed to resolve [%s] to git hash.', + config['bad_revision']) + good_revision = source_control.ResolveToRevision( + config['good_revision'], 'chromium', bisect_utils.DEPOT_DEPS_NAME, -100) + if not good_revision: + raise RuntimeError('Failed to resolve [%s] to git hash.', + config['good_revision']) + + return (good_revision, bad_revision) + + +def _GetStepAnnotationStringsDict(config): + if 'good_revision' in config and 'bad_revision' in config: + return { + 'build1': 'Building [%s]' % config['good_revision'], + 'build2': 'Building [%s]' % config['bad_revision'], + 'run1': 'Running [%s]' % config['good_revision'], + 'run2': 'Running [%s]' % config['bad_revision'], + 'results_label1': config['good_revision'], + 'results_label2': config['bad_revision'], + } + else: + return { + 'build1': 'Building With Patch', + 'build2': 'Building Without Patch', + 'run1': 'Running With Patch', + 'run2': 'Running Without Patch', + 'results_label1': 'Patch', + 'results_label2': 'ToT', + } + + +def _RunBuildStepForPerformanceTest(bisect_instance, build_string, revision): + if revision: + bisect_utils.OutputAnnotationStepStart('Syncing [%s]' % revision) + if not source_control.SyncToRevision(revision, 'gclient'): + raise RuntimeError('Failed to sync to [%s].' % revision) + bisect_utils.OutputAnnotationStepClosed() + + bisect_utils.OutputAnnotationStepStart(build_string) + + if bisect_utils.RunGClient(['runhooks']): + raise RuntimeError('Failed to run gclient runhooks') + + if not bisect_instance.ObtainBuild('chromium'): + raise RuntimeError('Patched version failed to build.') + + bisect_utils.OutputAnnotationStepClosed() + + +def _RunCommandStepForPerformanceTest(bisect_instance, + opts, + reset_on_first_run, + upload_on_last_run, + results_label, + run_string): + bisect_utils.OutputAnnotationStepStart(run_string) + + results = bisect_instance.RunPerformanceTestAndParseResults( + opts.command, + opts.metric, + reset_on_first_run=reset_on_first_run, + upload_on_last_run=upload_on_last_run, + results_label=results_label) + + if results[1]: + raise RuntimeError('Patched version failed to run performance test.') + + bisect_utils.OutputAnnotationStepClosed() + + return results + + +def _RunPerformanceTest(config): + """Runs a performance test with and without the current patch. + + Args: + config: Contents of the config file, a dictionary. + + Attempts to build and run the current revision with and without the + current patch, with the parameters passed in. + """ + # Bisect script expects to be run from the src directory + os.chdir(SRC_DIR) + + opts = _CreateBisectOptionsFromConfig(config) + revisions = _ResolveRevisionsFromConfig(config) + annotations_dict = _GetStepAnnotationStringsDict(config) + b = bisect_perf_regression.BisectPerformanceMetrics(opts, os.getcwd()) + + _RunBuildStepForPerformanceTest(b, annotations_dict['build1'], revisions[0]) + + results_with_patch = _RunCommandStepForPerformanceTest( + b, opts, True, True, annotations_dict['results_label1'], + annotations_dict['run1']) + + bisect_utils.OutputAnnotationStepStart('Reverting Patch') + # TODO: When this is re-written to recipes, this should use bot_update's + # revert mechanism to fully revert the client. But for now, since we know that + # the perf try bot currently only supports src/ and src/third_party/WebKit, we + # simply reset those two directories. + bisect_utils.CheckRunGit(['reset', '--hard']) + bisect_utils.CheckRunGit(['reset', '--hard'], + os.path.join('third_party', 'WebKit')) + bisect_utils.OutputAnnotationStepClosed() + + _RunBuildStepForPerformanceTest(b, annotations_dict['build2'], revisions[1]) + + results_without_patch = _RunCommandStepForPerformanceTest( + b, opts, False, True, annotations_dict['results_label2'], + annotations_dict['run1']) + + # Find the link to the cloud stored results file. + _ParseAndOutputCloudLinks(results_without_patch, results_with_patch) + + def _SetupAndRunPerformanceTest(config, path_to_goma): """Attempts to build and run the current revision with and without the current patch, with the parameters passed in.
diff --git a/tools/telemetry/telemetry/core/backends/chrome/cros_browser_backend.py b/tools/telemetry/telemetry/core/backends/chrome/cros_browser_backend.py index 1c3d657..f3a6024 100644 --- a/tools/telemetry/telemetry/core/backends/chrome/cros_browser_backend.py +++ b/tools/telemetry/telemetry/core/backends/chrome/cros_browser_backend.py
@@ -128,7 +128,7 @@ forwarders.PortPairs( http=forwarders.PortPair(self._port, self._remote_debugging_port), https=None, - dns=None), forwarding_flag='L') + dns=None), use_remote_port_forwarding=False) # Wait for oobe. self._WaitForBrowserToComeUp(wait_for_extensions=False)
diff --git a/tools/telemetry/telemetry/core/backends/chrome/inspector_backend.py b/tools/telemetry/telemetry/core/backends/chrome/inspector_backend.py index 9674882..de67274c 100644 --- a/tools/telemetry/telemetry/core/backends/chrome/inspector_backend.py +++ b/tools/telemetry/telemetry/core/backends/chrome/inspector_backend.py
@@ -45,7 +45,7 @@ elif not self._browser_backend.HasBrowserFinishedLaunching(): raise exceptions.BrowserConnectionGoneException(self.app, err_msg) else: - raise exceptions.TabCrashException(self.app, err_msg) + raise exceptions.DevtoolsTargetCrashException(self.app, err_msg) self._console = inspector_console.InspectorConsole(self) self._memory = inspector_memory.InspectorMemory(self)
diff --git a/tools/telemetry/telemetry/core/forwarders/cros_forwarder.py b/tools/telemetry/telemetry/core/forwarders/cros_forwarder.py index dbc0993..6757504 100644 --- a/tools/telemetry/telemetry/core/forwarders/cros_forwarder.py +++ b/tools/telemetry/telemetry/core/forwarders/cros_forwarder.py
@@ -16,20 +16,21 @@ super(CrOsForwarderFactory, self).__init__() self._cri = cri - def Create(self, port_pairs, forwarding_flag='R'): # pylint: disable=W0221 + # pylint: disable=arguments-differ + def Create(self, port_pairs, use_remote_port_forwarding=True): if self._cri.local: return do_nothing_forwarder.DoNothingForwarder(port_pairs) - return CrOsSshForwarder(self._cri, forwarding_flag, port_pairs) + return CrOsSshForwarder(self._cri, use_remote_port_forwarding, port_pairs) class CrOsSshForwarder(forwarders.Forwarder): - def __init__(self, cri, forwarding_flag, port_pairs): + def __init__(self, cri, use_remote_port_forwarding, port_pairs): super(CrOsSshForwarder, self).__init__(port_pairs) self._cri = cri self._proc = None forwarding_args = self._ForwardingArgs( - forwarding_flag, self.host_ip, port_pairs) + use_remote_port_forwarding, self.host_ip, port_pairs) self._proc = subprocess.Popen( self._cri.FormSSHCommandLine(['sleep', '999999999'], forwarding_args), stdout=subprocess.PIPE, @@ -42,9 +43,8 @@ # pylint: disable=unused-argument @staticmethod - def _ForwardingArgs(forwarding_flag, host_ip, port_pairs): - assert forwarding_flag in ('-R', '-L'), 'Forwarding flag requires -R or -L.' - if forwarding_flag == '-R': + def _ForwardingArgs(use_remote_port_forwarding, host_ip, port_pairs): + if use_remote_port_forwarding: arg_format = '-R{pp.remote_port}:{host_ip}:{pp.local_port}' else: arg_format = '-L{pp.local_port}:{host_ip}:{pp.remote_port}'
diff --git a/tools/telemetry/telemetry/core/forwarders/cros_forwarder_unittest.py b/tools/telemetry/telemetry/core/forwarders/cros_forwarder_unittest.py index c8fe585..d160a12 100644 --- a/tools/telemetry/telemetry/core/forwarders/cros_forwarder_unittest.py +++ b/tools/telemetry/telemetry/core/forwarders/cros_forwarder_unittest.py
@@ -8,7 +8,7 @@ from telemetry.core.forwarders import cros_forwarder # pylint: disable=W0212 -class ForwardingAgsTest(unittest.TestCase): +class ForwardingArgsTest(unittest.TestCase): port_pairs = forwarders.PortPairs( http=forwarders.PortPair(111, 222), https=forwarders.PortPair(333, 444), @@ -16,19 +16,16 @@ def testForwardingArgsReverse(self): forwarding_args = cros_forwarder.CrOsSshForwarder._ForwardingArgs( - forwarding_flag='-R', host_ip='5.5.5.5', port_pairs=self.port_pairs) + use_remote_port_forwarding=True, host_ip='5.5.5.5', + port_pairs=self.port_pairs) self.assertEqual( ['-R222:5.5.5.5:111', '-R444:5.5.5.5:333'], forwarding_args) def testForwardingArgs(self): forwarding_args = cros_forwarder.CrOsSshForwarder._ForwardingArgs( - forwarding_flag='-L', host_ip='2.2.2.2', port_pairs=self.port_pairs) + use_remote_port_forwarding=False, host_ip='2.2.2.2', + port_pairs=self.port_pairs) self.assertEqual( ['-L111:2.2.2.2:222', '-L333:2.2.2.2:444'], forwarding_args) - - def testBadForwardingFlagRaises(self): - with self.assertRaises(AssertionError): - _ = cros_forwarder.CrOsSshForwarder._ForwardingArgs( - '-X', '1.1.1.1', self.port_pairs) \ No newline at end of file
diff --git a/tools/telemetry/telemetry/core/platform/tracing_controller_backend.py b/tools/telemetry/telemetry/core/platform/tracing_controller_backend.py index 87f3269c..9edaa88f 100644 --- a/tools/telemetry/telemetry/core/platform/tracing_controller_backend.py +++ b/tools/telemetry/telemetry/core/platform/tracing_controller_backend.py
@@ -21,20 +21,7 @@ assert isinstance(trace_options, tracing_options.TracingOptions) - num_running_browser_backends = len(self.running_browser_backends) - if num_running_browser_backends != 1: - # Note: it is possible to implement tracing for both the case of 0 and >1. - # For >1, we just need to merge the trace files at StopTracing. - # - # For 0, we want to modify chrome's trace-startup to support leaving - # tracing on indefinitely. Then have the backend notify the platform - # and the tracing controller that it is starting a browser, have - # the controller add in the trace-startup command, and then when we get - # the Stop message or the DidStopBrowser(), issue the stop tracing command - # on the right backend. - raise NotImplementedError( - 'Start tracing does not support the case of %i running browser ' - 'instances' % num_running_browser_backends) + self._AssertOneBrowserBackend() self._current_trace_options = trace_options self._current_category_filter = category_filter @@ -45,10 +32,8 @@ trace_options, category_filter.filter_string, timeout) def Stop(self): - if not self.is_tracing_running: - raise Exception('Not tracing') - if len(self.running_browser_backends) != 1: - raise NotImplementedError() + assert self.is_tracing_running, 'Can only stop tracing when tracing.' + self._AssertOneBrowserBackend() result = None if self._current_trace_options.enable_chrome_trace: @@ -59,6 +44,20 @@ self._current_category_filter = None return result + def _AssertOneBrowserBackend(self): + # Note: it is possible to implement tracing for both the case of 0 and >1. + # For >1, we just need to merge the trace files at StopTracing. + # + # For 0, we want to modify chrome's trace-startup to support leaving + # tracing on indefinitely. Then have the backend notify the platform + # and the tracing controller that it is starting a browser, have + # the controller add in the trace-startup command, and then when we get + # the Stop message or the DidStopBrowser(), issue the stop tracing command + # on the right backend. + num_instances = len(self.running_browser_backends) + assert num_instances == 1, ( + 'Tracing only supports one browser instance (not %i).' % num_instances) + def IsChromeTracingSupported(self, browser): browser_backend = self._platform_backend.GetBackendForBrowser(browser) return browser_backend.supports_tracing
diff --git a/tools/telemetry/telemetry/user_story/user_story_runner.py b/tools/telemetry/telemetry/user_story/user_story_runner.py index 57d07f10..bdc9a40 100644 --- a/tools/telemetry/telemetry/user_story/user_story_runner.py +++ b/tools/telemetry/telemetry/user_story/user_story_runner.py
@@ -241,9 +241,6 @@ except Exception: # Tear down & restart the state for unhandled exceptions thrown by # _RunUserStoryAndProcessErrorIfNeeded. - exception_formatter.PrintFormattedException( - msg='Unhandled exception while running %s' % - user_story.display_name) results.AddValue(failure.FailureValue(user_story, sys.exc_info())) state.TearDownState(results) state = group.shared_user_story_state_class(
diff --git a/tools/valgrind/browser_wrapper_win.py b/tools/valgrind/browser_wrapper_win.py index ee0a961..0023ca7 100644 --- a/tools/valgrind/browser_wrapper_win.py +++ b/tools/valgrind/browser_wrapper_win.py
@@ -26,7 +26,7 @@ # Usually, we pass "-logdir" "foo\bar\spam path" args to Dr. Memory. # To group reports per UI test, we want to put the reports for each test into a # separate directory. This code can be simplified when we have -# http://code.google.com/p/drmemory/issues/detail?id=684 fixed. +# https://github.com/DynamoRIO/drmemory/issues/684 fixed. logdir_idx = cmd_to_run.index("-logdir") old_logdir = cmd_to_run[logdir_idx + 1]
diff --git a/tools/valgrind/drmemory/suppressions.txt b/tools/valgrind/drmemory/suppressions.txt index 5dfc58ba..737cc8618 100644 --- a/tools/valgrind/drmemory/suppressions.txt +++ b/tools/valgrind/drmemory/suppressions.txt
@@ -45,32 +45,32 @@ # private symbols so may need to be updated when we switch to auto-loading PDBs UNADDRESSABLE ACCESS -name=http://code.google.com/p/drmemory/issues/detail?id=12 UNADDR +name=https://github.com/DynamoRIO/drmemory/issues/12 UNADDR ... SHELL32.dll!SHFileOperation* UNADDRESSABLE ACCESS -name=http://code.google.com/p/drmemory/issues/detail?id=40 UNADDR +name=https://github.com/DynamoRIO/drmemory/issues/40 UNADDR ... WINSPOOL.DRV!* INVALID HEAP ARGUMENT -name=http://code.google.com/p/drmemory/issues/detail?id=40 INVALID HEAP +name=https://github.com/DynamoRIO/drmemory/issues/40 INVALID HEAP ... WINSPOOL.DRV!* UNADDRESSABLE ACCESS -name=http://code.google.com/p/drmemory/issues/detail?id=59 +name=https://github.com/DynamoRIO/drmemory/issues/59 ... *!SetEnvironmentVariable* UNADDRESSABLE ACCESS -name=http://code.google.com/p/drmemory/issues/detail?id=68 (UNADDR 1) +name=https://github.com/DynamoRIO/drmemory/issues/68 (UNADDR 1) ... MSWSOCK.dll!WSPStartup UNADDRESSABLE ACCESS -name=http://code.google.com/p/drmemory/issues/detail?id=68 (UNADDR 2) +name=https://github.com/DynamoRIO/drmemory/issues/68 (UNADDR 2) ... ntdll.dll!RtlValidateUnicodeString @@ -132,7 +132,7 @@ base_unittests.exe!operator new[] base_unittests.exe!base::ToolsSanityTest_MemoryLeak_Test::TestBody -# "..." is needed due to http://code.google.com/p/drmemory/issues/detail?id=666 +# "..." is needed due to https://github.com/DynamoRIO/drmemory/issues/666 UNADDRESSABLE ACCESS name=sanity test 02 (malloc/read left) base_unittests.exe!*ReadValueOutOfArrayBoundsLeft @@ -157,7 +157,7 @@ base_unittests.exe!*MakeSomeErrors base_unittests.exe!base::ToolsSanityTest_AccessesToMallocMemory_Test::TestBody -# "..." is needed due to http://code.google.com/p/drmemory/issues/detail?id=666 +# "..." is needed due to https://github.com/DynamoRIO/drmemory/issues/666 UNADDRESSABLE ACCESS name=sanity test 06 (new/read left) base_unittests.exe!*ReadValueOutOfArrayBoundsLeft @@ -252,7 +252,7 @@ igdumd32.dll!* UNADDRESSABLE ACCESS -name=http://code.google.com/p/drmemory/issues/detail?id=582 bizarre cl-generated read-beyond-TOS +name=https://github.com/DynamoRIO/drmemory/issues/582 bizarre cl-generated read-beyond-TOS instruction=mov 0xfffffffc(%esp) -> %eax chrome.dll!blink::RenderStyle::resetBorder* @@ -271,7 +271,7 @@ *!sandbox::GetPathFromHandle GDI USAGE ERROR -name=http://code.google.com/p/drmemory/issues/detail?id=899 deleting bitmap which is probably safe +name=https://github.com/DynamoRIO/drmemory/issues/899 deleting bitmap which is probably safe system call NtGdiDeleteObjectApp *!skia::`anonymous namespace'::Bitmap::~Bitmap *!skia::`anonymous namespace'::Bitmap::`scalar deleting destructor' @@ -325,7 +325,7 @@ name=http://crbug.com/119552 c # optional gdi32.dll frame followed by user32.dll # TODO(bruening): once have -# http://code.google.com/p/drmemory/issues/detail?id=846 +# https://github.com/DynamoRIO/drmemory/issues/846 # I would do "gdi32.dll!...\nuser32.dll!*" *32.dll!* ... @@ -462,7 +462,7 @@ system call NtCreateSection KERNELBASE.dll!CreateFileMappingW base.dll!base::SharedMemory::Create -base.dll!base::SharedMemory::CreateAndMapAnonymous +base.dll!base::SharedMemory::CreateAnonymous content.dll!content::ChildThread::AllocateSharedMemory content.dll!content::ChildSharedBitmapManager::AllocateSharedBitmap cc.dll!cc::ResourceProvider::CreateBitmap @@ -525,7 +525,7 @@ *!blink::RenderBlock::layout HANDLE LEAK -name=https://code.google.com/p/drmemory/issues/detail?id=1545 +name=https://github.com/DynamoRIO/drmemory/issues/1545 system call NtGdiCreateCompatibleDC GDI32.dll!CreateCompatibleDC skia.dll!LogFontTypeface::onGetTableData @@ -603,9 +603,9 @@ # This suppression is deliberately general, as bugs reported in # v8 generated code are difficult to track down. Xref Dr. Memory issue -# https://code.google.com/p/drmemory/issues/detail?id=1582 +# https://github.com/DynamoRIO/drmemory/issues/1582 UNADDRESSABLE ACCESS -name=https://code.google.com/p/drmemory/issues/detail?id=1582 +name=https://github.com/DynamoRIO/drmemory/issues/1582 ... *!v8::internal::Invoke *!v8::internal::Execution::Call @@ -623,11 +623,11 @@ *!content::RenderViewHostImpl::CreateRenderView UNADDRESSABLE ACCESS -name=http://code.google.com/p/dynamorio/issues/detail?id=1443 +name=https://github.com/DynamoRIO/dynamorio/issues/1443 dynamorio.dll!* UNINITIALIZED READ -name=http://code.google.com/p/dynamorio/issues/detail?id=1443 (another instance) +name=https://github.com/DynamoRIO/dynamorio/issues/1443 (another instance) dynamorio.dll!* UNADDRESSABLE ACCESS
diff --git a/tools/valgrind/drmemory/suppressions_full.txt b/tools/valgrind/drmemory/suppressions_full.txt index 3cfad23..050e507 100644 --- a/tools/valgrind/drmemory/suppressions_full.txt +++ b/tools/valgrind/drmemory/suppressions_full.txt
@@ -16,7 +16,7 @@ # TODO(timurrrr): check if these frames change when NT_SYMBOLS are present. LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=406 +name=https://github.com/DynamoRIO/drmemory/issues/406 ADVAPI32.dll!WmiOpenBlock ADVAPI32.dll!WmiOpenBlock @@ -28,7 +28,7 @@ # They deliberately use uninit local var in sqlite random generator. # Random bytes may mess up the call stack between randomByte and -# sqlite3_* frames (http://code.google.com/p/drmemory/issues/detail?id=1514) +# sqlite3_* frames (https://github.com/DynamoRIO/drmemory/issues/1514) # so we just look for randomByte. UNINITIALIZED READ name=sqlite3_randomness UNINIT @@ -76,168 +76,168 @@ # Please note: the following suppressions were written in the abscense of # private symbols so may need to be updated when we switch to auto-loading PDBs UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=12 (1) +name=https://github.com/DynamoRIO/drmemory/issues/12 (1) ntdll.dll!Rtl* ntdll.dll!Rtl* ntdll.dll!RtlFindActivationContextSectionString UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=12 (2) +name=https://github.com/DynamoRIO/drmemory/issues/12 (2) ... SHELL32.dll!SHFileOperation* UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=12 (3) +name=https://github.com/DynamoRIO/drmemory/issues/12 (3) ... SHELL32.dll!SHGetFolderPath* LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=12 (4) +name=https://github.com/DynamoRIO/drmemory/issues/12 (4) ... SHELL32.dll!SHGetFolderPath* UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=12 (5) +name=https://github.com/DynamoRIO/drmemory/issues/12 (5) ... SHELL32.dll!SHCreateDirectory* UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=12 (6) +name=https://github.com/DynamoRIO/drmemory/issues/12 (6) ... SHELL32.dll!ILLoadFromStream* UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=12 (7) +name=https://github.com/DynamoRIO/drmemory/issues/12 (7) ... SHELL32.dll!ILSaveToStream* LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=12 (8) +name=https://github.com/DynamoRIO/drmemory/issues/12 (8) ... SHELL32.dll!SHFileOperation* UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=12 (9) +name=https://github.com/DynamoRIO/drmemory/issues/12 (9) ... SHELL32.dll!SHGetItemFromDataObject LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=12 (10) +name=https://github.com/DynamoRIO/drmemory/issues/12 (10) ... SHELL32.dll!SHGetItemFromDataObject LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=12 (11) +name=https://github.com/DynamoRIO/drmemory/issues/12 (11) ... ole32.dll!* SHELL32.dll!SHChangeNotifySuspendResume UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=14 (1) +name=https://github.com/DynamoRIO/drmemory/issues/14 (1) ... *!CreateProcess* LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=14 (2) +name=https://github.com/DynamoRIO/drmemory/issues/14 (2) ... *!CreateProcess* UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=14 (3) +name=https://github.com/DynamoRIO/drmemory/issues/14 (3) ... *!base::LaunchApp* UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=17 (1) +name=https://github.com/DynamoRIO/drmemory/issues/17 (1) ... *!CreateWindow* POSSIBLE LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=17 (2) +name=https://github.com/DynamoRIO/drmemory/issues/17 (2) GDI32.dll!* GDI32.dll!CreateFontIndirectExW GDI32.dll!CreateFontIndirectW LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=17 (3) +name=https://github.com/DynamoRIO/drmemory/issues/17 (3) KERNELBASE.dll!LocalAlloc ... USER32.dll!CreateWindow* UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=18 a +name=https://github.com/DynamoRIO/drmemory/issues/18 a ... *!CoInitialize* UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=18 b +name=https://github.com/DynamoRIO/drmemory/issues/18 b ... *!CoCreateInstance* UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=18 c +name=https://github.com/DynamoRIO/drmemory/issues/18 c ... *!CoUninitialize* UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=18 d +name=https://github.com/DynamoRIO/drmemory/issues/18 d ... UxTheme.dll!* UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=40 a +name=https://github.com/DynamoRIO/drmemory/issues/40 a ... WINSPOOL.DRV!* LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=40 b +name=https://github.com/DynamoRIO/drmemory/issues/40 b ... WINSPOOL.DRV!* UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=48 a +name=https://github.com/DynamoRIO/drmemory/issues/48 a system call NtContinue ... *!*SetThreadName UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=48 b +name=https://github.com/DynamoRIO/drmemory/issues/48 b system call NtContinue *!WTF::initializeCurrentThreadInternal UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=52 a +name=https://github.com/DynamoRIO/drmemory/issues/52 a ... DBGHELP.dll!SymInitialize UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=52 b +name=https://github.com/DynamoRIO/drmemory/issues/52 b ... DBGHELP.dll!SymEnumSourceFiles UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=52 c +name=https://github.com/DynamoRIO/drmemory/issues/52 c ... msvcrt.dll!_RTDynamicCast UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=52 bit-level fp in dbghelp +name=https://github.com/DynamoRIO/drmemory/issues/52 bit-level fp in dbghelp instruction=test 0x*(%*) $0x?? DBGHELP.dll!SymUnloadModule64 UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=53 +name=https://github.com/DynamoRIO/drmemory/issues/53 ADVAPI32.dll!WmiMofEnumerateResourcesA ADVAPI32.dll!WmiMofEnumerateResourcesA ADVAPI32.dll!Sta*TraceW UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=58 +name=https://github.com/DynamoRIO/drmemory/issues/58 ... *!_cfltcvt_l UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=60 +name=https://github.com/DynamoRIO/drmemory/issues/60 USP10.dll!* ... USP10.dll!ScriptStringAnalyse @@ -250,65 +250,65 @@ USER32.dll!IMPSetIMEA UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=65 a +name=https://github.com/DynamoRIO/drmemory/issues/65 a ... *!SystemFunction036 UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=65 b +name=https://github.com/DynamoRIO/drmemory/issues/65 b ... *!talk_base::CreateRandomString UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=68 a +name=https://github.com/DynamoRIO/drmemory/issues/68 a ... WS2_32.dll!* UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=68 b +name=https://github.com/DynamoRIO/drmemory/issues/68 b ... ADVAPI32.dll!SetSecurityDescriptorDacl UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=68 c +name=https://github.com/DynamoRIO/drmemory/issues/68 c ... MSWSOCK.dll!WSPStartup UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=68 d +name=https://github.com/DynamoRIO/drmemory/issues/68 d ... ntdll.dll!RtlValidateUnicodeString LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=256 +name=https://github.com/DynamoRIO/drmemory/issues/256 *!_mtinit *!__tmainCRTStartup *!mainCRTStartup POSSIBLE LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=274 a +name=https://github.com/DynamoRIO/drmemory/issues/274 a ... GDI32.dll!CreateDCW LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=274 b +name=https://github.com/DynamoRIO/drmemory/issues/274 b ... GDI32.dll!CreateDCW LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=275 +name=https://github.com/DynamoRIO/drmemory/issues/275 ... *!_getptd* UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=276 +name=https://github.com/DynamoRIO/drmemory/issues/276 ... ntdll.dll!RtlConvertUlongToLargeInteger ntdll.dll!RtlConvertUlongToLargeInteger ntdll.dll!KiUserExceptionDispatcher LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=305 +name=https://github.com/DynamoRIO/drmemory/issues/305 *!free *!free *!operator new @@ -316,57 +316,57 @@ *!MiniDumpWriteDump UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=346 a +name=https://github.com/DynamoRIO/drmemory/issues/346 a ... GDI32.dll!CloseEnhMetaFile UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=346 b +name=https://github.com/DynamoRIO/drmemory/issues/346 b GDI32.dll!SetPolyFillMode GDI32.dll!CreateICW UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=362 +name=https://github.com/DynamoRIO/drmemory/issues/362 USER32.dll!UnregisterClass* LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=382 +name=https://github.com/DynamoRIO/drmemory/issues/382 ... ntdll.dll!CsrNewThread UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=397 +name=https://github.com/DynamoRIO/drmemory/issues/397 system call NtDeviceIoControlFile InputBuffer ADVAPI32.dll!ImpersonateAnonymousToken UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=407 a +name=https://github.com/DynamoRIO/drmemory/issues/407 a system call NtRequestWaitReplyPort RPCRT4.dll!I_RpcSendReceive RPCRT4.dll!NdrSendReceive UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=407 b +name=https://github.com/DynamoRIO/drmemory/issues/407 b IMM32.dll!* ntdll.dll!LdrInitializeThunk ntdll.dll!LdrShutdownThread UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=412 a +name=https://github.com/DynamoRIO/drmemory/issues/412 a ADVAPI32.dll!RegDeleteValue* UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=412 b +name=https://github.com/DynamoRIO/drmemory/issues/412 b ... ADVAPI32.dll!Crypt* UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=412 c +name=https://github.com/DynamoRIO/drmemory/issues/412 c ... RPCRT4.dll!NdrClientCall2 LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=412 d +name=https://github.com/DynamoRIO/drmemory/issues/412 d RSAENH.dll!DllUnregisterServer ... ADVAPI32.dll!CryptAcquireContextA @@ -375,17 +375,17 @@ CRYPT32.dll!CertFindCertificateInStore UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=412 e +name=https://github.com/DynamoRIO/drmemory/issues/412 e ... RSAENH.dll!CPGenRandom UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=412 f +name=https://github.com/DynamoRIO/drmemory/issues/412 f ... CRYPT??.dll!Crypt* UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=412 g +name=https://github.com/DynamoRIO/drmemory/issues/412 g *!replace_memcmp ... *!testing::internal::CmpHelperEQ* @@ -396,30 +396,30 @@ # have frame pointers, and we have trouble unwinding from it. Therefore, we use # this broad suppression, effectively disabling uninit checks in rsaenh.dll. UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=412 h +name=https://github.com/DynamoRIO/drmemory/issues/412 h RSAENH.dll!* UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=425 a +name=https://github.com/DynamoRIO/drmemory/issues/425 a CLBCatQ.DLL!DestroyStgDatabase CLBCatQ.DLL!PostError CLBCatQ.DLL!PostError LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=425 b +name=https://github.com/DynamoRIO/drmemory/issues/425 b RPCRT4.dll!I_RpcBCacheFree RPCRT4.dll!I_RpcBCacheFree ... RPCRT4.dll!NdrClientCall2 UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=425 c +name=https://github.com/DynamoRIO/drmemory/issues/425 c msdmo.dll!* msdmo.dll!* DEVENUM.DLL!* UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=435 a +name=https://github.com/DynamoRIO/drmemory/issues/435 a ... ntdll.dll!RtlSetSecurityObject ntdll.dll!RtlNewSecurityObjectEx @@ -427,7 +427,7 @@ NTMARTA.dll!AccRewriteSetNamedRights POSSIBLE LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=435 b +name=https://github.com/DynamoRIO/drmemory/issues/435 b WLDAP32.dll!Ordinal325 ... WLDAP32.dll!Ordinal325 @@ -440,34 +440,34 @@ # mod+offs suppression because the symbolic makes no sense and changes # completely in the presence of WS2_32.dll symbols. LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=438 +name=https://github.com/DynamoRIO/drmemory/issues/438 <WS2_32.dll+0x260c> <WS2_32.dll+0x2b76> <WS2_32.dll+0x2c61> UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=454 a +name=https://github.com/DynamoRIO/drmemory/issues/454 a ... WINMM.dll!wave*GetNumDevs LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=454 b +name=https://github.com/DynamoRIO/drmemory/issues/454 b ... WINMM.dll!wave*GetNumDevs LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=466 +name=https://github.com/DynamoRIO/drmemory/issues/466 ntdll.dll!RtlRunOnceBeginInitialize ntdll.dll!RtlInitializeCriticalSectionAndSpinCount UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=473 a +name=https://github.com/DynamoRIO/drmemory/issues/473 a system call NtDeviceIoControlFile InputBuffer ... iphlpapi.dll!GetAdaptersAddresses POSSIBLE LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=473 b +name=https://github.com/DynamoRIO/drmemory/issues/473 b ESENT.dll!* ESENT.dll!* ESENT.dll!* @@ -481,14 +481,14 @@ iphlpapi.dll!GetAdaptersAddresses POSSIBLE LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=473 c +name=https://github.com/DynamoRIO/drmemory/issues/473 c RPCRT4.dll!* RPCRT4.dll!* ... IPHLPAPI.DLL!GetAdaptersAddresses LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=475 +name=https://github.com/DynamoRIO/drmemory/issues/475 ... ADVAPI32.dll!CryptAcquireContextA ... @@ -499,105 +499,105 @@ # Lots of leaks from our interactions with the system certificate store. May be # worth reviewing our use of their API. LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=476 a +name=https://github.com/DynamoRIO/drmemory/issues/476 a KERNEL*.dll!LocalAlloc ... CRYPT32.dll!CertGetCRLContextProperty LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=476 b +name=https://github.com/DynamoRIO/drmemory/issues/476 b KERNEL*.dll!LocalAlloc ... CRYPT32.dll!CertAddCRLContextToStore LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=476 c +name=https://github.com/DynamoRIO/drmemory/issues/476 c KERNEL*.dll!LocalAlloc ... CRYPT32.dll!CertOpenStore LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=476 d +name=https://github.com/DynamoRIO/drmemory/issues/476 d ... CRYPT32.dll!CertOpenSystemStore? LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=476 e +name=https://github.com/DynamoRIO/drmemory/issues/476 e ... CRYPT32.dll!CertGetCertificateChain LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=476 f +name=https://github.com/DynamoRIO/drmemory/issues/476 f ... CRYPT32.dll!CertCompareIntegerBlob LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=476 g +name=https://github.com/DynamoRIO/drmemory/issues/476 g ... CRYPT32.dll!CryptUnprotectData LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=476 h +name=https://github.com/DynamoRIO/drmemory/issues/476 h KERNEL*.dll!LocalAlloc ... CRYPT32.dll!CertEnumCertificatesInStore LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=476 i +name=https://github.com/DynamoRIO/drmemory/issues/476 i ... CRYPT32.dll!CryptProtectData LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=476 j +name=https://github.com/DynamoRIO/drmemory/issues/476 j ... CRYPT32.dll!CryptExportPublicKeyInfoEx UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=502 a +name=https://github.com/DynamoRIO/drmemory/issues/502 a system call NtSecureConnectPort parameter #3 GDI32.dll!* GDI32.dll!* UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=502 b +name=https://github.com/DynamoRIO/drmemory/issues/502 b system call NtGdiEnumFonts parameter #6 GDI32.dll!* GDI32.dll!* UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=511 a +name=https://github.com/DynamoRIO/drmemory/issues/511 a RPCRT4.dll!... ole32.dll!* UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=511 b +name=https://github.com/DynamoRIO/drmemory/issues/511 b ole32.dll!* ole32.dll!* ole32.dll!StringFromGUID2 UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=512 a +name=https://github.com/DynamoRIO/drmemory/issues/512 a ... *!browser_sync::Cryptographer::PackBootstrapToken *!browser_sync::Cryptographer::GetBootstrapToken UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=512 b +name=https://github.com/DynamoRIO/drmemory/issues/512 b ... *!Encrypt* # TODO(bruening): remove these once we have v8 bitfields handled UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=513 a +name=https://github.com/DynamoRIO/drmemory/issues/513 a *!v8* UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=513 b +name=https://github.com/DynamoRIO/drmemory/issues/513 b *!* *!v8* UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=513 c +name=https://github.com/DynamoRIO/drmemory/issues/513 c <not in a module> ... *!v8* @@ -606,17 +606,17 @@ # has no symbols. These are all on the bots using component build, so we use # v8.dll. TODO(bruening): remove these once we've fixed the symbol issue. UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=513 d +name=https://github.com/DynamoRIO/drmemory/issues/513 d v8.dll!* UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=513 e +name=https://github.com/DynamoRIO/drmemory/issues/513 e <not in a module> ... v8.dll!* UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=546 +name=https://github.com/DynamoRIO/drmemory/issues/546 ... mscms.dll!* ... @@ -631,13 +631,13 @@ *!views::TooltipManagerWin::TooltipManagerWin UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=567 a +name=https://github.com/DynamoRIO/drmemory/issues/567 a dbghelp.dll!* ... dbghelp.dll!StackWalk64 LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=567 b +name=https://github.com/DynamoRIO/drmemory/issues/567 b *!* dbghelp.dll!* ... @@ -647,7 +647,7 @@ # TppWorkerThread w/ syms. We used to use mod+offs here, but that was too # brittle, so we switched to RPCRT4.dll!*. LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=569 +name=https://github.com/DynamoRIO/drmemory/issues/569 RPCRT4.dll!... ntdll.dll!* ntdll.dll!* @@ -772,7 +772,7 @@ # False pos uninit in shell32 when resolving links. UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=745 +name=https://github.com/DynamoRIO/drmemory/issues/745 SHELL*.dll!* ... SHELL*.dll!* @@ -781,31 +781,31 @@ # Probable false pos uninit in ffmpeg. Probably due to running off the end of a # buffer with SSE/MMX instructions whose results are then masked out later. UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=747 a +name=https://github.com/DynamoRIO/drmemory/issues/747 a *!ff_pred4x4_vertical_vp8_mmxext UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=747 b +name=https://github.com/DynamoRIO/drmemory/issues/747 b *!ff_pred4x4_down_left_mmxext UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=747 c +name=https://github.com/DynamoRIO/drmemory/issues/747 c *!ff_vorbis_floor1_render_list UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=747 d +name=https://github.com/DynamoRIO/drmemory/issues/747 d *!ff_put_vp8_epel8_h6_ssse3 UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=747 e +name=https://github.com/DynamoRIO/drmemory/issues/747 e *!ff_put_vp8_epel8_h4_ssse3 UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=747 f +name=https://github.com/DynamoRIO/drmemory/issues/747 f *!ff_fft_permute_sse UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=747 g +name=https://github.com/DynamoRIO/drmemory/issues/747 g *!ff_simple_idct_add_mmx # ffmpeg seems to leak a pthread condition variable. @@ -820,7 +820,7 @@ # Improperly handled ioctl in bcrypt. UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=748 +name=https://github.com/DynamoRIO/drmemory/issues/748 system call NtDeviceIoControlFile InputBuffer ... bcrypt.dll!BCryptUnregisterConfigChangeNotify @@ -829,7 +829,7 @@ # Not sure what this is. POSSIBLE LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=749 +name=https://github.com/DynamoRIO/drmemory/issues/749 ... fwpuclnt.dll!* ... @@ -849,37 +849,37 @@ # More uninit false pos in rpcrt4.dll not caught by default suppressions. UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=529 +name=https://github.com/DynamoRIO/drmemory/issues/529 RPCRT4.dll!* ... *!base::LaunchProcess # System leak from CreateEnvironmentBlock. LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=757 +name=https://github.com/DynamoRIO/drmemory/issues/757 ... USERENV.dll!CreateEnvironmentBlock # Looks like another instance of 753 LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=753 +name=https://github.com/DynamoRIO/drmemory/issues/753 ... ntdll.dll!RtlLoadString # More bit manip fps UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=493 +name=https://github.com/DynamoRIO/drmemory/issues/493 USP10.dll!ScriptPositionSingleGlyph # Various TLS leaks that we don't understand yet. We should be finding a root # for these. LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=778 a +name=https://github.com/DynamoRIO/drmemory/issues/778 a KERNELBASE.dll!TlsSetValue # Originally filed as: http://crbug.com/109281 LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=778 b +name=https://github.com/DynamoRIO/drmemory/issues/778 b *!operator new *!operator new[] *!*::ConstructTlsVector @@ -888,14 +888,14 @@ # This is an NSS PRThread object installed in TLS. Why isn't this detected as a # root? See also http://crbug.com/32624 LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=778 c +name=https://github.com/DynamoRIO/drmemory/issues/778 c *!PR_Calloc *!_PR_AttachThread *!_PRI_AttachThread # Bit-level fps in rich edit layer. UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=791 +name=https://github.com/DynamoRIO/drmemory/issues/791 RICHED20.dll!* RICHED20.dll!* @@ -910,13 +910,13 @@ # Async NtReadFile false positives. This was fixed in drmemory r772, remove # this supp when we pull that rev. UNADDRESSABLE ACCESS -name=http://code.google.com/p/drmemory/issues/detail?id=798 +name=https://github.com/DynamoRIO/drmemory/issues/798 system call NtReadFile parameter #5 KERNEL32.dll!ReadFile # Probable syscall false positive. UNADDRESSABLE ACCESS -name=http://code.google.com/p/drmemory/issues/detail?id=809 +name=https://github.com/DynamoRIO/drmemory/issues/809 system call NtGdiPolyPolyDraw parameter #1 *!gfx::Path::CreateNativeRegion @@ -925,39 +925,39 @@ # write precise suppressions. Until we have bit-level tracking (DRMi#113) we # should keep this. UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=113 rpcrt4.dll wildcard +name=https://github.com/DynamoRIO/drmemory/issues/113 rpcrt4.dll wildcard RPCRT4.dll!* UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=841 a +name=https://github.com/DynamoRIO/drmemory/issues/841 a ... CRYPTNET.dll!I_CryptNetGetConnectivity UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=841 b +name=https://github.com/DynamoRIO/drmemory/issues/841 b ... webio.dll!* UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=841 c +name=https://github.com/DynamoRIO/drmemory/issues/841 c ... winhttp.dll!* LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=841 d +name=https://github.com/DynamoRIO/drmemory/issues/841 d ... CRYPTNET.dll!I_CryptNetGetConnectivity # Often missing a ntdll.dll!KiUserCallbackDispatcher frame. UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=810 +name=https://github.com/DynamoRIO/drmemory/issues/810 instruction=test %edx %edx USER32.dll!GetClassLongW ... *!ui::CenterAndSizeWindow UNINITIALIZED READ -name=http://code.google.com/p/drmemory/issues/detail?id=815 +name=https://github.com/DynamoRIO/drmemory/issues/815 KERNEL*.dll!... dxgi.dll!* USER32.dll!GetMonitorInfoA @@ -974,7 +974,7 @@ # Possible true system use after free. UNADDRESSABLE ACCESS -name=http://code.google.com/p/drmemory/issues/detail?id=623 +name=https://github.com/DynamoRIO/drmemory/issues/623 KERNELBASE.dll!TlsGetValue OLEAUT32.dll!SysFreeString OLEAUT32.dll!SysAllocStringByteLen @@ -985,7 +985,7 @@ # basic_streambuf seems to leak something in creating a std::_Mutex LEAK -name=http://code.google.com/p/drmemory/issues/detail?id=857 +name=https://github.com/DynamoRIO/drmemory/issues/857 ntdll.dll!... ntdll.dll!RtlInitializeCriticalSection *!_Mtxinit @@ -1631,7 +1631,7 @@ # There are so many osmesa errors we have to suppress (mostly the unpack_RGB* # variety) that it's a performance hit. We avoid that by requesting # whole-module suppression -# (see https://code.google.com/p/drmemory/issues/detail?id=1529). +# (see https://github.com/DynamoRIO/drmemory/issues/1529). UNINITIALIZED READ name=bug_347967_all_osmesa osmesa.dll!*
diff --git a/tools/valgrind/gtest_exclude/browser_tests.gtest-drmemory_win32.txt b/tools/valgrind/gtest_exclude/browser_tests.gtest-drmemory_win32.txt index 2a23eee..425b3590 100644 --- a/tools/valgrind/gtest_exclude/browser_tests.gtest-drmemory_win32.txt +++ b/tools/valgrind/gtest_exclude/browser_tests.gtest-drmemory_win32.txt
@@ -1,6 +1,6 @@ # TODO(zhaoqin): File bugs for those failing browser tests. -# Dr.Memory i#1052: http://code.google.com/p/drmemory/issues/detail?id=1052 +# Dr.Memory i#1052: https://github.com/DynamoRIO/drmemory/issues/1052 # # The list is too long for gtest_filter, so we exclude the whole # test case if any of its tests failed.
diff --git a/tools/valgrind/gtest_exclude/chromeos_unittests.gtest.txt b/tools/valgrind/gtest_exclude/chromeos_unittests.gtest.txt new file mode 100644 index 0000000..ee21d7e --- /dev/null +++ b/tools/valgrind/gtest_exclude/chromeos_unittests.gtest.txt
@@ -0,0 +1,3 @@ +# crbug.com/437847 +AutoConnectHandlerTest.ReconnectOnCertPatternResolved +NetworkConnectionHandlerTest.ConnectWithCertificateSuccess
diff --git a/tools/valgrind/gtest_exclude/content_browsertests.gtest-drmemory_win32.txt b/tools/valgrind/gtest_exclude/content_browsertests.gtest-drmemory_win32.txt index cd8ecc45..569be95 100644 --- a/tools/valgrind/gtest_exclude/content_browsertests.gtest-drmemory_win32.txt +++ b/tools/valgrind/gtest_exclude/content_browsertests.gtest-drmemory_win32.txt
@@ -1,7 +1,7 @@ # crbug.com/389132 WebRtcAecDumpBrowserTest.*WithAecDump* -# http://code.google.com/p/drmemory/issues/detail?id=1528 +# https://github.com/DynamoRIO/drmemory/issues/1528 # Un-analyzed test failures: DeviceInertialSensorBrowserTest.MotionNullTestWithAlert DeviceInertialSensorBrowserTest.OrientationNullTestWithAlert
diff --git a/tools/valgrind/gtest_exclude/media_unittests.gtest-drmemory_win32.txt b/tools/valgrind/gtest_exclude/media_unittests.gtest-drmemory_win32.txt index 3152445..8ee264d 100644 --- a/tools/valgrind/gtest_exclude/media_unittests.gtest-drmemory_win32.txt +++ b/tools/valgrind/gtest_exclude/media_unittests.gtest-drmemory_win32.txt
@@ -1,4 +1,4 @@ # Hangs under Dr. Memory -# http://code.google.com/p/drmemory/issues/detail?id=978 +# https://github.com/DynamoRIO/drmemory/issues/978 WinAudioTest.SyncSocketBasic AudioBusTest.CopyTo
diff --git a/tools/valgrind/gtest_exclude/net_unittests.gtest-drmemory_win-xp.txt b/tools/valgrind/gtest_exclude/net_unittests.gtest-drmemory_win-xp.txt index 46717dc..9d77b20 100644 --- a/tools/valgrind/gtest_exclude/net_unittests.gtest-drmemory_win-xp.txt +++ b/tools/valgrind/gtest_exclude/net_unittests.gtest-drmemory_win-xp.txt
@@ -1,3 +1,3 @@ -# http://code.google.com/p/drmemory/issues/detail?id=842 +# https://github.com/DynamoRIO/drmemory/issues/842 # Failing and then crashing. HttpNetworkTransationSpdy21Test.HttpsProxySpdy*
diff --git a/tools/valgrind/gtest_exclude/net_unittests.gtest-drmemory_win32.txt b/tools/valgrind/gtest_exclude/net_unittests.gtest-drmemory_win32.txt index 465d258..2f7a2117 100644 --- a/tools/valgrind/gtest_exclude/net_unittests.gtest-drmemory_win32.txt +++ b/tools/valgrind/gtest_exclude/net_unittests.gtest-drmemory_win32.txt
@@ -5,7 +5,7 @@ URLRequestTestHTTP.GetTest_ManyCookies # Dr. Memory hits an assertion: -# http://code.google.com/p/drmemory/issues/detail?id=422 +# https://github.com/DynamoRIO/drmemory/issues/422 HttpAuthTest.* HttpAuthHandlerFactoryTest.* X509CertificateTest.*
diff --git a/tools/valgrind/gtest_exclude/unit_tests.gtest-drmemory_win-xp.txt b/tools/valgrind/gtest_exclude/unit_tests.gtest-drmemory_win-xp.txt index 2ef9d50..18a4d45 100644 --- a/tools/valgrind/gtest_exclude/unit_tests.gtest-drmemory_win-xp.txt +++ b/tools/valgrind/gtest_exclude/unit_tests.gtest-drmemory_win-xp.txt
@@ -1,7 +1,7 @@ # Crashing (!) since forever, needs analysis. BookmarkNodeDataTest.* -# http://code.google.com/p/drmemory/issues/detail?id=842 +# https://github.com/DynamoRIO/drmemory/issues/842 # Fails assertion. App data corrupted by DrMemory? JsonSchemaTest.TestType JsonSchemaTest.TestNumber
diff --git a/tools/valgrind/gtest_exclude/unit_tests.gtest-drmemory_win32.txt b/tools/valgrind/gtest_exclude/unit_tests.gtest-drmemory_win32.txt index 7e28846..dc461a9 100644 --- a/tools/valgrind/gtest_exclude/unit_tests.gtest-drmemory_win32.txt +++ b/tools/valgrind/gtest_exclude/unit_tests.gtest-drmemory_win32.txt
@@ -1,16 +1,16 @@ ################################################## # known Dr. Memory bugs: -# http://code.google.com/p/drmemory/issues/detail?id=318 +# https://github.com/DynamoRIO/drmemory/issues/318 AudioRendererHostTest.* ################################################## # un-analyzed Dr. Memory bugs: -# http://code.google.com/p/drmemory/issues/detail?id=979 +# https://github.com/DynamoRIO/drmemory/issues/979 FirefoxProfileImporterTest.Firefox35Importer -# http://code.google.com/p/drmemory/issues/detail?id=980 +# https://github.com/DynamoRIO/drmemory/issues/980 MetricsLogManagerTest.* ################################################## @@ -60,7 +60,7 @@ SyncBackendHostTest.DownloadControlTypes SyncBackendHostTest.SilentlyFailToDownloadControlTypes -# DrM-i#1339: https://code.google.com/p/drmemory/issues/detail?id=1339 +# DrM-i#1339: https://github.com/DynamoRIO/drmemory/issues/1339 ExtensionServiceTest.InstallTheme # http://crbug.com/302156
diff --git a/tools/valgrind/memcheck/suppressions_mac.txt b/tools/valgrind/memcheck/suppressions_mac.txt index 4ae5e47..dc9850b 100644 --- a/tools/valgrind/memcheck/suppressions_mac.txt +++ b/tools/valgrind/memcheck/suppressions_mac.txt
@@ -242,3 +242,10 @@ fun:_ZN7content45PluginLoaderPosixTest_PluginLaunchFailed_TestC1Ev fun:_ZN7testing8internal15TestFactoryImplIN7content45PluginLoaderPosixTest_PluginLaunchFailed_TestEE10CreateTestEv } +{ + bug_437807 + Memcheck:Leak + ... + fun:_ZN4base3mac30PathForFrameworkBundleResourceEPK10__CFString + fun:_ZN3gin13IsolateHolder14LoadV8SnapshotEv +}
diff --git a/tools/valgrind/scan-build.py b/tools/valgrind/scan-build.py index f943bf6..b117d1e 100755 --- a/tools/valgrind/scan-build.py +++ b/tools/valgrind/scan-build.py
@@ -5,6 +5,7 @@ import argparse import errno +import json import os import re import sys @@ -191,6 +192,8 @@ commands = parser.add_mutually_exclusive_group(required=True) commands.add_argument("--update", action='store_true') commands.add_argument("--find", metavar='search term') + parser.add_argument("--json", action='store_true', + help="Output in JSON format") args = parser.parse_args() path = os.path.abspath(os.path.dirname(argv[0])) @@ -205,22 +208,38 @@ builder.ScanLogs(lambda x:False) if args.find: + result = [] tester = MultiLineChange(args.find.splitlines()) fyi.FetchInfo() - print "SCANNING FOR ", args.find + if not args.json: + print "SCANNING FOR ", args.find for builder in fyi.Builders(): - print "Scanning", builder.Name() + if not args.json: + print "Scanning", builder.Name() occurrences = builder.ScanLogs(tester) if occurrences: min_build = min(occurrences) path = builder.GetBuildPath(min_build) - print "Earliest occurrence in build %d" % min_build - print "Latest occurrence in build %d" % max(occurrences) - print "Latest build: %d" % builder.LatestBuild() - print path - print "%d total" % len(occurrences) - + if args.json: + data = {} + data['builder'] = builder.Name() + data['first_affected'] = min_build + data['last_affected'] = max(occurrences) + data['last_build'] = builder.LatestBuild() + data['frequency'] = ((int(builder.LatestBuild()) - int(min_build)) / + len(occurrences)) + data['total'] = len(occurrences) + data['first_url'] = path + result.append(data) + else: + print "Earliest occurrence in build %d" % min_build + print "Latest occurrence in build %d" % max(occurrences) + print "Latest build: %d" % builder.LatestBuild() + print path + print "%d total" % len(occurrences) + if args.json: + json.dump(result, sys.stdout, indent=2, sort_keys=True) if __name__ == "__main__": sys.exit(main(sys.argv))
diff --git a/tools/valgrind/valgrind_test.py b/tools/valgrind/valgrind_test.py index f568b5e..24fa32ac 100644 --- a/tools/valgrind/valgrind_test.py +++ b/tools/valgrind/valgrind_test.py
@@ -833,11 +833,11 @@ def ToolCommand(self): """Get the tool command to run.""" # WINHEAP is what Dr. Memory supports as there are issues w/ both - # jemalloc (http://code.google.com/p/drmemory/issues/detail?id=320) and - # tcmalloc (http://code.google.com/p/drmemory/issues/detail?id=314) + # jemalloc (https://github.com/DynamoRIO/drmemory/issues/320) and + # tcmalloc (https://github.com/DynamoRIO/drmemory/issues/314) add_env = { "CHROME_ALLOCATOR" : "WINHEAP", - "JSIMD_FORCEMMX" : "1", # http://code.google.com/p/drmemory/issues/detail?id=540 + "JSIMD_FORCEMMX" : "1", # https://github.com/DynamoRIO/drmemory/issues/540 } for k,v in add_env.iteritems(): logging.info("export %s=%s", k, v) @@ -855,7 +855,7 @@ # With file-based config we must update the file every time, and # it will affect simultaneous drmem uses by this user. While file-based # config has many advantages, here we may want this-instance-only - # (http://code.google.com/p/drmemory/issues/detail?id=334). + # (https://github.com/DynamoRIO/drmemory/issues/334). drconfig_cmd = [ proc[0].replace("drmemory.exe", "drconfig.exe") ] drconfig_cmd += ["-quiet"] # suppress errors about no 64-bit libs run_drconfig = True @@ -990,7 +990,7 @@ # Use one analyzer for all the log files to avoid printing duplicate reports # # TODO(timurrrr): unify this with Valgrind and other tools when we have - # http://code.google.com/p/drmemory/issues/detail?id=684 + # https://github.com/DynamoRIO/drmemory/issues/684 analyzer = drmemory_analyze.DrMemoryAnalyzer() ret = 0
diff --git a/ui/accelerated_widget_mac/BUILD.gn b/ui/accelerated_widget_mac/BUILD.gn new file mode 100644 index 0000000..9069b5a3 --- /dev/null +++ b/ui/accelerated_widget_mac/BUILD.gn
@@ -0,0 +1,37 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# GYP version: ui/accelerated_widget_mac/accelerated_widget_mac.gyp:accelerated_widget_mac +component("accelerated_widget_mac") { + sources = [ + "accelerated_widget_mac.h", + "accelerated_widget_mac.mm", + "accelerated_widget_mac_export.h", + "io_surface_context.h", + "io_surface_context.mm", + "io_surface_layer.h", + "io_surface_layer.mm", + "io_surface_texture.h", + "io_surface_texture.mm", + "software_layer.h", + "software_layer.mm", + "surface_handle_types.cc", + "surface_handle_types.h", + ] + + defines = [ "ACCELERATED_WIDGET_MAC_IMPLEMENTATION" ] + + deps = [ + "//base", + "//skia", + "//ui/base", + "//ui/events", + "//ui/gfx/geometry", + "//ui/gl", + ] + + libs = [ + "QuartzCore.framework", + ] +}
diff --git a/ui/accelerated_widget_mac/DEPS b/ui/accelerated_widget_mac/DEPS new file mode 100644 index 0000000..32be787d --- /dev/null +++ b/ui/accelerated_widget_mac/DEPS
@@ -0,0 +1,8 @@ +include_rules = [ + "+third_party/skia", + "+ui/base/cocoa", + "+ui/events", + "+ui/gfx/geometry", + "+ui/gfx/native_widget_types.h", + "+ui/gl", +]
diff --git a/ui/accelerated_widget_mac/OWNERS b/ui/accelerated_widget_mac/OWNERS new file mode 100644 index 0000000..4eb0cb4 --- /dev/null +++ b/ui/accelerated_widget_mac/OWNERS
@@ -0,0 +1 @@ +ccameron@chromium.org
diff --git a/ui/accelerated_widget_mac/README b/ui/accelerated_widget_mac/README new file mode 100644 index 0000000..de7b0eb --- /dev/null +++ b/ui/accelerated_widget_mac/README
@@ -0,0 +1,7 @@ +This directory contains the accelerated_widget_mac ui component. The main +exported class is AcceleratedWidgetMac, which owns a tree of Core Animation +CALayers that are placed into an NSView provided by the +AcceleratedWidgetMacNSView client class. + +AcceleratedWidgetMac receives frames from the compositor and ensures it has +appropriate layers for rendering that frame type into the NSView.
diff --git a/ui/accelerated_widget_mac/accelerated_widget_mac.gyp b/ui/accelerated_widget_mac/accelerated_widget_mac.gyp new file mode 100644 index 0000000..66fd48c --- /dev/null +++ b/ui/accelerated_widget_mac/accelerated_widget_mac.gyp
@@ -0,0 +1,47 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +{ + 'variables': { + 'chromium_code': 1, + }, + 'targets': [ + { + # GN version: //ui/accelerated_widget_mac + 'target_name': 'accelerated_widget_mac', + 'type': '<(component)', + 'sources': [ + 'accelerated_widget_mac.h', + 'accelerated_widget_mac.mm', + 'accelerated_widget_mac_export.h', + 'io_surface_context.h', + 'io_surface_context.mm', + 'io_surface_layer.h', + 'io_surface_layer.mm', + 'io_surface_texture.h', + 'io_surface_texture.mm', + 'software_layer.h', + 'software_layer.mm', + 'surface_handle_types.cc', + 'surface_handle_types.h', + ], + 'defines': [ + 'ACCELERATED_WIDGET_MAC_IMPLEMENTATION', + ], + 'dependencies': [ + '<(DEPTH)/base/base.gyp:base', + '<(DEPTH)/skia/skia.gyp:skia', + '<(DEPTH)/ui/base/ui_base.gyp:ui_base', + '<(DEPTH)/ui/events/events.gyp:events_base', + '<(DEPTH)/ui/gfx/gfx.gyp:gfx_geometry', + '<(DEPTH)/ui/gl/gl.gyp:gl', + ], + 'link_settings': { + 'libraries': [ + '$(SDKROOT)/System/Library/Frameworks/QuartzCore.framework', + ], + }, + }, + ], +}
diff --git a/content/browser/compositor/browser_compositor_ca_layer_tree_mac.h b/ui/accelerated_widget_mac/accelerated_widget_mac.h similarity index 83% rename from content/browser/compositor/browser_compositor_ca_layer_tree_mac.h rename to ui/accelerated_widget_mac/accelerated_widget_mac.h index 34b5c977..bf78433 100644 --- a/content/browser/compositor/browser_compositor_ca_layer_tree_mac.h +++ b/ui/accelerated_widget_mac/accelerated_widget_mac.h
@@ -2,30 +2,32 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CONTENT_BROWSER_COMPOSITOR_ACCELERATED_WIDGET_HELPER_MAC_H_ -#define CONTENT_BROWSER_COMPOSITOR_ACCELERATED_WIDGET_HELPER_MAC_H_ +#ifndef UI_ACCELERATED_WIDGET_MAC_ACCELERATED_WIDGET_MAC_H_ +#define UI_ACCELERATED_WIDGET_MAC_ACCELERATED_WIDGET_MAC_H_ #include <IOSurface/IOSurfaceAPI.h> #include <vector> -#include "skia/ext/platform_canvas.h" +#include "ui/accelerated_widget_mac/accelerated_widget_mac_export.h" #include "ui/events/latency_info.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/native_widget_types.h" #if defined(__OBJC__) -#include <Cocoa/Cocoa.h> -#include "base/mac/scoped_nsobject.h" -#include "content/browser/compositor/io_surface_layer_mac.h" -#include "content/browser/compositor/software_layer_mac.h" +#import <Cocoa/Cocoa.h> +#import "base/mac/scoped_nsobject.h" +#import "ui/accelerated_widget_mac/io_surface_layer.h" +#import "ui/accelerated_widget_mac/software_layer.h" #include "ui/base/cocoa/remote_layer_api.h" #endif // __OBJC__ +class SkCanvas; + namespace cc { class SoftwareFrameData; } -namespace content { +namespace ui { class AcceleratedWidgetMac; @@ -47,9 +49,10 @@ // to a ui::Compositor, which will cause, through its output surface, calls to // GotAcceleratedFrame and GotSoftwareFrame. The CALayers may be installed // in an NSView by setting the AcceleratedWidgetMacNSView for the helper. -class AcceleratedWidgetMac : public IOSurfaceLayerClient { +class ACCELERATED_WIDGET_MAC_EXPORT AcceleratedWidgetMac + : public IOSurfaceLayerClient { public: - AcceleratedWidgetMac(); + explicit AcceleratedWidgetMac(bool needs_gl_finish_workaround); virtual ~AcceleratedWidgetMac(); gfx::AcceleratedWidget accelerated_widget() { return native_widget_; } @@ -78,10 +81,9 @@ float scale_factor, const base::Closure& drawn_callback); - void GotSoftwareFrame( - cc::SoftwareFrameData* frame_data, float scale_factor, SkCanvas* canvas); + void GotSoftwareFrame(float scale_factor, SkCanvas* canvas); -private: + private: // IOSurfaceLayerClient implementation: bool IOSurfaceLayerShouldAckImmediately() const override; void IOSurfaceLayerDidDrawFrame() override; @@ -138,11 +140,16 @@ // The size in DIP of the last swap received from |compositor_|. gfx::Size last_swap_size_dip_; + // Whether surfaces created by the widget should use the glFinish() workaround + // after compositing. + bool needs_gl_finish_workaround_; + DISALLOW_COPY_AND_ASSIGN(AcceleratedWidgetMac); }; #endif // __OBJC__ +ACCELERATED_WIDGET_MAC_EXPORT void AcceleratedWidgetMacGotAcceleratedFrame( gfx::AcceleratedWidget widget, uint64 surface_handle, const std::vector<ui::LatencyInfo>& latency_info, @@ -150,10 +157,10 @@ const base::Closure& drawn_callback, bool* disable_throttling, int* renderer_id); +ACCELERATED_WIDGET_MAC_EXPORT void AcceleratedWidgetMacGotSoftwareFrame( - gfx::AcceleratedWidget widget, - cc::SoftwareFrameData* frame_data, float scale_factor, SkCanvas* canvas); + gfx::AcceleratedWidget widget, float scale_factor, SkCanvas* canvas); -} // namespace content +} // namespace ui -#endif // CONTENT_BROWSER_COMPOSITOR_ACCELERATED_WIDGET_HELPER_MAC_H_ +#endif // UI_ACCELERATED_WIDGET_MAC_ACCELERATED_WIDGET_MAC_H_
diff --git a/content/browser/compositor/browser_compositor_ca_layer_tree_mac.mm b/ui/accelerated_widget_mac/accelerated_widget_mac.mm similarity index 92% rename from content/browser/compositor/browser_compositor_ca_layer_tree_mac.mm rename to ui/accelerated_widget_mac/accelerated_widget_mac.mm index 43aec83..8397dc6f 100644 --- a/content/browser/compositor/browser_compositor_ca_layer_tree_mac.mm +++ b/ui/accelerated_widget_mac/accelerated_widget_mac.mm
@@ -2,23 +2,21 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/browser/compositor/browser_compositor_ca_layer_tree_mac.h" +#include "ui/accelerated_widget_mac/accelerated_widget_mac.h" #include <map> -#include "cc/output/software_frame_data.h" #include "base/debug/trace_event.h" #include "base/lazy_instance.h" #include "base/message_loop/message_loop.h" -#include "content/browser/compositor/io_surface_layer_mac.h" -#include "content/browser/compositor/software_layer_mac.h" -#include "content/common/gpu/surface_handle_types_mac.h" -#include "content/public/browser/context_factory.h" +#include "third_party/skia/include/core/SkCanvas.h" +#include "ui/accelerated_widget_mac/io_surface_layer.h" +#include "ui/accelerated_widget_mac/surface_handle_types.h" #include "ui/base/cocoa/animation_utils.h" #include "ui/gfx/geometry/dip_util.h" #include "ui/gl/scoped_cgl.h" -namespace content { +namespace ui { namespace { typedef std::map<gfx::AcceleratedWidget,AcceleratedWidgetMac*> @@ -37,13 +35,14 @@ return found->second; } -} +} // namespace //////////////////////////////////////////////////////////////////////////////// // AcceleratedWidgetMac -AcceleratedWidgetMac::AcceleratedWidgetMac() - : view_(NULL) { +AcceleratedWidgetMac::AcceleratedWidgetMac(bool needs_gl_finish_workaround) + : view_(NULL), + needs_gl_finish_workaround_(needs_gl_finish_workaround) { // Disable the fade-in animation as the layers are added. ScopedCAActionDisabler disabler; @@ -215,7 +214,8 @@ if (needs_new_layer) { io_surface_layer_.reset( [[IOSurfaceLayer alloc] initWithClient:this - withScaleFactor:scale_factor]); + withScaleFactor:scale_factor + needsGLFinishWorkaround:needs_gl_finish_workaround_]); if (io_surface_layer_) [flipped_layer_ addSublayer:io_surface_layer_]; else @@ -266,11 +266,9 @@ DestroySoftwareLayer(); } -void AcceleratedWidgetMac::GotSoftwareFrame( - cc::SoftwareFrameData* frame_data, - float scale_factor, - SkCanvas* canvas) { - if (!frame_data || !canvas || !view_) +void AcceleratedWidgetMac::GotSoftwareFrame(float scale_factor, + SkCanvas* canvas) { + if (!canvas || !view_) return; // Disable the fade-in or fade-out effect if we create or remove layers. @@ -379,12 +377,11 @@ } void AcceleratedWidgetMacGotSoftwareFrame( - gfx::AcceleratedWidget widget, - cc::SoftwareFrameData* frame_data, float scale_factor, SkCanvas* canvas) { + gfx::AcceleratedWidget widget, float scale_factor, SkCanvas* canvas) { AcceleratedWidgetMac* accelerated_widget_mac = GetHelperFromAcceleratedWidget(widget); if (accelerated_widget_mac) - accelerated_widget_mac->GotSoftwareFrame(frame_data, scale_factor, canvas); + accelerated_widget_mac->GotSoftwareFrame(scale_factor, canvas); } -} // namespace content +} // namespace ui
diff --git a/ui/accelerated_widget_mac/accelerated_widget_mac_export.h b/ui/accelerated_widget_mac/accelerated_widget_mac_export.h new file mode 100644 index 0000000..e16df3d --- /dev/null +++ b/ui/accelerated_widget_mac/accelerated_widget_mac_export.h
@@ -0,0 +1,24 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_ACCELERATED_WIDGET_MAC_ACCELERATED_WIDGET_MAC_EXPORT_H_ +#define UI_ACCELERATED_WIDGET_MAC_ACCELERATED_WIDGET_MAC_EXPORT_H_ + +#if defined(WIN32) +#error Not for use on Windows. +#endif + +#if defined(COMPONENT_BUILD) + +#if defined(ACCELERATED_WIDGET_MAC_IMPLEMENTATION) +#define ACCELERATED_WIDGET_MAC_EXPORT __attribute__((visibility("default"))) +#else +#define ACCELERATED_WIDGET_MAC_EXPORT +#endif + +#else // defined(COMPONENT_BUILD) +#define ACCELERATED_WIDGET_MAC_EXPORT +#endif + +#endif // UI_ACCELERATED_WIDGET_MAC_ACCELERATED_WIDGET_MAC_EXPORT_H_
diff --git a/content/browser/compositor/io_surface_context_mac.h b/ui/accelerated_widget_mac/io_surface_context.h similarity index 86% rename from content/browser/compositor/io_surface_context_mac.h rename to ui/accelerated_widget_mac/io_surface_context.h index 4e5802a..75347b48 100644 --- a/content/browser/compositor/io_surface_context_mac.h +++ b/ui/accelerated_widget_mac/io_surface_context.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CONTENT_BROWSER_COMPOSITOR_IO_SURFACE_CONTEXT_MAC_H_ -#define CONTENT_BROWSER_COMPOSITOR_IO_SURFACE_CONTEXT_MAC_H_ +#ifndef UI_ACCELERATED_WIDGET_MAC_IO_SURFACE_CONTEXT_H_ +#define UI_ACCELERATED_WIDGET_MAC_IO_SURFACE_CONTEXT_H_ #include <OpenGL/OpenGL.h> #include <map> @@ -16,7 +16,7 @@ #include "ui/gl/gpu_switching_observer.h" #include "ui/gl/scoped_cgl.h" -namespace content { +namespace ui { class IOSurfaceContext : public base::RefCounted<IOSurfaceContext>, @@ -44,7 +44,7 @@ CGLContextObj cgl_context() const { return cgl_context_; } - // content::GpuDataManagerObserver implementation. + // ui::GpuSwitchingObserver implementation. void OnGpuSwitched() override; private: @@ -67,6 +67,6 @@ static TypeMap* type_map(); }; -} // namespace content +} // namespace ui -#endif // CONTENT_BROWSER_COMPOSITOR_IO_SURFACE_CONTEXT_MAC_H_ +#endif // UI_ACCELERATED_WIDGET_MAC_IO_SURFACE_CONTEXT_H_
diff --git a/content/browser/compositor/io_surface_context_mac.mm b/ui/accelerated_widget_mac/io_surface_context.mm similarity index 95% rename from content/browser/compositor/io_surface_context_mac.mm rename to ui/accelerated_widget_mac/io_surface_context.mm index 82c81b1a..59e79fd8 100644 --- a/content/browser/compositor/io_surface_context_mac.mm +++ b/ui/accelerated_widget_mac/io_surface_context.mm
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/browser/compositor/io_surface_context_mac.h" +#include "ui/accelerated_widget_mac/io_surface_context.h" #include <OpenGL/gl.h> #include <OpenGL/OpenGL.h> @@ -11,11 +11,10 @@ #include "base/command_line.h" #include "base/debug/trace_event.h" #include "base/logging.h" -#include "ui/base/ui_base_switches.h" #include "ui/gl/gl_switches.h" #include "ui/gl/gpu_switching_manager.h" -namespace content { +namespace ui { // static scoped_refptr<IOSurfaceContext> @@ -118,4 +117,4 @@ base::LazyInstance<IOSurfaceContext::TypeMap> IOSurfaceContext::type_map_; -} // namespace content +} // namespace ui
diff --git a/content/browser/compositor/io_surface_layer_mac.h b/ui/accelerated_widget_mac/io_surface_layer.h similarity index 87% rename from content/browser/compositor/io_surface_layer_mac.h rename to ui/accelerated_widget_mac/io_surface_layer.h index 5a218e8..ba48ff9 100644 --- a/content/browser/compositor/io_surface_layer_mac.h +++ b/ui/accelerated_widget_mac/io_surface_layer.h
@@ -2,19 +2,20 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CONTENT_BROWSER_COMPOSITOR_IO_SURFACE_LAYER_MAC_H_ -#define CONTENT_BROWSER_COMPOSITOR_IO_SURFACE_LAYER_MAC_H_ +#ifndef UI_ACCELERATED_WIDGET_MAC_IO_SURFACE_LAYER_H_ +#define UI_ACCELERATED_WIDGET_MAC_IO_SURFACE_LAYER_H_ #import <Cocoa/Cocoa.h> #include "base/mac/scoped_cftyperef.h" #include "base/memory/ref_counted.h" #include "base/timer/timer.h" -#include "ui/gfx/size.h" +#include "ui/gfx/geometry/size.h" @class IOSurfaceLayer; -namespace content { +namespace ui { + class IOSurfaceTexture; class IOSurfaceContext; @@ -44,7 +45,7 @@ class IOSurfaceLayerHelper { public: IOSurfaceLayerHelper(IOSurfaceLayerClient* client, - IOSurfaceLayer* layer); + IOSurfaceLayer* layer); ~IOSurfaceLayerHelper(); // Called when the IOSurfaceLayer gets a new frame. @@ -84,7 +85,7 @@ void TimerFired(); // The client that the owning layer was created with. - content::IOSurfaceLayerClient* const client_; + IOSurfaceLayerClient* const client_; // The layer that owns this helper. IOSurfaceLayer* const layer_; @@ -111,19 +112,20 @@ base::DelayTimer<IOSurfaceLayerHelper> timer_; }; -} // namespace content +} // namespace ui // The CoreAnimation layer for drawing accelerated content. @interface IOSurfaceLayer : CAOpenGLLayer { @private - scoped_refptr<content::IOSurfaceTexture> iosurface_; - scoped_refptr<content::IOSurfaceContext> context_; + scoped_refptr<ui::IOSurfaceTexture> iosurface_; + scoped_refptr<ui::IOSurfaceContext> context_; - scoped_ptr<content::IOSurfaceLayerHelper> helper_; + scoped_ptr<ui::IOSurfaceLayerHelper> helper_; } -- (id)initWithClient:(content::IOSurfaceLayerClient*)client - withScaleFactor:(float)scale_factor; +- (id)initWithClient:(ui::IOSurfaceLayerClient*)client + withScaleFactor:(float)scale_factor + needsGLFinishWorkaround:(bool)needs_gl_finish_workaround; - (bool)gotFrameWithIOSurface:(IOSurfaceID)io_surface_id withPixelSize:(gfx::Size)pixel_size @@ -158,4 +160,4 @@ - (void)endPumpingFrames; @end -#endif // CONTENT_BROWSER_COMPOSITOR_IO_SURFACE_LAYER_MAC_H_ +#endif // UI_ACCELERATED_WIDGET_MAC_IO_SURFACE_LAYER_H_
diff --git a/content/browser/compositor/io_surface_layer_mac.mm b/ui/accelerated_widget_mac/io_surface_layer.mm similarity index 92% rename from content/browser/compositor/io_surface_layer_mac.mm rename to ui/accelerated_widget_mac/io_surface_layer.mm index 2ca94792..41e0ab9a0 100644 --- a/content/browser/compositor/io_surface_layer_mac.mm +++ b/ui/accelerated_widget_mac/io_surface_layer.mm
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/browser/compositor/io_surface_layer_mac.h" +#include "ui/accelerated_widget_mac/io_surface_layer.h" #include <CoreFoundation/CoreFoundation.h> #include <OpenGL/CGLIOSurface.h> @@ -13,16 +13,16 @@ #include "base/debug/trace_event.h" #include "base/mac/mac_util.h" #include "base/mac/sdk_forward_declarations.h" -#include "content/browser/compositor/io_surface_context_mac.h" -#include "content/browser/compositor/io_surface_texture_mac.h" +#include "ui/accelerated_widget_mac/io_surface_context.h" +#include "ui/accelerated_widget_mac/io_surface_texture.h" #include "ui/base/cocoa/animation_utils.h" -#include "ui/gfx/size_conversions.h" +#include "ui/gfx/geometry/size_conversions.h" #include "ui/gl/gpu_switching_manager.h" //////////////////////////////////////////////////////////////////////////////// // IOSurfaceLayerHelper -namespace content { +namespace ui { IOSurfaceLayerHelper::IOSurfaceLayerHelper( IOSurfaceLayerClient* client, @@ -160,21 +160,22 @@ DisplayIfNeededAndAck(); } -} // namespace content +} // namespace ui //////////////////////////////////////////////////////////////////////////////// // IOSurfaceLayer @implementation IOSurfaceLayer -- (id)initWithClient:(content::IOSurfaceLayerClient*)client - withScaleFactor:(float)scale_factor { +- (id)initWithClient:(ui::IOSurfaceLayerClient*)client + withScaleFactor:(float)scale_factor + needsGLFinishWorkaround:(bool)needs_gl_finish_workaround { if (self = [super init]) { - helper_.reset(new content::IOSurfaceLayerHelper(client, self)); + helper_.reset(new ui::IOSurfaceLayerHelper(client, self)); - iosurface_ = content::IOSurfaceTexture::Create(); - context_ = content::IOSurfaceContext::Get( - content::IOSurfaceContext::kCALayerContext); + iosurface_ = ui::IOSurfaceTexture::Create(needs_gl_finish_workaround); + context_ = ui::IOSurfaceContext::Get( + ui::IOSurfaceContext::kCALayerContext); if (!iosurface_.get() || !context_.get()) { LOG(ERROR) << "Failed create CompositingIOSurface or context"; [self resetClient];
diff --git a/content/browser/compositor/io_surface_texture_mac.h b/ui/accelerated_widget_mac/io_surface_texture.h similarity index 88% rename from content/browser/compositor/io_surface_texture_mac.h rename to ui/accelerated_widget_mac/io_surface_texture.h index 595c912..473e69cb 100644 --- a/content/browser/compositor/io_surface_texture_mac.h +++ b/ui/accelerated_widget_mac/io_surface_texture.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CONTENT_BROWSER_COMPOSITOR_IO_SURFACE_TEXTURE_MAC_H_ -#define CONTENT_BROWSER_COMPOSITOR_IO_SURFACE_TEXTURE_MAC_H_ +#ifndef UI_ACCELERATED_WIDGET_MAC_IO_SURFACE_TEXTURE_H_ +#define UI_ACCELERATED_WIDGET_MAC_IO_SURFACE_TEXTURE_H_ #include <deque> #include <list> @@ -19,11 +19,8 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/time/time.h" -#include "media/base/video_frame.h" +#include "ui/gfx/geometry/size.h" #include "ui/gfx/native_widget_types.h" -#include "ui/gfx/rect.h" -#include "ui/gfx/rect_conversions.h" -#include "ui/gfx/size.h" class SkBitmap; @@ -31,7 +28,7 @@ class Rect; } -namespace content { +namespace ui { class IOSurfaceContext; class RenderWidgetHostViewFrameSubscriber; @@ -44,7 +41,8 @@ : public base::RefCounted<IOSurfaceTexture> { public: // Returns NULL if IOSurfaceTexture or GL API calls fail. - static scoped_refptr<IOSurfaceTexture> Create(); + static scoped_refptr<IOSurfaceTexture> Create( + bool needs_gl_finish_workaround); // Set IOSurfaceTexture that will be drawn on the next NSView drawRect. bool SetIOSurface( @@ -65,7 +63,8 @@ friend class base::RefCounted<IOSurfaceTexture>; IOSurfaceTexture( - const scoped_refptr<IOSurfaceContext>& context); + const scoped_refptr<IOSurfaceContext>& context, + bool needs_gl_finish_workaround); ~IOSurfaceTexture(); // Unref the IOSurfaceTexture and delete the associated GL texture. If the GPU @@ -109,6 +108,7 @@ void EvictionMarkEvicted(); EvictionQueue::iterator eviction_queue_iterator_; bool eviction_has_been_drawn_since_updated_; + const bool needs_gl_finish_workaround_; static void EvictionScheduleDoEvict(); static void EvictionDoEvict(); @@ -116,6 +116,6 @@ static bool eviction_scheduled_; }; -} // namespace content +} // namespace ui -#endif // CONTENT_BROWSER_COMPOSITOR_IO_SURFACE_TEXTURE_MAC_H_ +#endif // UI_ACCELERATED_WIDGET_MAC_IO_SURFACE_TEXTURE_H_
diff --git a/content/browser/compositor/io_surface_texture_mac.mm b/ui/accelerated_widget_mac/io_surface_texture.mm similarity index 88% rename from content/browser/compositor/io_surface_texture_mac.mm rename to ui/accelerated_widget_mac/io_surface_texture.mm index dea6b287..11de3162 100644 --- a/content/browser/compositor/io_surface_texture_mac.mm +++ b/ui/accelerated_widget_mac/io_surface_texture.mm
@@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/browser/compositor/io_surface_texture_mac.h" +#include "ui/accelerated_widget_mac/io_surface_texture.h" #include <OpenGL/CGLIOSurface.h> #include <OpenGL/CGLRenderers.h> -#include <OpenGL/OpenGL.h> #include <OpenGL/gl.h> +#include <OpenGL/OpenGL.h> #include "base/bind.h" #include "base/bind_helpers.h" @@ -18,23 +18,17 @@ #include "base/mac/mac_util.h" #include "base/message_loop/message_loop.h" #include "base/threading/platform_thread.h" -#include "content/browser/compositor/io_surface_context_mac.h" -#include "content/browser/gpu/gpu_data_manager_impl.h" -#include "content/browser/renderer_host/render_widget_host_impl.h" -#include "content/browser/renderer_host/render_widget_host_view_mac.h" -#include "content/common/content_constants_internal.h" -#include "gpu/config/gpu_driver_bug_workaround_type.h" -#include "media/base/video_util.h" #include "third_party/skia/include/core/SkBitmap.h" -#include "ui/gfx/rect.h" -#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h" -#include "ui/gfx/size_conversions.h" +#include "ui/accelerated_widget_mac/io_surface_context.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/size_conversions.h" #include "ui/gl/gl_context.h" -namespace content { +namespace ui { // static -scoped_refptr<IOSurfaceTexture> IOSurfaceTexture::Create() { +scoped_refptr<IOSurfaceTexture> IOSurfaceTexture::Create( + bool needs_gl_finish_workaround) { scoped_refptr<IOSurfaceContext> offscreen_context = IOSurfaceContext::Get( IOSurfaceContext::kOffscreenContext); @@ -43,16 +37,18 @@ return NULL; } - return new IOSurfaceTexture(offscreen_context); + return new IOSurfaceTexture(offscreen_context, needs_gl_finish_workaround); } IOSurfaceTexture::IOSurfaceTexture( - const scoped_refptr<IOSurfaceContext>& offscreen_context) + const scoped_refptr<IOSurfaceContext>& offscreen_context, + bool needs_gl_finish_workaround) : offscreen_context_(offscreen_context), texture_(0), gl_error_(GL_NO_ERROR), eviction_queue_iterator_(eviction_queue_.Get().end()), - eviction_has_been_drawn_since_updated_(false) { + eviction_has_been_drawn_since_updated_(false), + needs_gl_finish_workaround_(needs_gl_finish_workaround) { CHECK(offscreen_context_.get()); } @@ -110,10 +106,7 @@ glBegin(GL_TRIANGLES); glEnd(); - bool workaround_needed = - GpuDataManagerImpl::GetInstance()->IsDriverBugWorkaroundActive( - gpu::FORCE_GL_FINISH_AFTER_COMPOSITING); - if (workaround_needed) { + if (needs_gl_finish_workaround_) { TRACE_EVENT0("gpu", "glFinish"); glFinish(); } @@ -294,4 +287,4 @@ // static bool IOSurfaceTexture::eviction_scheduled_ = false; -} // namespace content +} // namespace ui
diff --git a/content/browser/compositor/software_layer_mac.h b/ui/accelerated_widget_mac/software_layer.h similarity index 71% rename from content/browser/compositor/software_layer_mac.h rename to ui/accelerated_widget_mac/software_layer.h index 687070e5..314314e 100644 --- a/content/browser/compositor/software_layer_mac.h +++ b/ui/accelerated_widget_mac/software_layer.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CONTENT_BROWSER_RENDERER_HOST_SOFTWARE_LAYER_MAC_H_ -#define CONTENT_BROWSER_RENDERER_HOST_SOFTWARE_LAYER_MAC_H_ +#ifndef UI_ACCELERATED_WIDGET_MAC_SOFTWARE_LAYER_H_ +#define UI_ACCELERATED_WIDGET_MAC_SOFTWARE_LAYER_H_ #import <Cocoa/Cocoa.h> @@ -19,4 +19,4 @@ @end -#endif // CONTENT_BROWSER_RENDERER_HOST_SOFTWARE_LAYER_MAC_H_ +#endif // UI_ACCELERATED_WIDGET_MAC_SOFTWARE_LAYER_H_
diff --git a/content/browser/compositor/software_layer_mac.mm b/ui/accelerated_widget_mac/software_layer.mm similarity index 96% rename from content/browser/compositor/software_layer_mac.mm rename to ui/accelerated_widget_mac/software_layer.mm index eb2f03c2..1139b14 100644 --- a/content/browser/compositor/software_layer_mac.mm +++ b/ui/accelerated_widget_mac/software_layer.mm
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/browser/compositor/software_layer_mac.h" +#include "ui/accelerated_widget_mac/software_layer.h" #include "base/debug/trace_event.h" #include "base/mac/mac_util.h"
diff --git a/content/common/gpu/surface_handle_types_mac.cc b/ui/accelerated_widget_mac/surface_handle_types.cc similarity index 93% rename from content/common/gpu/surface_handle_types_mac.cc rename to ui/accelerated_widget_mac/surface_handle_types.cc index ef72542..22d2f6dc 100644 --- a/content/common/gpu/surface_handle_types_mac.cc +++ b/ui/accelerated_widget_mac/surface_handle_types.cc
@@ -2,11 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/common/gpu/surface_handle_types_mac.h" +#include "ui/accelerated_widget_mac/surface_handle_types.h" #include "base/logging.h" -namespace content { +namespace ui { namespace { // The type of the handle is stored in the upper 64 bits. @@ -50,4 +50,4 @@ return kTypeCAContext | (ca_context_id ^ kXORMaskCAContext); } -} // namespace content +} // namespace ui
diff --git a/content/common/gpu/surface_handle_types_mac.h b/ui/accelerated_widget_mac/surface_handle_types.h similarity index 72% rename from content/common/gpu/surface_handle_types_mac.h rename to ui/accelerated_widget_mac/surface_handle_types.h index 8432017..7b55ec9 100644 --- a/content/common/gpu/surface_handle_types_mac.h +++ b/ui/accelerated_widget_mac/surface_handle_types.h
@@ -2,16 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CONTENT_COMMON_GPU_SURFACE_HANDLE_TYPES_MAC_H_ -#define CONTENT_COMMON_GPU_SURFACE_HANDLE_TYPES_MAC_H_ +#ifndef UI_ACCELERATED_WIDGET_MAC_SURFACE_HANDLE_TYPES_H_ +#define UI_ACCELERATED_WIDGET_MAC_SURFACE_HANDLE_TYPES_H_ #include <IOSurface/IOSurface.h> #include <OpenGL/CGLIOSurface.h> #include "base/basictypes.h" +#include "ui/accelerated_widget_mac/accelerated_widget_mac_export.h" #include "ui/base/cocoa/remote_layer_api.h" -namespace content { +namespace ui { // The surface handle passed between the GPU and browser process may refer to // an IOSurface or a CAContext. These helper functions must be used to identify @@ -27,9 +28,12 @@ CAContextID CAContextIDFromSurfaceHandle(uint64 surface_handle); IOSurfaceID IOSurfaceIDFromSurfaceHandle(uint64 surface_handle); +ACCELERATED_WIDGET_MAC_EXPORT uint64 SurfaceHandleFromIOSurfaceID(IOSurfaceID io_surface_id); + +ACCELERATED_WIDGET_MAC_EXPORT uint64 SurfaceHandleFromCAContextID(CAContextID ca_context_id); -} // namespace content +} // namespace ui -#endif // CONTENT_COMMON_GPU_HANDLE_TYPES_MAC_H_ +#endif // UI_ACCELERATED_WIDGET_MAC_SURFACE_HANDLE_TYPES_H_
diff --git a/ui/accessibility/ax_enums.idl b/ui/accessibility/ax_enums.idl index f34a45c2..7bd8653 100644 --- a/ui/accessibility/ax_enums.idl +++ b/ui/accessibility/ax_enums.idl
@@ -96,7 +96,6 @@ disclosure_triangle, div, document, - editable_text, embedded_object, figcaption, figure, @@ -104,7 +103,6 @@ form, grid, group, - grow_area, heading, iframe, ignored, @@ -160,7 +158,6 @@ slider_thumb, spin_button_part, spin_button, - split_group, splitter, static_text, status, @@ -201,6 +198,7 @@ focusable, focused, haspopup, + horizontal, hovered, indeterminate, invisible,
diff --git a/ui/accessibility/platform/ax_platform_node_mac.mm b/ui/accessibility/platform/ax_platform_node_mac.mm index cd859fd..b296303 100644 --- a/ui/accessibility/platform/ax_platform_node_mac.mm +++ b/ui/accessibility/platform/ax_platform_node_mac.mm
@@ -51,14 +51,12 @@ {ui::AX_ROLE_DISCLOSURE_TRIANGLE, NSAccessibilityDisclosureTriangleRole}, {ui::AX_ROLE_DIV, NSAccessibilityGroupRole}, {ui::AX_ROLE_DOCUMENT, NSAccessibilityGroupRole}, - {ui::AX_ROLE_EDITABLE_TEXT, NSAccessibilityTextFieldRole}, {ui::AX_ROLE_FIGCAPTION, NSAccessibilityGroupRole}, {ui::AX_ROLE_FIGURE, NSAccessibilityGroupRole}, {ui::AX_ROLE_FOOTER, NSAccessibilityGroupRole}, {ui::AX_ROLE_FORM, NSAccessibilityGroupRole}, {ui::AX_ROLE_GRID, NSAccessibilityGridRole}, {ui::AX_ROLE_GROUP, NSAccessibilityGroupRole}, - {ui::AX_ROLE_GROW_AREA, NSAccessibilityGrowAreaRole}, {ui::AX_ROLE_HEADING, @"AXHeading"}, {ui::AX_ROLE_IFRAME, NSAccessibilityGroupRole}, {ui::AX_ROLE_IGNORED, NSAccessibilityUnknownRole}, @@ -107,7 +105,6 @@ {ui::AX_ROLE_SLIDER_THUMB, NSAccessibilityValueIndicatorRole}, {ui::AX_ROLE_SPIN_BUTTON, NSAccessibilityIncrementorRole}, {ui::AX_ROLE_SPLITTER, NSAccessibilitySplitterRole}, - {ui::AX_ROLE_SPLIT_GROUP, NSAccessibilitySplitGroupRole}, {ui::AX_ROLE_STATIC_TEXT, NSAccessibilityStaticTextRole}, {ui::AX_ROLE_STATUS, NSAccessibilityGroupRole}, {ui::AX_ROLE_SVG_ROOT, NSAccessibilityGroupRole},
diff --git a/ui/app_list/views/app_list_main_view.cc b/ui/app_list/views/app_list_main_view.cc index 97faa4cd..ef551d3 100644 --- a/ui/app_list/views/app_list_main_view.cc +++ b/ui/app_list/views/app_list_main_view.cc
@@ -10,6 +10,7 @@ #include "base/callback.h" #include "base/files/file_path.h" #include "base/message_loop/message_loop.h" +#include "base/profiler/scoped_tracker.h" #include "base/strings/string_util.h" #include "ui/app_list/app_list_constants.h" #include "ui/app_list/app_list_folder_item.h" @@ -142,7 +143,6 @@ AddChildView(contents_view_); search_box_view_->set_contents_view(contents_view_); - UpdateSearchBoxVisibility(); contents_view_->SetPaintToLayer(true); contents_view_->SetFillsBoundsOpaquely(false); @@ -197,20 +197,6 @@ Layout(); } -void AppListMainView::UpdateSearchBoxVisibility() { - bool visible = !contents_view_->IsStateActive(AppListModel::STATE_START); - search_box_view_->SetVisible(visible); - if (visible && GetWidget() && GetWidget()->IsVisible()) - search_box_view_->search_box()->RequestFocus(); -} - -void AppListMainView::OnStartPageSearchTextfieldChanged( - const base::string16& new_contents) { - search_box_view_->SetVisible(true); - search_box_view_->search_box()->SetText(new_contents); - search_box_view_->search_box()->RequestFocus(); -} - views::Widget* AppListMainView::GetCustomPageClickzone() const { // During shutdown, the widgets may be deleted, which means // |custom_page_clickzone_| will be a dangling pointer. Therefore, always @@ -292,6 +278,10 @@ } void AppListMainView::InitWidgets() { + // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed. + tracked_objects::ScopedTracker tracking_profile( + FROM_HERE_WITH_EXPLICIT_FUNCTION("431326 AppListMainView::InitWidgets")); + // The widget that receives click events to transition to the custom page. views::Widget::InitParams custom_page_clickzone_params( views::Widget::InitParams::TYPE_CONTROL); @@ -343,7 +333,6 @@ base::TrimWhitespace(model_->search_box()->text(), base::TRIM_ALL, &query); bool should_show_search = !query.empty(); contents_view_->ShowSearchResults(should_show_search); - UpdateSearchBoxVisibility(); delegate_->StartSearch(); }
diff --git a/ui/app_list/views/app_list_main_view.h b/ui/app_list/views/app_list_main_view.h index 374e28d..81f26838 100644 --- a/ui/app_list/views/app_list_main_view.h +++ b/ui/app_list/views/app_list_main_view.h
@@ -54,10 +54,6 @@ void ModelChanged(); - void UpdateSearchBoxVisibility(); - - void OnStartPageSearchTextfieldChanged(const base::string16& new_contents); - SearchBoxView* search_box_view() const { return search_box_view_; } // Gets the invisible widget that sits partly over the bottom of the app list,
diff --git a/ui/app_list/views/app_list_main_view_unittest.cc b/ui/app_list/views/app_list_main_view_unittest.cc index c7a66b0..ca35458b 100644 --- a/ui/app_list/views/app_list_main_view_unittest.cc +++ b/ui/app_list/views/app_list_main_view_unittest.cc
@@ -154,14 +154,14 @@ grid_view->UpdateDragFromItem(pointer, drag_event); } + ContentsView* GetContentsView() { return main_view_->contents_view(); } + AppsGridView* RootGridView() { - return main_view_->contents_view()->apps_container_view()->apps_grid_view(); + return GetContentsView()->apps_container_view()->apps_grid_view(); } AppListFolderView* FolderView() { - return main_view_->contents_view() - ->apps_container_view() - ->app_list_folder_view(); + return GetContentsView()->apps_container_view()->app_list_folder_view(); } AppsGridView* FolderGridView() { return FolderView()->items_grid_view(); } @@ -293,13 +293,23 @@ // Tests dragging an item out of a single item folder and dropping it onto the // page switcher. Regression test for http://crbug.com/415530/. TEST_F(AppListMainViewTest, DragReparentItemOntoPageSwitcher) { + // Number of apps to populate. Should provide more than 1 page of apps (6*4 = + // 24). + const int kNumApps = 30; + + // Ensure we are on the apps grid view page. + app_list::ContentsView* contents_view = GetContentsView(); + contents_view->SetActivePage( + contents_view->GetPageIndexForState(AppListModel::STATE_APPS)); + contents_view->Layout(); + AppListItemView* folder_item_view = CreateAndOpenSingleItemFolder(); const gfx::Rect first_slot_tile = folder_item_view->bounds(); - delegate_->GetTestModel()->PopulateApps(20); + delegate_->GetTestModel()->PopulateApps(kNumApps); EXPECT_EQ(1, FolderViewModel()->view_size()); - EXPECT_EQ(21, RootViewModel()->view_size()); + EXPECT_EQ(kNumApps + 1, RootViewModel()->view_size()); AppListItemView* dragged = StartDragForReparent(0); @@ -314,7 +324,7 @@ FolderGridView()->EndDrag(false); // The folder should be destroyed. - EXPECT_EQ(21, RootViewModel()->view_size()); + EXPECT_EQ(kNumApps + 1, RootViewModel()->view_size()); EXPECT_EQ(NULL, delegate_->GetTestModel()->FindFolderItem("single_item_folder")); }
diff --git a/ui/app_list/views/app_list_view.cc b/ui/app_list/views/app_list_view.cc index eff6ed52..b400697 100644 --- a/ui/app_list/views/app_list_view.cc +++ b/ui/app_list/views/app_list_view.cc
@@ -159,7 +159,6 @@ app_list_main_view_(NULL), search_box_view_(NULL), speech_view_(NULL), - experimental_banner_view_(NULL), overlay_view_(NULL), animation_observer_(new HideViewAnimationObserver()) { CHECK(delegate); @@ -373,18 +372,6 @@ AddChildView(speech_view_); } - if (app_list::switches::IsExperimentalAppListEnabled()) { - // Draw a banner in the corner of the experimental app list. - experimental_banner_view_ = new views::ImageView; - const gfx::ImageSkia& experimental_icon = - *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( - IDR_APP_LIST_EXPERIMENTAL_ICON); - experimental_banner_view_->SetImage(experimental_icon); - experimental_banner_view_->SetPaintToLayer(true); - experimental_banner_view_->SetFillsBoundsOpaquely(false); - AddChildView(experimental_banner_view_); - } - OnProfilesChanged(); } @@ -502,12 +489,7 @@ } views::View* AppListView::GetInitiallyFocusedView() { - return app_list::switches::IsExperimentalAppListEnabled() - ? app_list_main_view_->contents_view() - ->start_page_view() - ->dummy_search_box_view() - ->search_box() - : app_list_main_view_->search_box_view()->search_box(); + return app_list_main_view_->search_box_view()->search_box(); } gfx::ImageSkia AppListView::GetWindowIcon() { @@ -577,6 +559,8 @@ // GetDefaultSearchBoxBounds() returns the bounds in |contents_view|'s // coordinate, therefore convert it to this coordinate. ContentsView* contents_view = app_list_main_view_->contents_view(); + // TODO(mgiuca): Position the search box in the center of the page, when + // in STATE_START. gfx::RectF search_box_bounds = contents_view->GetDefaultSearchBoxBounds(); ConvertRectToTarget(contents_view, this, &search_box_bounds); search_box_view_->SetBoundsRect(gfx::ToNearestRect(search_box_bounds)); @@ -590,18 +574,6 @@ speech_bounds.Inset(-speech_view_->GetInsets()); speech_view_->SetBoundsRect(speech_bounds); } - - if (experimental_banner_view_) { - // Position the experimental banner in the lower right corner. - gfx::Rect image_bounds = experimental_banner_view_->GetImageBounds(); - image_bounds.set_origin( - gfx::Point(contents_bounds.width() - image_bounds.width(), - contents_bounds.height() - image_bounds.height())); - experimental_banner_view_->SetBoundsRect(image_bounds); - } - - if (overlay_view_) - overlay_view_->SetBoundsRect(contents_bounds); } void AppListView::SchedulePaintInRect(const gfx::Rect& rect) {
diff --git a/ui/app_list/views/app_list_view.h b/ui/app_list/views/app_list_view.h index f32434e..53eb0dc 100644 --- a/ui/app_list/views/app_list_view.h +++ b/ui/app_list/views/app_list_view.h
@@ -95,6 +95,8 @@ // Returns true if the app list should be centered and in landscape mode. bool ShouldCenterWindow() const; + SearchBoxView* search_box_view() const { return search_box_view_; } + // Overridden from views::View: gfx::Size GetPreferredSize() const override; void Paint(gfx::Canvas* canvas, const views::CullSet& cull_set) override; @@ -167,9 +169,6 @@ SearchBoxView* search_box_view_; SpeechView* speech_view_; - // The red "experimental" banner for the experimental app list. - views::ImageView* experimental_banner_view_; - // A semi-transparent white overlay that covers the app list while dialogs are // open. views::View* overlay_view_;
diff --git a/ui/app_list/views/app_list_view_unittest.cc b/ui/app_list/views/app_list_view_unittest.cc index 4638791..94fbd56e 100644 --- a/ui/app_list/views/app_list_view_unittest.cc +++ b/ui/app_list/views/app_list_view_unittest.cc
@@ -180,9 +180,13 @@ : test_type_(static_cast<TestType>(test_type)) { switch (test_type_) { case NORMAL: + base::CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kDisableExperimentalAppList); break; case LANDSCAPE: base::CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kDisableExperimentalAppList); + base::CommandLine::ForCurrentProcess()->AppendSwitch( switches::kEnableCenteredAppList); break; case EXPERIMENTAL: @@ -432,7 +436,6 @@ // Show the start page view. EXPECT_TRUE(SetAppListState(AppListModel::STATE_START)); - EXPECT_FALSE(main_view->search_box_view()->visible()); gfx::Size view_size(view_->GetPreferredSize()); // Simulate clicking the "All apps" button. Check that we navigate to the @@ -441,7 +444,6 @@ SimulateClick(start_page_view->all_apps_button()); main_view->contents_view()->Layout(); EXPECT_TRUE(IsStateShown(AppListModel::STATE_APPS)); - EXPECT_TRUE(main_view->search_box_view()->visible()); // Hiding and showing the search box should not affect the app list's // preferred size. This is a regression test for http://crbug.com/386912. @@ -565,13 +567,11 @@ AppListMainView* main_view = view_->app_list_main_view(); ContentsView* contents_view = main_view->contents_view(); EXPECT_TRUE(SetAppListState(AppListModel::STATE_APPS)); - EXPECT_TRUE(main_view->search_box_view()->visible()); // Show the search results. contents_view->ShowSearchResults(true); contents_view->Layout(); EXPECT_TRUE(contents_view->IsStateActive(AppListModel::STATE_SEARCH_RESULTS)); - EXPECT_TRUE(main_view->search_box_view()->visible()); const gfx::Rect default_contents_bounds = contents_view->GetDefaultContentsBounds(); @@ -594,51 +594,49 @@ EXPECT_EQ(AppListModel::STATE_APPS, delegate_->GetTestModel()->state()); EXPECT_EQ(default_contents_bounds, contents_view->apps_container_view()->bounds()); - EXPECT_TRUE(main_view->search_box_view()->visible()); if (test_type_ == EXPERIMENTAL) { + // Check that typing into the search box triggers the search page. EXPECT_TRUE(SetAppListState(AppListModel::STATE_START)); - // Check that typing into the dummy search box triggers the search page. + view_->Layout(); + EXPECT_EQ(default_contents_bounds, + contents_view->start_page_view()->bounds()); + // TODO(mgiuca): The search box should be small and centered. + EXPECT_EQ(contents_view->GetDefaultSearchBoxBounds(), + view_->search_box_view()->bounds()); + base::string16 search_text = base::UTF8ToUTF16("test"); - SearchBoxView* dummy_search_box = - contents_view->start_page_view()->dummy_search_box_view(); - EXPECT_TRUE(dummy_search_box->IsDrawn()); - dummy_search_box->search_box()->InsertText(search_text); - contents_view->Layout(); + main_view->search_box_view()->search_box()->SetText(base::string16()); + main_view->search_box_view()->search_box()->InsertText(search_text); // Check that the current search is using |search_text|. EXPECT_EQ(search_text, delegate_->GetTestModel()->search_box()->text()); - EXPECT_TRUE(main_view->search_box_view()->visible()); EXPECT_EQ(search_text, main_view->search_box_view()->search_box()->text()); + view_->Layout(); EXPECT_TRUE( contents_view->IsStateActive(AppListModel::STATE_SEARCH_RESULTS)); - EXPECT_EQ(AppListModel::STATE_SEARCH_RESULTS, - delegate_->GetTestModel()->state()); - EXPECT_EQ(default_contents_bounds, - contents_view->search_results_page_view()->bounds()); + EXPECT_EQ(contents_view->GetDefaultSearchBoxBounds(), + view_->search_box_view()->bounds()); - // Check that typing into the real search box triggers the search page. + // Check that typing into the search box triggers the search page. EXPECT_TRUE(SetAppListState(AppListModel::STATE_APPS)); + view_->Layout(); EXPECT_EQ(default_contents_bounds, contents_view->apps_container_view()->bounds()); + EXPECT_EQ(contents_view->GetDefaultSearchBoxBounds(), + view_->search_box_view()->bounds()); base::string16 new_search_text = base::UTF8ToUTF16("apple"); main_view->search_box_view()->search_box()->SetText(base::string16()); main_view->search_box_view()->search_box()->InsertText(new_search_text); - // Check that the current search is using |search_text|. + // Check that the current search is using |new_search_text|. EXPECT_EQ(new_search_text, delegate_->GetTestModel()->search_box()->text()); EXPECT_EQ(new_search_text, main_view->search_box_view()->search_box()->text()); - contents_view->Layout(); + view_->Layout(); EXPECT_TRUE( contents_view->IsStateActive(AppListModel::STATE_SEARCH_RESULTS)); - EXPECT_TRUE(main_view->search_box_view()->visible()); - EXPECT_TRUE(dummy_search_box->search_box()->text().empty()); - - // Check that the dummy search box is clear when reshowing the start page. - EXPECT_TRUE(SetAppListState(AppListModel::STATE_APPS)); - EXPECT_TRUE(SetAppListState(AppListModel::STATE_START)); - EXPECT_TRUE(dummy_search_box->IsDrawn()); - EXPECT_TRUE(dummy_search_box->search_box()->text().empty()); + EXPECT_EQ(contents_view->GetDefaultSearchBoxBounds(), + view_->search_box_view()->bounds()); } Close();
diff --git a/ui/app_list/views/apps_grid_view.cc b/ui/app_list/views/apps_grid_view.cc index 73bc8b7b..f5e5ca0 100644 --- a/ui/app_list/views/apps_grid_view.cc +++ b/ui/app_list/views/apps_grid_view.cc
@@ -110,15 +110,6 @@ : gfx::Size(kPreferredTileWidth, kPreferredTileHeight); } -// Returns the size of a tile view inccluding its padding. -gfx::Size GetTotalTileSize() { - gfx::Size size = GetTileViewSize(); - if (switches::IsExperimentalAppListEnabled()) - size.Enlarge(2 * kExperimentalTileLeftRightPadding, - 2 * kExperimentalTileTopBottomPadding); - return size; -} - // RowMoveAnimationDelegate is used when moving an item into a different row. // Before running the animation, the item's layer is re-created and kept in // the original position, then the item is moved to just before its target @@ -425,6 +416,16 @@ } } +// static +gfx::Size AppsGridView::GetTotalTileSize() { + gfx::Size size = GetTileViewSize(); + if (switches::IsExperimentalAppListEnabled()) { + size.Enlarge(2 * kExperimentalTileLeftRightPadding, + 2 * kExperimentalTileTopBottomPadding); + } + return size; +} + void AppsGridView::ResetForShowApps() { activated_folder_item_view_ = NULL; ClearDragState();
diff --git a/ui/app_list/views/apps_grid_view.h b/ui/app_list/views/apps_grid_view.h index e5a2d2c..3ec37548 100644 --- a/ui/app_list/views/apps_grid_view.h +++ b/ui/app_list/views/apps_grid_view.h
@@ -79,6 +79,9 @@ int cols() const { return cols_; } int rows_per_page() const { return rows_per_page_; } + // Returns the size of a tile view including its padding. + static gfx::Size GetTotalTileSize(); + // This resets the grid view to a fresh state for showing the app list. void ResetForShowApps();
diff --git a/ui/app_list/views/apps_grid_view_unittest.cc b/ui/app_list/views/apps_grid_view_unittest.cc index 7e9ba741..e7edc45 100644 --- a/ui/app_list/views/apps_grid_view_unittest.cc +++ b/ui/app_list/views/apps_grid_view_unittest.cc
@@ -35,9 +35,6 @@ const int kRows = 2; const int kTilesPerPage = kCols * kRows; -const int kWidth = 320; -const int kHeight = 240; - class PageFlipWaiter : public PaginationModelObserver { public: PageFlipWaiter(base::MessageLoopForUI* ui_loop, PaginationModel* model) @@ -96,7 +93,8 @@ apps_grid_view_.reset(new AppsGridView(NULL)); apps_grid_view_->SetLayout(kCols, kRows); - apps_grid_view_->SetBoundsRect(gfx::Rect(gfx::Size(kWidth, kHeight))); + apps_grid_view_->SetBoundsRect( + gfx::Rect(apps_grid_view_->GetPreferredSize())); apps_grid_view_->SetModel(model_.get()); apps_grid_view_->SetItemList(model_->top_level_item_list()); @@ -133,7 +131,7 @@ gfx::Insets insets(apps_grid_view_->GetInsets()); gfx::Rect rect(gfx::Point(insets.left(), insets.top()), - GetItemViewAt(0)->bounds().size()); + AppsGridView::GetTotalTileSize()); rect.Offset(col * rect.width(), row * rect.height()); return rect; } @@ -437,6 +435,7 @@ // Drag the new item to the left so that the grid reorders. gfx::Point from = GetItemTileRectAt(0, 1).CenterPoint(); gfx::Point to = GetItemTileRectAt(0, 0).bottom_left(); + to.Offset(0, -1); // Get a point inside the rect. AppListItemView* dragged_view = SimulateDrag(AppsGridView::MOUSE, from, to); test_api_->LayoutToIdealBounds();
diff --git a/ui/app_list/views/contents_view.cc b/ui/app_list/views/contents_view.cc index 3f649e7..c703dcf 100644 --- a/ui/app_list/views/contents_view.cc +++ b/ui/app_list/views/contents_view.cc
@@ -205,9 +205,6 @@ if (search_results_list_view_) search_results_list_view_->UpdateAutoLaunchState(); - // Notify parent AppListMainView of the page change. - app_list_main_view_->UpdateSearchBoxVisibility(); - if (custom_page_view_) { custom_page_view_->SetFocusable(state == AppListModel::STATE_CUSTOM_LAUNCHER_PAGE); @@ -427,8 +424,16 @@ gfx::Rect rect(GetDefaultContentsBounds()); // Custom pages are aligned to the top of the window, not under the search // box. - if (IsStateActive(AppListModel::STATE_CUSTOM_LAUNCHER_PAGE)) + double progress = 0; + if (IsStateActive(AppListModel::STATE_CUSTOM_LAUNCHER_PAGE)) { rect = GetContentsBounds(); + progress = 1; + } + + // Notify the custom launcher page that the active page has changed. + app_list_main_view_->view_delegate()->CustomLauncherPageAnimationChanged( + progress); + if (rect.IsEmpty()) return;
diff --git a/ui/app_list/views/search_box_view.cc b/ui/app_list/views/search_box_view.cc index c519fee..9ef86f0 100644 --- a/ui/app_list/views/search_box_view.cc +++ b/ui/app_list/views/search_box_view.cc
@@ -266,6 +266,7 @@ speech_button_ = NULL; } } + Layout(); } void SearchBoxView::HintTextChanged() {
diff --git a/ui/app_list/views/start_page_view.cc b/ui/app_list/views/start_page_view.cc index b8642c1..e696637 100644 --- a/ui/app_list/views/start_page_view.cc +++ b/ui/app_list/views/start_page_view.cc
@@ -12,6 +12,7 @@ #include "ui/app_list/search_result.h" #include "ui/app_list/views/all_apps_tile_item_view.h" #include "ui/app_list/views/app_list_main_view.h" +#include "ui/app_list/views/contents_view.h" #include "ui/app_list/views/search_box_view.h" #include "ui/app_list/views/search_result_list_view.h" #include "ui/app_list/views/search_result_tile_item_view.h" @@ -32,38 +33,33 @@ const int kTopMargin = 84; const int kInstantContainerSpacing = 11; const int kSearchBoxAndTilesSpacing = 40; +const int kStartPageSearchBoxWidth = 480; // WebView constants. const int kWebViewWidth = 500; const int kWebViewHeight = 105; -// DummySearchBoxView constants. -const int kDummySearchBoxWidth = 480; - // Tile container constants. const size_t kNumStartPageTiles = 4; const int kTileSpacing = 10; -// A placeholder search box which is sized to fit within the start page view. -class DummySearchBoxView : public SearchBoxView { +// An invisible placeholder view which fills the space for the search box view +// in a box layout. The search box view itself is a child of the AppListView +// (because it is visible on many different pages). +class SearchBoxSpacerView : public views::View { public: - DummySearchBoxView(SearchBoxViewDelegate* delegate, - AppListViewDelegate* view_delegate) - : SearchBoxView(delegate, view_delegate) { - back_button()->SetVisible(false); - } + SearchBoxSpacerView(const gfx::Size& search_box_size) + : size_(kStartPageSearchBoxWidth, search_box_size.height()) {} - ~DummySearchBoxView() override {} + ~SearchBoxSpacerView() override {} // Overridden from views::View: - gfx::Size GetPreferredSize() const override { - gfx::Size size(SearchBoxView::GetPreferredSize()); - size.set_width(kDummySearchBoxWidth); - return size; - } + gfx::Size GetPreferredSize() const override { return size_; } private: - DISALLOW_COPY_AND_ASSIGN(DummySearchBoxView); + gfx::Size size_; + + DISALLOW_COPY_AND_ASSIGN(SearchBoxSpacerView); }; } // namespace @@ -72,10 +68,11 @@ AppListViewDelegate* view_delegate) : app_list_main_view_(app_list_main_view), view_delegate_(view_delegate), - search_box_view_(new DummySearchBoxView(this, view_delegate_)), + search_box_spacer_view_(new SearchBoxSpacerView( + app_list_main_view->search_box_view()->GetPreferredSize())), instant_container_(new views::View), tiles_container_(new views::View) { - // The view containing the start page WebContents and DummySearchBoxView. + // The view containing the start page WebContents and SearchBoxSpacerView. InitInstantContainer(); AddChildView(instant_container_); @@ -108,17 +105,7 @@ instant_container_->AddChildView(web_view); } - // TODO(calamity): This container is needed to horizontally center the search - // box view. Remove this container once BoxLayout supports CrossAxisAlignment. - views::View* search_box_container = new views::View(); - views::BoxLayout* layout_manager = - new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0); - layout_manager->set_main_axis_alignment( - views::BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER); - search_box_container->SetLayoutManager(layout_manager); - search_box_container->AddChildView(search_box_view_); - - instant_container_->AddChildView(search_box_container); + instant_container_->AddChildView(search_box_spacer_view_); } void StartPageView::InitTilesContainer() { @@ -146,13 +133,6 @@ } void StartPageView::Reset() { - // This can be called when the app list is closing (widget is invisible). In - // that case, do not steal focus from other elements. - if (GetWidget() && GetWidget()->IsVisible()) - search_box_view_->search_box()->RequestFocus(); - - search_box_view_->ClearSearch(); - Update(); } @@ -219,15 +199,4 @@ void StartPageView::UpdateSelectedIndex(int old_selected, int new_selected) { } -void StartPageView::QueryChanged(SearchBoxView* sender) { - // Forward the search terms on to the real search box and clear the dummy - // search box. - app_list_main_view_->OnStartPageSearchTextfieldChanged( - sender->search_box()->text()); - sender->search_box()->SetText(base::string16()); -} - -void StartPageView::BackButtonPressed() { -} - } // namespace app_list
diff --git a/ui/app_list/views/start_page_view.h b/ui/app_list/views/start_page_view.h index 62364c6..a867ada 100644 --- a/ui/app_list/views/start_page_view.h +++ b/ui/app_list/views/start_page_view.h
@@ -7,7 +7,6 @@ #include "base/basictypes.h" #include "ui/app_list/app_list_export.h" -#include "ui/app_list/views/search_box_view_delegate.h" #include "ui/app_list/views/search_result_container_view.h" namespace app_list { @@ -19,8 +18,7 @@ class TileItemView; // The start page for the experimental app list. -class APP_LIST_EXPORT StartPageView : public SearchResultContainerView, - public SearchBoxViewDelegate { +class APP_LIST_EXPORT StartPageView : public SearchResultContainerView { public: StartPageView(AppListMainView* app_list_main_view, AppListViewDelegate* view_delegate); @@ -34,7 +32,6 @@ return search_result_tile_views_; } TileItemView* all_apps_button() const; - SearchBoxView* dummy_search_box_view() { return search_box_view_; } // Called when the start page view is displayed. void OnShow(); @@ -57,16 +54,12 @@ void InitInstantContainer(); void InitTilesContainer(); - // Overridden from SearchBoxViewDelegate: - void QueryChanged(SearchBoxView* sender) override; - void BackButtonPressed() override; - // The parent view of ContentsView which is the parent of this view. AppListMainView* app_list_main_view_; AppListViewDelegate* view_delegate_; // Owned by AppListView. - SearchBoxView* search_box_view_; // Owned by views hierarchy. + views::View* search_box_spacer_view_; // Owned by views hierarchy. views::View* instant_container_; // Owned by views hierarchy. views::View* tiles_container_; // Owned by views hierarchy.
diff --git a/ui/aura/window_unittest.cc b/ui/aura/window_unittest.cc index 2972507..d28df60 100644 --- a/ui/aura/window_unittest.cc +++ b/ui/aura/window_unittest.cc
@@ -1994,26 +1994,6 @@ w.reset(); } -TEST_F(WindowTest, StackWindowAtBottomBelowWindowWhoseLayerHasNoDelegate) { - scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window())); - window1->layer()->set_name("1"); - scoped_ptr<Window> window2(CreateTestWindowWithId(2, root_window())); - window2->layer()->set_name("2"); - scoped_ptr<Window> window3(CreateTestWindowWithId(3, root_window())); - window3->layer()->set_name("3"); - - EXPECT_EQ("1 2 3", ChildWindowIDsAsString(root_window())); - EXPECT_EQ("1 2 3", - ui::test::ChildLayerNamesAsString(*root_window()->layer())); - window1->layer()->set_delegate(NULL); - root_window()->StackChildAtBottom(window3.get()); - - // Window 3 should have moved to the bottom. - EXPECT_EQ("3 1 2", ChildWindowIDsAsString(root_window())); - EXPECT_EQ("3 1 2", - ui::test::ChildLayerNamesAsString(*root_window()->layer())); -} - class TestVisibilityClient : public client::VisibilityClient { public: explicit TestVisibilityClient(Window* root_window)
diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn index e9bdf73..a92f42d 100644 --- a/ui/base/BUILD.gn +++ b/ui/base/BUILD.gn
@@ -747,14 +747,8 @@ # TODO(GYP): Make this work on Android and reenable it. if (!is_android) { -# TODO(tfarina): Rename this target to ui_base_unittests. -# In order to do this we will need to keep this target, add a dummy -# ui_base_unittests target that just points to ui_unittests, change -# buildbot code to reference the new 'ui_base_unittests' target. -# After buildbot is updated, we can make the changes in Chromium and -# remove 'ui_unittests' target. crbug.com/331829 -# GYP version: ui/base/ui_base_tests.gyp:ui_unittests -test("ui_unittests") { +# GYP version: ui/base/ui_base_tests.gyp:ui_base_unittests +test("ui_base_unittests") { sources = [ "l10n/l10n_util_mac_unittest.mm", "l10n/l10n_util_unittest.cc", @@ -848,7 +842,7 @@ ] if (is_ios) { - # TODO(GYP) lots of iOS-only steps for ui_unittests + # TODO(GYP) lots of iOS-only steps for ui_base_unittests } if (is_win) { @@ -918,7 +912,7 @@ deps += [ "//third_party/mozilla", - #'ui_unittests_bundle', TODO(GYP) + #'ui_base_tests_bundle', TODO(GYP) ] } @@ -944,4 +938,4 @@ } } } -# TODO(GYP) Mac (ui_unittest_bundle) and Android (ui_unittests_apk). +# TODO(GYP) Mac (ui_base_tests_bundle) and Android (ui_base_unittests_apk).
diff --git a/ui/base/test/run_all_unittests.cc b/ui/base/test/run_all_unittests.cc index 4215631..19adcedb 100644 --- a/ui/base/test/run_all_unittests.cc +++ b/ui/base/test/run_all_unittests.cc
@@ -73,8 +73,9 @@ "en-US", NULL, ui::ResourceBundle::LOAD_COMMON_RESOURCES); #elif defined(OS_IOS) || defined(OS_ANDROID) - // On iOS, the ui_unittests binary is itself a mini bundle, with resources - // built in. On Android, ui_unittests_apk provides the necessary framework. + // On iOS, the ui_base_unittests binary is itself a mini bundle, with + // resources built in. On Android, ui_base_unittests_apk provides the + // necessary framework. ui::ResourceBundle::InitSharedInstanceWithLocale( "en-US", NULL, ui::ResourceBundle::LOAD_COMMON_RESOURCES); @@ -85,7 +86,7 @@ ui::ResourceBundle::InitSharedInstanceWithPakPath( exe_path.AppendASCII("ui_test.pak")); - // ui_unittests can't depend on the locales folder which Chrome will make + // ui_base_unittests can't depend on the locales folder which Chrome will make // later, so use the path created by ui_test_pak. PathService::Override(ui::DIR_LOCALES, exe_path.AppendASCII("ui")); #endif
diff --git a/ui/base/ui_base_switches.cc b/ui/base/ui_base_switches.cc index 24d0d553..abf7f63 100644 --- a/ui/base/ui_base_switches.cc +++ b/ui/base/ui_base_switches.cc
@@ -27,6 +27,9 @@ // Disables controls that support touch base text editing. const char kDisableTouchEditing[] = "disable-touch-editing"; +// Disables additional visual feedback to touch input. +const char kDisableTouchFeedback[] = "disable-touch-feedback"; + // Enables a zoomed popup bubble that allows the user to select a link. const char kEnableLinkDisambiguationPopup[] = "enable-link-disambiguation-popup"; @@ -40,9 +43,6 @@ // Enables controls that support touch base text editing. const char kEnableTouchEditing[] = "enable-touch-editing"; -// Enables additional visual feedback to touch input. -const char kEnableTouchFeedback[] = "enable-touch-feedback"; - // The language file that we want to try to open. Of the form // language[-country] where language is the 2 letter code from ISO-639. const char kLang[] = "lang";
diff --git a/ui/base/ui_base_switches.h b/ui/base/ui_base_switches.h index b4d503b..56e5d2c 100644 --- a/ui/base/ui_base_switches.h +++ b/ui/base/ui_base_switches.h
@@ -21,11 +21,11 @@ UI_BASE_EXPORT extern const char kDisableTouchAdjustment[]; UI_BASE_EXPORT extern const char kDisableTouchDragDrop[]; UI_BASE_EXPORT extern const char kDisableTouchEditing[]; +UI_BASE_EXPORT extern const char kDisableTouchFeedback[]; UI_BASE_EXPORT extern const char kEnableLinkDisambiguationPopup[]; UI_BASE_EXPORT extern const char kEnableTextInputFocusManager[]; UI_BASE_EXPORT extern const char kEnableTouchDragDrop[]; UI_BASE_EXPORT extern const char kEnableTouchEditing[]; -UI_BASE_EXPORT extern const char kEnableTouchFeedback[]; UI_BASE_EXPORT extern const char kLang[]; UI_BASE_EXPORT extern const char kNoMessageBox[]; UI_BASE_EXPORT extern const char kViewerConnect[];
diff --git a/ui/base/ui_base_switches_util.cc b/ui/base/ui_base_switches_util.cc index 7a89264a..5fe380a 100644 --- a/ui/base/ui_base_switches_util.cc +++ b/ui/base/ui_base_switches_util.cc
@@ -47,8 +47,8 @@ } bool IsTouchFeedbackEnabled() { - static bool touch_feedback_enabled = CommandLine::ForCurrentProcess()-> - HasSwitch(switches::kEnableTouchFeedback); + static bool touch_feedback_enabled = !CommandLine::ForCurrentProcess()-> + HasSwitch(switches::kDisableTouchFeedback); return touch_feedback_enabled; }
diff --git a/ui/base/ui_base_tests.gyp b/ui/base/ui_base_tests.gyp index 2deda70..85626be 100644 --- a/ui/base/ui_base_tests.gyp +++ b/ui/base/ui_base_tests.gyp
@@ -8,19 +8,223 @@ }, 'targets': [ { - # TODO(tfarina): Remove this target after all traces of it are updated to - # point to ui_base_unittests. That means updating buildbot code and some - # references in chromium too. crbug.com/331829 - # GN version: //ui/base:unittests - 'target_name': 'ui_unittests', - 'includes': [ 'ui_base_tests.gypi' ], - }, - { # GN version: //ui/base:unittests 'target_name': 'ui_base_unittests', - # TODO(tfarina): When ui_unittests is removed, move the content of the - # gypi file back here. - 'includes': [ 'ui_base_tests.gypi' ], + 'type': '<(gtest_target_type)', + 'dependencies': [ + '../../base/base.gyp:base', + '../../base/base.gyp:test_support_base', + '../../net/net.gyp:net', + '../../skia/skia.gyp:skia', + '../../testing/gmock.gyp:gmock', + '../../testing/gtest.gyp:gtest', + '../../third_party/icu/icu.gyp:icui18n', + '../../third_party/icu/icu.gyp:icuuc', + '../../url/url.gyp:url_lib', + '../events/events.gyp:events_base', + '../gfx/gfx.gyp:gfx_test_support', + '../resources/ui_resources.gyp:ui_resources', + '../resources/ui_resources.gyp:ui_test_pak', + '../strings/ui_strings.gyp:ui_strings', + 'ui_base.gyp:ui_base', + 'ui_base.gyp:ui_base_test_support', + ], + # iOS uses a small subset of ui. common_sources are the only files that + # are built on iOS. + 'common_sources' : [ + # Note: file list duplicated in GN build. + 'layout_unittest.cc', + 'l10n/l10n_util_mac_unittest.mm', + 'l10n/l10n_util_unittest.cc', + 'l10n/l10n_util_win_unittest.cc', + 'l10n/time_format_unittest.cc', + 'models/tree_node_iterator_unittest.cc', + 'resource/data_pack_literal.cc', + 'resource/data_pack_unittest.cc', + 'resource/resource_bundle_unittest.cc', + 'test/run_all_unittests.cc', + ], + 'all_sources': [ + # Note: file list duplicated in GN build. + '<@(_common_sources)', + 'accelerators/accelerator_manager_unittest.cc', + 'accelerators/menu_label_accelerator_util_linux_unittest.cc', + 'clipboard/custom_data_helper_unittest.cc', + 'cocoa/base_view_unittest.mm', + 'cocoa/cocoa_base_utils_unittest.mm', + 'cocoa/controls/blue_label_button_unittest.mm', + 'cocoa/controls/hover_image_menu_button_unittest.mm', + 'cocoa/controls/hyperlink_button_cell_unittest.mm', + 'cocoa/controls/hyperlink_text_view_unittest.mm', + 'cocoa/focus_tracker_unittest.mm', + 'cocoa/fullscreen_window_manager_unittest.mm', + 'cocoa/hover_image_button_unittest.mm', + 'cocoa/menu_controller_unittest.mm', + 'cocoa/nsgraphics_context_additions_unittest.mm', + 'cocoa/nsview_additions_unittest.mm', + 'cocoa/tracking_area_unittest.mm', + 'dragdrop/os_exchange_data_provider_aurax11_unittest.cc', + 'ime/candidate_window_unittest.cc', + 'ime/chromeos/character_composer_unittest.cc', + 'ime/composition_text_util_pango_unittest.cc', + 'ime/input_method_base_unittest.cc', + 'ime/input_method_chromeos_unittest.cc', + 'ime/remote_input_method_win_unittest.cc', + 'ime/win/imm32_manager_unittest.cc', + 'ime/win/tsf_input_scope_unittest.cc', + 'models/list_model_unittest.cc', + 'models/list_selection_model_unittest.cc', + 'models/tree_node_model_unittest.cc', + 'test/test_clipboard_unittest.cc', + 'test/data/resource.h', + 'text/bytes_formatting_unittest.cc', + 'touch/touch_editing_controller_unittest.cc', + 'view_prop_unittest.cc', + 'webui/web_ui_util_unittest.cc', + 'x/selection_requestor_unittest.cc', + ], + 'include_dirs': [ + '../..', + ], + 'conditions': [ + ['OS!="ios"', { + 'sources' : [ '<@(_all_sources)' ], + }, { # OS=="ios" + 'sources' : [ '<@(_common_sources)' ], + # The ResourceBundle unittest expects a locale.pak file to exist in + # the bundle for English-US. Copy it in from where it was generated + # by ui_resources.gyp:ui_test_pak. + 'mac_bundle_resources': [ + '<(PRODUCT_DIR)/ui/en.lproj/locale.pak', + ], + 'actions': [ + { + 'action_name': 'copy_test_data', + 'variables': { + 'test_data_files': [ + 'test/data', + ], + 'test_data_prefix' : 'ui/base', + }, + 'includes': [ '../../build/copy_test_data_ios.gypi' ], + }, + ], + }], + ['OS == "win"', { + 'sources': [ + 'dragdrop/os_exchange_data_win_unittest.cc', + 'win/hwnd_subclass_unittest.cc', + 'win/open_file_name_win_unittest.cc', + ], + 'msvs_settings': { + 'VCLinkerTool': { + 'DelayLoadDLLs': [ + 'd2d1.dll', + 'd3d10_1.dll', + ], + 'AdditionalDependencies': [ + 'd2d1.lib', + 'd3d10_1.lib', + ], + }, + }, + 'link_settings': { + 'libraries': [ + '-limm32.lib', + '-loleacc.lib', + ], + }, + # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. + 'msvs_disabled_warnings': [ 4267, ], + }], + ['OS == "android"', { + 'dependencies': [ + '../../testing/android/native_test.gyp:native_test_native_code', + ], + 'sources!': [ + 'touch/touch_editing_controller_unittest.cc', + ], + }], + ['use_pango == 1', { + 'dependencies': [ + '../../build/linux/system.gyp:pangocairo', + ], + 'conditions': [ + ['use_allocator!="none"', { + 'dependencies': [ + '../../base/allocator/allocator.gyp:allocator', + ], + }], + ], + }], + ['use_x11==1', { + 'dependencies': [ + '../../build/linux/system.gyp:x11', + '../../tools/xdisplaycheck/xdisplaycheck.gyp:xdisplaycheck', + '../events/platform/x11/x11_events_platform.gyp:x11_events_platform', + '../gfx/x/gfx_x11.gyp:gfx_x11', + ], + }], + ['OS!="win" or use_aura==0', { + 'sources!': [ + 'view_prop_unittest.cc', + ], + }], + ['use_x11==1 and use_aura==1', { + 'sources': [ + 'cursor/cursor_loader_x11_unittest.cc', + ], + }], + ['OS=="mac"', { + 'dependencies': [ + '../../third_party/mozilla/mozilla.gyp:mozilla', + '../events/events.gyp:events_test_support', + 'ui_base_tests_bundle', + ], + 'conditions': [ + ['component=="static_library"', { + # Needed for mozilla.gyp. + 'xcode_settings': {'OTHER_LDFLAGS': ['-Wl,-ObjC']}, + }], + ], + }], + ['use_aura==1 or toolkit_views==1', { + 'sources': [ + 'dragdrop/os_exchange_data_unittest.cc', + ], + 'dependencies': [ + '../events/events.gyp:events', + '../events/events.gyp:events_base', + '../events/events.gyp:events_test_support', + '../events/platform/events_platform.gyp:events_platform', + ], + }], + ['chromeos==1', { + 'dependencies': [ + '../../chromeos/chromeos.gyp:chromeos', + ], + 'sources!': [ + 'dragdrop/os_exchange_data_provider_aurax11_unittest.cc', + 'x/selection_requestor_unittest.cc', + ], + }], + ['use_x11==0', { + 'sources!': [ + 'ime/chromeos/character_composer_unittest.cc', + 'ime/input_method_chromeos_unittest.cc', + 'ime/composition_text_util_pango_unittest.cc', + ], + }], + ], + 'target_conditions': [ + ['OS == "ios"', { + 'sources/': [ + # Pull in specific Mac files for iOS (which have been filtered out + # by file name rules). + ['include', '^l10n/l10n_util_mac_unittest\\.mm$'], + ], + }], + ], }, ], 'conditions': [ @@ -51,25 +255,6 @@ ['OS == "android"', { 'targets': [ { - # TODO(tfarina): Remove this target after all traces of it are updated - # to point to ui_base_unittests_apk. crbug.com/331829 - 'target_name': 'ui_unittests_apk', - 'type': 'none', - 'dependencies': [ - # TODO(tfarina): This is a layer violation and should be removed. - # crbug.com/176960 - # For now this is here as a temporary band-aid to fix the clobber - # issue we are seeing when running this target on Android. - # crbug.com/374490 - '../../chrome/chrome_resources.gyp:packed_resources', - 'ui_unittests', - ], - 'variables': { - 'test_suite_name': 'ui_unittests', - }, - 'includes': [ '../../build/apk_test.gypi' ], - }, - { 'target_name': 'ui_base_unittests_apk', 'type': 'none', 'dependencies': [
diff --git a/ui/base/ui_base_tests.gypi b/ui/base/ui_base_tests.gypi deleted file mode 100644 index 080587a..0000000 --- a/ui/base/ui_base_tests.gypi +++ /dev/null
@@ -1,225 +0,0 @@ -# Copyright 2013 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -{ - 'type': '<(gtest_target_type)', - 'dependencies': [ - '../../base/base.gyp:base', - '../../base/base.gyp:test_support_base', - '../../net/net.gyp:net', - '../../skia/skia.gyp:skia', - '../../testing/gmock.gyp:gmock', - '../../testing/gtest.gyp:gtest', - '../../third_party/icu/icu.gyp:icui18n', - '../../third_party/icu/icu.gyp:icuuc', - '../../url/url.gyp:url_lib', - '../events/events.gyp:events_base', - '../gfx/gfx.gyp:gfx_test_support', - '../resources/ui_resources.gyp:ui_resources', - '../resources/ui_resources.gyp:ui_test_pak', - '../strings/ui_strings.gyp:ui_strings', - 'ui_base.gyp:ui_base', - 'ui_base.gyp:ui_base_test_support', - ], - # iOS uses a small subset of ui. common_sources are the only files that - # are built on iOS. - 'common_sources' : [ - # Note: file list duplicated in GN build. - 'layout_unittest.cc', - 'l10n/l10n_util_mac_unittest.mm', - 'l10n/l10n_util_unittest.cc', - 'l10n/l10n_util_win_unittest.cc', - 'l10n/time_format_unittest.cc', - 'models/tree_node_iterator_unittest.cc', - 'resource/data_pack_literal.cc', - 'resource/data_pack_unittest.cc', - 'resource/resource_bundle_unittest.cc', - 'test/run_all_unittests.cc', - ], - 'all_sources': [ - # Note: file list duplicated in GN build. - '<@(_common_sources)', - 'accelerators/accelerator_manager_unittest.cc', - 'accelerators/menu_label_accelerator_util_linux_unittest.cc', - 'clipboard/custom_data_helper_unittest.cc', - 'cocoa/base_view_unittest.mm', - 'cocoa/cocoa_base_utils_unittest.mm', - 'cocoa/controls/blue_label_button_unittest.mm', - 'cocoa/controls/hover_image_menu_button_unittest.mm', - 'cocoa/controls/hyperlink_button_cell_unittest.mm', - 'cocoa/controls/hyperlink_text_view_unittest.mm', - 'cocoa/focus_tracker_unittest.mm', - 'cocoa/fullscreen_window_manager_unittest.mm', - 'cocoa/hover_image_button_unittest.mm', - 'cocoa/menu_controller_unittest.mm', - 'cocoa/nsgraphics_context_additions_unittest.mm', - 'cocoa/nsview_additions_unittest.mm', - 'cocoa/tracking_area_unittest.mm', - 'dragdrop/os_exchange_data_provider_aurax11_unittest.cc', - 'ime/candidate_window_unittest.cc', - 'ime/chromeos/character_composer_unittest.cc', - 'ime/chromeos/component_extension_ime_manager_unittest.cc', - 'ime/chromeos/composition_text_unittest.cc', - 'ime/chromeos/extension_ime_util_unittest.cc', - 'ime/chromeos/ime_keyboard_x11_unittest.cc', - 'ime/composition_text_util_pango_unittest.cc', - 'ime/input_method_base_unittest.cc', - 'ime/input_method_chromeos_unittest.cc', - 'ime/remote_input_method_win_unittest.cc', - 'ime/win/imm32_manager_unittest.cc', - 'ime/win/tsf_input_scope_unittest.cc', - 'models/list_model_unittest.cc', - 'models/list_selection_model_unittest.cc', - 'models/tree_node_model_unittest.cc', - 'test/test_clipboard_unittest.cc', - 'test/data/resource.h', - 'text/bytes_formatting_unittest.cc', - 'touch/touch_editing_controller_unittest.cc', - 'view_prop_unittest.cc', - 'webui/web_ui_util_unittest.cc', - 'x/selection_requestor_unittest.cc', - ], - 'include_dirs': [ - '../..', - ], - 'conditions': [ - ['OS!="ios"', { - 'sources' : [ '<@(_all_sources)' ], - }, { # OS=="ios" - 'sources' : [ '<@(_common_sources)' ], - # The ResourceBundle unittest expects a locale.pak file to exist in - # the bundle for English-US. Copy it in from where it was generated - # by ui_resources.gyp:ui_test_pak. - 'mac_bundle_resources': [ - '<(PRODUCT_DIR)/ui/en.lproj/locale.pak', - ], - 'actions': [ - { - 'action_name': 'copy_test_data', - 'variables': { - 'test_data_files': [ - 'test/data', - ], - 'test_data_prefix' : 'ui/base', - }, - 'includes': [ '../../build/copy_test_data_ios.gypi' ], - }, - ], - }], - ['OS == "win"', { - 'sources': [ - 'dragdrop/os_exchange_data_win_unittest.cc', - 'win/hwnd_subclass_unittest.cc', - 'win/open_file_name_win_unittest.cc', - ], - 'msvs_settings': { - 'VCLinkerTool': { - 'DelayLoadDLLs': [ - 'd2d1.dll', - 'd3d10_1.dll', - ], - 'AdditionalDependencies': [ - 'd2d1.lib', - 'd3d10_1.lib', - ], - }, - }, - 'link_settings': { - 'libraries': [ - '-limm32.lib', - '-loleacc.lib', - ], - }, - # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. - 'msvs_disabled_warnings': [ 4267, ], - }], - ['OS == "android"', { - 'dependencies': [ - '../../testing/android/native_test.gyp:native_test_native_code', - ], - 'sources!': [ - 'touch/touch_editing_controller_unittest.cc', - ], - }], - ['use_pango == 1', { - 'dependencies': [ - '../../build/linux/system.gyp:pangocairo', - ], - 'conditions': [ - ['use_allocator!="none"', { - 'dependencies': [ - '../../base/allocator/allocator.gyp:allocator', - ], - }], - ], - }], - ['use_x11==1', { - 'dependencies': [ - '../../build/linux/system.gyp:x11', - '../../tools/xdisplaycheck/xdisplaycheck.gyp:xdisplaycheck', - '../events/platform/x11/x11_events_platform.gyp:x11_events_platform', - '../gfx/x/gfx_x11.gyp:gfx_x11', - ], - }], - ['OS!="win" or use_aura==0', { - 'sources!': [ - 'view_prop_unittest.cc', - ], - }], - ['use_x11==1 and use_aura==1', { - 'sources': [ - 'cursor/cursor_loader_x11_unittest.cc', - ], - }], - ['OS=="mac"', { - 'dependencies': [ - '../../third_party/mozilla/mozilla.gyp:mozilla', - '../events/events.gyp:events_test_support', - 'ui_base_tests_bundle', - ], - 'conditions': [ - ['component=="static_library"', { - # Needed for mozilla.gyp. - 'xcode_settings': {'OTHER_LDFLAGS': ['-Wl,-ObjC']}, - }], - ], - }], - ['use_aura==1 or toolkit_views==1', { - 'sources': [ - 'dragdrop/os_exchange_data_unittest.cc', - ], - 'dependencies': [ - '../events/events.gyp:events', - '../events/events.gyp:events_base', - '../events/events.gyp:events_test_support', - '../events/platform/events_platform.gyp:events_platform', - ], - }], - ['chromeos==1', { - 'dependencies': [ - '../../chromeos/chromeos.gyp:chromeos', - ], - 'sources!': [ - 'dragdrop/os_exchange_data_provider_aurax11_unittest.cc', - 'x/selection_requestor_unittest.cc', - ], - }], - ['use_x11==0', { - 'sources!': [ - 'ime/chromeos/character_composer_unittest.cc', - 'ime/input_method_chromeos_unittest.cc', - 'ime/composition_text_util_pango_unittest.cc', - ], - }], - ], - 'target_conditions': [ - ['OS == "ios"', { - 'sources/': [ - # Pull in specific Mac files for iOS (which have been filtered out - # by file name rules). - ['include', '^l10n/l10n_util_mac_unittest\\.mm$'], - ], - }], - ], -}
diff --git a/ui/base/ui_base_tests_bundle.gypi b/ui/base/ui_base_tests_bundle.gypi index 8fb6307..2eeabe88 100644 --- a/ui/base/ui_base_tests_bundle.gypi +++ b/ui/base/ui_base_tests_bundle.gypi
@@ -2,7 +2,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -# This file contains resources for the ui_unittests test bundle. +# This file contains resources for the ui_base_unittests test bundle. # See chrome_dll_bundle.gypi for a description of the techniques here. { 'product_name': 'ui_unittests Framework',
diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc index bbf05bb..f6763229 100644 --- a/ui/compositor/compositor.cc +++ b/ui/compositor/compositor.cc
@@ -109,6 +109,7 @@ #endif #if defined(OS_WIN) settings.disable_hi_res_timer_tasks_on_battery = true; + settings.renderer_settings.finish_rendering_on_resize = true; #endif // These flags should be mirrored by renderer versions in content/renderer/. @@ -239,7 +240,7 @@ // TODO(nduca): Temporary while compositor calls // compositeImmediately() directly. cc::BeginFrameArgs args = cc::BeginFrameArgs::Create( - gfx::FrameTime::Now(), base::TimeTicks(), + BEGINFRAME_FROM_HERE, gfx::FrameTime::Now(), base::TimeTicks(), cc::BeginFrameArgs::DefaultInterval(), cc::BeginFrameArgs::SYNCHRONOUS); BeginMainFrame(args); host_->Composite(args.frame_time); @@ -256,8 +257,9 @@ host_->SetNeedsRedrawRect(damage_rect); } -void Compositor::FinishAllRendering() { +void Compositor::DisableSwapUntilResize() { host_->FinishAllRendering(); + context_factory_->ResizeDisplay(this, gfx::Size()); } void Compositor::SetLatencyInfo(const ui::LatencyInfo& latency_info) { @@ -272,6 +274,7 @@ size_ = size_in_pixel; host_->SetViewportSize(size_in_pixel); root_web_layer_->SetBounds(size_in_pixel); + context_factory_->ResizeDisplay(this, size_in_pixel); } if (device_scale_factor_ != scale) { device_scale_factor_ = scale;
diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h index e45f215..57e4a8e2 100644 --- a/ui/compositor/compositor.h +++ b/ui/compositor/compositor.h
@@ -105,6 +105,10 @@ // Creates a Surface ID allocator with a new namespace. virtual scoped_ptr<cc::SurfaceIdAllocator> CreateSurfaceIdAllocator() = 0; + + // Resize the display corresponding to this compositor to a particular size. + virtual void ResizeDisplay(ui::Compositor* compositor, + const gfx::Size& size) = 0; }; // This class represents a lock on the compositor, that can be used to prevent @@ -183,8 +187,9 @@ // from changes to layer properties. void ScheduleRedrawRect(const gfx::Rect& damage_rect); - // Finishes all outstanding rendering on the GPU. - void FinishAllRendering(); + // Finishes all outstanding rendering and disables swapping on this surface + // until it is resized. + void DisableSwapUntilResize(); void SetLatencyInfo(const LatencyInfo& latency_info);
diff --git a/ui/compositor/test/in_process_context_factory.cc b/ui/compositor/test/in_process_context_factory.cc index dc7b767..961f9b1 100644 --- a/ui/compositor/test/in_process_context_factory.cc +++ b/ui/compositor/test/in_process_context_factory.cc
@@ -165,4 +165,8 @@ new cc::SurfaceIdAllocator(next_surface_id_namespace_++)); } +void InProcessContextFactory::ResizeDisplay(ui::Compositor* compositor, + const gfx::Size& size) { +} + } // namespace ui
diff --git a/ui/compositor/test/in_process_context_factory.h b/ui/compositor/test/in_process_context_factory.h index 04ae86f0..6fd4eaa 100644 --- a/ui/compositor/test/in_process_context_factory.h +++ b/ui/compositor/test/in_process_context_factory.h
@@ -47,6 +47,8 @@ gpu::GpuMemoryBufferManager* GetGpuMemoryBufferManager() override; base::MessageLoopProxy* GetCompositorMessageLoop() override; scoped_ptr<cc::SurfaceIdAllocator> CreateSurfaceIdAllocator() override; + void ResizeDisplay(ui::Compositor* compositor, + const gfx::Size& size) override; private: scoped_ptr<base::Thread> compositor_thread_;
diff --git a/ui/events/gesture_detection/touch_disposition_gesture_filter_unittest.cc b/ui/events/gesture_detection/touch_disposition_gesture_filter_unittest.cc index eb77e648..1452caa 100644 --- a/ui/events/gesture_detection/touch_disposition_gesture_filter_unittest.cc +++ b/ui/events/gesture_detection/touch_disposition_gesture_filter_unittest.cc
@@ -42,7 +42,7 @@ show_press_bounding_box_ = event.details.bounding_box(); if (cancel_after_next_gesture_) { cancel_after_next_gesture_ = false; - CancelTouchPoint(); + SendPacket(CancelTouchPoint(), NoGestures()); SendTouchNotConsumedAck(); } } @@ -71,6 +71,8 @@ return ::testing::AssertionSuccess(); } + GestureList NoGestures() { return GestureList(0); } + GestureList Gestures(EventType type) { return GestureList(1, type); } @@ -104,14 +106,6 @@ return gestures; } - void SendTouchGestures() { - touch_event_.set_event_time(base::TimeTicks::Now()); - EXPECT_EQ(TouchDispositionGestureFilter::SUCCESS, - SendTouchGestures(touch_event_, pending_gesture_packet_)); - GestureEventDataPacket gesture_packet; - std::swap(gesture_packet, pending_gesture_packet_); - } - TouchDispositionGestureFilter::PacketResult SendTouchGestures(const MotionEvent& touch, const GestureEventDataPacket& packet) { @@ -141,41 +135,50 @@ void SendTouchNotConsumedAck() { SendTouchEventAck(false); } - void PushGesture(EventType type) { - pending_gesture_packet_.Push(CreateGesture(type)); - } - - void PushGesture(EventType type, float x, float y, float diameter) { - pending_gesture_packet_.Push(CreateGesture(type, x, y, diameter)); - } - - void PressTouchPoint(int x, int y) { + const MockMotionEvent& PressTouchPoint(float x, float y) { touch_event_.PressPoint(x, y); touch_event_.SetRawOffset(raw_offset_.x(), raw_offset_.y()); - SendTouchGestures(); + return touch_event_; } - void MoveTouchPoint(size_t index, int x, int y) { - touch_event_.MovePoint(index, x, y); - touch_event_.SetRawOffset(raw_offset_.x(), raw_offset_.y()); - SendTouchGestures(); + const MockMotionEvent& PressTouchPoint() { return PressTouchPoint(0, 0); } + + const MockMotionEvent& MoveTouchPoint() { + touch_event_.MovePoint(0, 0, 0); + touch_event_.set_event_time(base::TimeTicks::Now()); + return touch_event_; } - void ReleaseTouchPoint() { + const MockMotionEvent& ReleaseTouchPoint() { touch_event_.ReleasePoint(); - SendTouchGestures(); + touch_event_.set_event_time(base::TimeTicks::Now()); + return touch_event_; } - void CancelTouchPoint() { + const MockMotionEvent& CancelTouchPoint() { touch_event_.CancelPoint(); - SendTouchGestures(); + touch_event_.set_event_time(base::TimeTicks::Now()); + return touch_event_; + } + + void SendPacket(const MockMotionEvent& touch_event, + GestureList gesture_list) { + GestureEventDataPacket gesture_packet; + for (EventType type : gesture_list) + gesture_packet.Push(CreateGesture(type)); + + EXPECT_EQ(TouchDispositionGestureFilter::SUCCESS, + SendTouchGestures(touch_event, gesture_packet)); } void SetRawTouchOffset(const gfx::Vector2dF& raw_offset) { raw_offset_ = raw_offset; } - void ResetTouchPoints() { touch_event_ = MockMotionEvent(); } + const MockMotionEvent& ResetTouchPoints() { + touch_event_ = MockMotionEvent(); + return touch_event_; + } bool GesturesSent() const { return !sent_gestures_.empty(); } @@ -229,15 +232,8 @@ float y, float diameter) { return GestureEventData( - GestureEventDetails(type), - 0, - MotionEvent::TOOL_TYPE_FINGER, - base::TimeTicks(), - touch_event_.GetX(0), - touch_event_.GetY(0), - touch_event_.GetRawX(0), - touch_event_.GetRawY(0), - 1, + GestureEventDetails(type), 0, MotionEvent::TOOL_TYPE_FINGER, + base::TimeTicks(), x, y, 0, 0, 1, gfx::RectF(x - diameter / 2, y - diameter / 2, diameter, diameter), kDefaultEventFlags); } @@ -255,10 +251,10 @@ }; TEST_F(TouchDispositionGestureFilterTest, BasicNoGestures) { - PressTouchPoint(1, 1); + PressTouchPoint(); EXPECT_FALSE(GesturesSent()); - MoveTouchPoint(0, 2, 2); + MoveTouchPoint(); EXPECT_FALSE(GesturesSent()); // No gestures should be dispatched by the ack, as the queued packets @@ -274,99 +270,83 @@ } TEST_F(TouchDispositionGestureFilterTest, BasicGestures) { + GestureList press_gestures = + Gestures(ET_GESTURE_BEGIN, ET_GESTURE_SCROLL_BEGIN); // An unconsumed touch's gesture should be sent. - PushGesture(ET_GESTURE_BEGIN); - PushGesture(ET_GESTURE_SCROLL_BEGIN); - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), press_gestures); EXPECT_FALSE(GesturesSent()); SendTouchNotConsumedAck(); - EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_BEGIN, ET_GESTURE_SCROLL_BEGIN), - GetAndResetSentGestures())); + EXPECT_TRUE(GesturesMatch(press_gestures, GetAndResetSentGestures())); // Multiple gestures can be queued for a single event. - PushGesture(ET_SCROLL_FLING_START); - PushGesture(ET_SCROLL_FLING_CANCEL); - PushGesture(ET_GESTURE_END); - ReleaseTouchPoint(); + GestureList release_gestures = + Gestures(ET_SCROLL_FLING_START, ET_SCROLL_FLING_CANCEL, ET_GESTURE_END); + SendPacket(ReleaseTouchPoint(), release_gestures); EXPECT_FALSE(GesturesSent()); SendTouchNotConsumedAck(); - EXPECT_TRUE(GesturesMatch(Gestures(ET_SCROLL_FLING_START, - ET_SCROLL_FLING_CANCEL, - ET_GESTURE_END), - GetAndResetSentGestures())); + EXPECT_TRUE(GesturesMatch(release_gestures, GetAndResetSentGestures())); } TEST_F(TouchDispositionGestureFilterTest, BasicGesturesConsumed) { // A consumed touch's gesture should not be sent. - PushGesture(ET_GESTURE_BEGIN); - PushGesture(ET_GESTURE_SCROLL_BEGIN); - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), + Gestures(ET_GESTURE_BEGIN, ET_GESTURE_SCROLL_BEGIN)); SendTouchConsumedAck(); EXPECT_FALSE(GesturesSent()); - PushGesture(ET_GESTURE_SCROLL_UPDATE); - MoveTouchPoint(0, 2, 2); + SendPacket(MoveTouchPoint(), Gestures(ET_GESTURE_SCROLL_UPDATE)); SendTouchConsumedAck(); EXPECT_FALSE(GesturesSent()); - PushGesture(ET_SCROLL_FLING_START); - PushGesture(ET_SCROLL_FLING_CANCEL); - PushGesture(ET_GESTURE_END); - ReleaseTouchPoint(); + SendPacket( + ReleaseTouchPoint(), + Gestures(ET_SCROLL_FLING_START, ET_SCROLL_FLING_CANCEL, ET_GESTURE_END)); SendTouchConsumedAck(); EXPECT_FALSE(GesturesSent()); } TEST_F(TouchDispositionGestureFilterTest, ConsumedThenNotConsumed) { // A consumed touch's gesture should not be sent. - PushGesture(ET_GESTURE_SCROLL_BEGIN); - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), Gestures(ET_GESTURE_SCROLL_BEGIN)); SendTouchConsumedAck(); EXPECT_FALSE(GesturesSent()); // Even if the subsequent touch is not consumed, continue dropping gestures. - PushGesture(ET_GESTURE_SCROLL_UPDATE); - MoveTouchPoint(0, 2, 2); + SendPacket(MoveTouchPoint(), Gestures(ET_GESTURE_SCROLL_UPDATE)); SendTouchNotConsumedAck(); EXPECT_FALSE(GesturesSent()); // Even if the subsequent touch had no consumer, continue dropping gestures. - PushGesture(ET_SCROLL_FLING_START); - ReleaseTouchPoint(); + SendPacket(ReleaseTouchPoint(), Gestures(ET_SCROLL_FLING_START)); SendTouchNotConsumedAck(); EXPECT_FALSE(GesturesSent()); } TEST_F(TouchDispositionGestureFilterTest, NotConsumedThenConsumed) { // A not consumed touch's gesture should be sent. - PushGesture(ET_GESTURE_SCROLL_BEGIN); - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), Gestures(ET_GESTURE_SCROLL_BEGIN)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_BEGIN), GetAndResetSentGestures())); // A newly consumed gesture should not be sent. - PushGesture(ET_GESTURE_PINCH_BEGIN); - PressTouchPoint(10, 10); + SendPacket(PressTouchPoint(), Gestures(ET_GESTURE_PINCH_BEGIN)); SendTouchConsumedAck(); EXPECT_FALSE(GesturesSent()); // And subsequent non-consumed pinch updates should not be sent. - PushGesture(ET_GESTURE_SCROLL_UPDATE); - PushGesture(ET_GESTURE_PINCH_UPDATE); - MoveTouchPoint(0, 2, 2); + SendPacket(MoveTouchPoint(), + Gestures(ET_GESTURE_SCROLL_UPDATE, ET_GESTURE_PINCH_UPDATE)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_UPDATE), GetAndResetSentGestures())); // End events dispatched only when their start events were. - PushGesture(ET_GESTURE_PINCH_END); - ReleaseTouchPoint(); + SendPacket(ReleaseTouchPoint(), Gestures(ET_GESTURE_PINCH_END)); SendTouchNotConsumedAck(); EXPECT_FALSE(GesturesSent()); - PushGesture(ET_GESTURE_SCROLL_END); - ReleaseTouchPoint(); + SendPacket(ReleaseTouchPoint(), Gestures(ET_GESTURE_SCROLL_END)); SendTouchConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_END), GetAndResetSentGestures())); @@ -374,27 +354,23 @@ TEST_F(TouchDispositionGestureFilterTest, ScrollAlternatelyConsumed) { // A consumed touch's gesture should not be sent. - PushGesture(ET_GESTURE_SCROLL_BEGIN); - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), Gestures(ET_GESTURE_SCROLL_BEGIN)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_BEGIN), GetAndResetSentGestures())); for (size_t i = 0; i < 3; ++i) { - PushGesture(ET_GESTURE_SCROLL_UPDATE); - MoveTouchPoint(0, 2, 2); + SendPacket(MoveTouchPoint(), Gestures(ET_GESTURE_SCROLL_UPDATE)); SendTouchConsumedAck(); EXPECT_FALSE(GesturesSent()); - PushGesture(ET_GESTURE_SCROLL_UPDATE); - MoveTouchPoint(0, 3, 3); + SendPacket(MoveTouchPoint(), Gestures(ET_GESTURE_SCROLL_UPDATE)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_UPDATE), GetAndResetSentGestures())); } - PushGesture(ET_GESTURE_SCROLL_END); - ReleaseTouchPoint(); + SendPacket(ReleaseTouchPoint(), Gestures(ET_GESTURE_SCROLL_END)); SendTouchConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_END), GetAndResetSentGestures())); @@ -402,73 +378,63 @@ TEST_F(TouchDispositionGestureFilterTest, NotConsumedThenNoConsumer) { // An unconsumed touch's gesture should be sent. - PushGesture(ET_GESTURE_SCROLL_BEGIN); - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), Gestures(ET_GESTURE_SCROLL_BEGIN)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_BEGIN), GetAndResetSentGestures())); // If the subsequent touch has no consumer (e.g., a secondary pointer is // pressed but not on a touch handling rect), send the gesture. - PushGesture(ET_GESTURE_PINCH_BEGIN); - PressTouchPoint(2, 2); + SendPacket(PressTouchPoint(), Gestures(ET_GESTURE_PINCH_BEGIN)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_PINCH_BEGIN), GetAndResetSentGestures())); // End events should be dispatched when their start events were, independent // of the ack state. - PushGesture(ET_GESTURE_PINCH_END); - ReleaseTouchPoint(); + SendPacket(ReleaseTouchPoint(), Gestures(ET_GESTURE_PINCH_END)); SendTouchConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_PINCH_END), GetAndResetSentGestures())); - PushGesture(ET_GESTURE_SCROLL_END); - ReleaseTouchPoint(); + SendPacket(ReleaseTouchPoint(), Gestures(ET_GESTURE_SCROLL_END)); SendTouchConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_END), GetAndResetSentGestures())); } TEST_F(TouchDispositionGestureFilterTest, EndingEventsSent) { - PushGesture(ET_GESTURE_SCROLL_BEGIN); - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), Gestures(ET_GESTURE_SCROLL_BEGIN)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_BEGIN), GetAndResetSentGestures())); - PushGesture(ET_GESTURE_PINCH_BEGIN); - PressTouchPoint(2, 2); + SendPacket(PressTouchPoint(), Gestures(ET_GESTURE_PINCH_BEGIN)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_PINCH_BEGIN), GetAndResetSentGestures())); // Consuming the touchend event can't suppress the match end gesture. - PushGesture(ET_GESTURE_PINCH_END); - ReleaseTouchPoint(); + SendPacket(ReleaseTouchPoint(), Gestures(ET_GESTURE_PINCH_END)); SendTouchConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_PINCH_END), GetAndResetSentGestures())); // But other events in the same packet are still suppressed. - PushGesture(ET_GESTURE_SCROLL_UPDATE); - PushGesture(ET_GESTURE_SCROLL_END); - ReleaseTouchPoint(); + SendPacket(ReleaseTouchPoint(), + Gestures(ET_GESTURE_SCROLL_UPDATE, ET_GESTURE_SCROLL_END)); SendTouchConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_END), GetAndResetSentGestures())); // ET_GESTURE_SCROLL_END and ET_SCROLL_FLING_START behave the same in this // regard. - PushGesture(ET_GESTURE_SCROLL_BEGIN); - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), Gestures(ET_GESTURE_SCROLL_BEGIN)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_BEGIN), GetAndResetSentGestures())); - PushGesture(ET_SCROLL_FLING_START); - ReleaseTouchPoint(); + SendPacket(ReleaseTouchPoint(), Gestures(ET_SCROLL_FLING_START)); SendTouchConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_SCROLL_FLING_START), GetAndResetSentGestures())); @@ -476,121 +442,99 @@ TEST_F(TouchDispositionGestureFilterTest, EndingEventsNotSent) { // Consuming a begin event ensures no end events are sent. - PushGesture(ET_GESTURE_SCROLL_BEGIN); - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), Gestures(ET_GESTURE_SCROLL_BEGIN)); SendTouchConsumedAck(); EXPECT_FALSE(GesturesSent()); - PushGesture(ET_GESTURE_PINCH_BEGIN); - PressTouchPoint(2, 2); + SendPacket(PressTouchPoint(), Gestures(ET_GESTURE_PINCH_BEGIN)); SendTouchNotConsumedAck(); EXPECT_FALSE(GesturesSent()); - PushGesture(ET_GESTURE_PINCH_END); - ReleaseTouchPoint(); + SendPacket(ReleaseTouchPoint(), Gestures(ET_GESTURE_PINCH_END)); SendTouchNotConsumedAck(); EXPECT_FALSE(GesturesSent()); - PushGesture(ET_GESTURE_SCROLL_END); - ReleaseTouchPoint(); + SendPacket(ReleaseTouchPoint(), Gestures(ET_GESTURE_SCROLL_END)); SendTouchNotConsumedAck(); EXPECT_FALSE(GesturesSent()); } TEST_F(TouchDispositionGestureFilterTest, UpdateEventsSuppressedPerEvent) { - PushGesture(ET_GESTURE_SCROLL_BEGIN); - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), Gestures(ET_GESTURE_SCROLL_BEGIN)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_BEGIN), GetAndResetSentGestures())); // Consuming a single scroll or pinch update should suppress only that event. - PushGesture(ET_GESTURE_SCROLL_UPDATE); - MoveTouchPoint(0, 2, 2); + SendPacket(MoveTouchPoint(), Gestures(ET_GESTURE_SCROLL_UPDATE)); SendTouchConsumedAck(); EXPECT_FALSE(GesturesSent()); - PushGesture(ET_GESTURE_PINCH_BEGIN); - PressTouchPoint(2, 2); + SendPacket(PressTouchPoint(), Gestures(ET_GESTURE_PINCH_BEGIN)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_PINCH_BEGIN), GetAndResetSentGestures())); - PushGesture(ET_GESTURE_PINCH_UPDATE); - MoveTouchPoint(1, 2, 3); + SendPacket(MoveTouchPoint(), Gestures(ET_GESTURE_PINCH_UPDATE)); SendTouchConsumedAck(); EXPECT_FALSE(GesturesSent()); // Subsequent updates should not be affected. - PushGesture(ET_GESTURE_SCROLL_UPDATE); - MoveTouchPoint(0, 4, 4); + SendPacket(MoveTouchPoint(), Gestures(ET_GESTURE_SCROLL_UPDATE)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_UPDATE), GetAndResetSentGestures())); - PushGesture(ET_GESTURE_PINCH_UPDATE); - MoveTouchPoint(0, 4, 5); + SendPacket(MoveTouchPoint(), Gestures(ET_GESTURE_PINCH_UPDATE)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_PINCH_UPDATE), GetAndResetSentGestures())); - PushGesture(ET_GESTURE_PINCH_END); - ReleaseTouchPoint(); + SendPacket(ReleaseTouchPoint(), Gestures(ET_GESTURE_PINCH_END)); SendTouchConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_PINCH_END), GetAndResetSentGestures())); - PushGesture(ET_GESTURE_SCROLL_END); - ReleaseTouchPoint(); + SendPacket(ReleaseTouchPoint(), Gestures(ET_GESTURE_SCROLL_END)); SendTouchConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_END), GetAndResetSentGestures())); } TEST_F(TouchDispositionGestureFilterTest, UpdateEventsDependOnBeginEvents) { - PushGesture(ET_GESTURE_SCROLL_BEGIN); - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), Gestures(ET_GESTURE_SCROLL_BEGIN)); SendTouchConsumedAck(); EXPECT_FALSE(GesturesSent()); // Scroll and pinch gestures depend on the scroll begin gesture being // dispatched. - PushGesture(ET_GESTURE_SCROLL_UPDATE); - MoveTouchPoint(0, 2, 2); + SendPacket(MoveTouchPoint(), Gestures(ET_GESTURE_SCROLL_UPDATE)); SendTouchNotConsumedAck(); EXPECT_FALSE(GesturesSent()); - PushGesture(ET_GESTURE_PINCH_BEGIN); - PressTouchPoint(2, 2); + SendPacket(PressTouchPoint(), Gestures(ET_GESTURE_PINCH_BEGIN)); SendTouchNotConsumedAck(); EXPECT_FALSE(GesturesSent()); - PushGesture(ET_GESTURE_PINCH_UPDATE); - MoveTouchPoint(1, 2, 3); + SendPacket(MoveTouchPoint(), Gestures(ET_GESTURE_PINCH_UPDATE)); SendTouchConsumedAck(); EXPECT_FALSE(GesturesSent()); - PushGesture(ET_GESTURE_PINCH_END); - ReleaseTouchPoint(); + SendPacket(ReleaseTouchPoint(), Gestures(ET_GESTURE_PINCH_END)); SendTouchNotConsumedAck(); EXPECT_FALSE(GesturesSent()); - PushGesture(ET_GESTURE_SCROLL_END); - ReleaseTouchPoint(); + SendPacket(ReleaseTouchPoint(), Gestures(ET_GESTURE_SCROLL_END)); SendTouchNotConsumedAck(); EXPECT_FALSE(GesturesSent()); } TEST_F(TouchDispositionGestureFilterTest, MultipleTouchSequences) { // Queue two touch-to-gestures sequences. - PushGesture(ET_GESTURE_TAP_DOWN); - PressTouchPoint(1, 1); - PushGesture(ET_GESTURE_TAP); - ReleaseTouchPoint(); - PushGesture(ET_GESTURE_SCROLL_BEGIN); - PressTouchPoint(1, 1); - PushGesture(ET_GESTURE_SCROLL_END); - ReleaseTouchPoint(); + SendPacket(PressTouchPoint(), Gestures(ET_GESTURE_TAP_DOWN)); + SendPacket(ReleaseTouchPoint(), Gestures(ET_GESTURE_TAP)); + SendPacket(PressTouchPoint(), Gestures(ET_GESTURE_SCROLL_BEGIN)); + SendPacket(ReleaseTouchPoint(), Gestures(ET_GESTURE_SCROLL_END)); // The first gesture sequence should not be allowed. SendTouchConsumedAck(); @@ -610,56 +554,53 @@ SetRawTouchOffset(raw_offset); // Simulate a fling. - PushGesture(ET_GESTURE_TAP_DOWN); - PushGesture(ET_GESTURE_SCROLL_BEGIN); - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), + Gestures(ET_GESTURE_TAP_DOWN, ET_GESTURE_SCROLL_BEGIN)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch( Gestures( ET_GESTURE_TAP_DOWN, ET_GESTURE_TAP_CANCEL, ET_GESTURE_SCROLL_BEGIN), GetAndResetSentGestures())); - PushGesture(ET_SCROLL_FLING_START); - ReleaseTouchPoint(); + SendPacket(ReleaseTouchPoint(), Gestures(ET_SCROLL_FLING_START)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_SCROLL_FLING_START), GetAndResetSentGestures())); // A new touch sequence should cancel the outstanding fling. - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(1, 1), NoGestures()); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_SCROLL_FLING_CANCEL), GetAndResetSentGestures())); EXPECT_EQ(CurrentTouchTime(), LastSentGestureTime()); EXPECT_EQ(LastSentGestureLocation(), gfx::PointF(1, 1)); EXPECT_EQ(LastSentGestureRawLocation(), gfx::PointF(1, 1) + raw_offset); - ReleaseTouchPoint(); + SendPacket(ReleaseTouchPoint(), NoGestures()); SendTouchNotConsumedAck(); EXPECT_FALSE(GesturesSent()); } TEST_F(TouchDispositionGestureFilterTest, ScrollEndedOnTouchReleaseIfNoFling) { // Simulate a scroll. - PushGesture(ET_GESTURE_TAP_DOWN); - PushGesture(ET_GESTURE_SCROLL_BEGIN); - PressTouchPoint(1, 1); + // Touch position will be used for synthesized scroll end gesture. + SendPacket(PressTouchPoint(2, 3), + Gestures(ET_GESTURE_TAP_DOWN, ET_GESTURE_SCROLL_BEGIN)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch( Gestures( ET_GESTURE_TAP_DOWN, ET_GESTURE_TAP_CANCEL, ET_GESTURE_SCROLL_BEGIN), GetAndResetSentGestures())); - ReleaseTouchPoint(); + SendPacket(ReleaseTouchPoint(), NoGestures()); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_END), GetAndResetSentGestures())); EXPECT_EQ(CurrentTouchTime(), LastSentGestureTime()); - EXPECT_EQ(LastSentGestureLocation(), gfx::PointF(1, 1)); + EXPECT_EQ(LastSentGestureLocation(), gfx::PointF(2, 3)); } TEST_F(TouchDispositionGestureFilterTest, ScrollEndedOnNewTouchSequence) { // Simulate a scroll. - PushGesture(ET_GESTURE_TAP_DOWN); - PushGesture(ET_GESTURE_SCROLL_BEGIN); - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), + Gestures(ET_GESTURE_TAP_DOWN, ET_GESTURE_SCROLL_BEGIN)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch( Gestures( @@ -668,7 +609,9 @@ // A new touch sequence should end the outstanding scroll. ResetTouchPoints(); - PressTouchPoint(2, 3); + + // Touch position will be used for synthesized scroll end gesture. + SendPacket(PressTouchPoint(2, 3), NoGestures()); SendTouchConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_END), GetAndResetSentGestures())); @@ -678,10 +621,9 @@ TEST_F(TouchDispositionGestureFilterTest, FlingCancelledOnScrollBegin) { // Simulate a fling sequence. - PushGesture(ET_GESTURE_TAP_DOWN); - PushGesture(ET_GESTURE_SCROLL_BEGIN); - PushGesture(ET_SCROLL_FLING_START); - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), + Gestures(ET_GESTURE_TAP_DOWN, ET_GESTURE_SCROLL_BEGIN, + ET_SCROLL_FLING_START)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_DOWN, ET_GESTURE_TAP_CANCEL, @@ -690,9 +632,8 @@ GetAndResetSentGestures())); // The new fling should cancel the preceding one. - PushGesture(ET_GESTURE_SCROLL_BEGIN); - PushGesture(ET_SCROLL_FLING_START); - ReleaseTouchPoint(); + SendPacket(ReleaseTouchPoint(), + Gestures(ET_GESTURE_SCROLL_BEGIN, ET_SCROLL_FLING_START)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_SCROLL_FLING_CANCEL, ET_GESTURE_SCROLL_BEGIN, @@ -702,14 +643,13 @@ TEST_F(TouchDispositionGestureFilterTest, FlingNotCancelledIfGFCEventReceived) { // Simulate a fling that is started then cancelled. - PushGesture(ET_GESTURE_SCROLL_BEGIN); - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), Gestures(ET_GESTURE_SCROLL_BEGIN)); SendTouchNotConsumedAck(); - PushGesture(ET_SCROLL_FLING_START); - MoveTouchPoint(0, 2, 3); + SendPacket(MoveTouchPoint(), Gestures(ET_SCROLL_FLING_START)); SendTouchNotConsumedAck(); - PushGesture(ET_SCROLL_FLING_CANCEL); - ReleaseTouchPoint(); + GestureEventDataPacket packet; + packet.Push(CreateGesture(ET_SCROLL_FLING_CANCEL, 2, 3, 0)); + SendTouchGestures(ReleaseTouchPoint(), packet); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_BEGIN, ET_SCROLL_FLING_START, @@ -719,23 +659,21 @@ // A new touch sequence will not inject a ET_SCROLL_FLING_CANCEL, as the fling // has already been cancelled. - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), NoGestures()); SendTouchNotConsumedAck(); - ReleaseTouchPoint(); + SendPacket(ReleaseTouchPoint(), NoGestures()); SendTouchNotConsumedAck(); EXPECT_FALSE(GesturesSent()); } TEST_F(TouchDispositionGestureFilterTest, TapCancelledWhenScrollBegins) { - PushGesture(ET_GESTURE_TAP_DOWN); - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), Gestures(ET_GESTURE_TAP_DOWN)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_DOWN), GetAndResetSentGestures())); // If the subsequent touch turns into a scroll, the tap should be cancelled. - PushGesture(ET_GESTURE_SCROLL_BEGIN); - MoveTouchPoint(0, 2, 2); + SendPacket(MoveTouchPoint(), Gestures(ET_GESTURE_SCROLL_BEGIN)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_CANCEL, ET_GESTURE_SCROLL_BEGIN), @@ -743,38 +681,37 @@ } TEST_F(TouchDispositionGestureFilterTest, TapCancelledWhenTouchConsumed) { - PushGesture(ET_GESTURE_TAP_DOWN); - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), Gestures(ET_GESTURE_TAP_DOWN)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_DOWN), GetAndResetSentGestures())); // If the subsequent touch is consumed, the tap should be cancelled. - PushGesture(ET_GESTURE_SCROLL_BEGIN); - MoveTouchPoint(0, 2, 2); + GestureEventDataPacket packet; + packet.Push(CreateGesture(ET_GESTURE_SCROLL_BEGIN, 2, 3, 0)); + SendTouchGestures(MoveTouchPoint(), packet); + SendTouchConsumedAck(); EXPECT_TRUE( GesturesMatch(Gestures(ET_GESTURE_TAP_CANCEL, ET_GESTURE_SCROLL_BEGIN), GetAndResetSentGestures())); - EXPECT_EQ(LastSentGestureLocation(), gfx::PointF(1, 1)); + EXPECT_EQ(LastSentGestureLocation(), gfx::PointF(2, 3)); } TEST_F(TouchDispositionGestureFilterTest, TapNotCancelledIfTapEndingEventReceived) { - PushGesture(ET_GESTURE_TAP_DOWN); - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), Gestures(ET_GESTURE_TAP_DOWN)); SendTouchNotConsumedAck(); EXPECT_TRUE( GesturesMatch(Gestures(ET_GESTURE_TAP_DOWN), GetAndResetSentGestures())); - PushGesture(ET_GESTURE_TAP); - ReleaseTouchPoint(); + SendPacket(ReleaseTouchPoint(), Gestures(ET_GESTURE_TAP)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SHOW_PRESS, ET_GESTURE_TAP), GetAndResetSentGestures())); // The tap should not be cancelled as it was terminated by a |ET_GESTURE_TAP|. - PressTouchPoint(2, 2); + SendPacket(PressTouchPoint(), NoGestures()); SendTouchConsumedAck(); EXPECT_FALSE(GesturesSent()); } @@ -782,8 +719,7 @@ TEST_F(TouchDispositionGestureFilterTest, TimeoutGestures) { // If the sequence is allowed, and there are no preceding gestures, the // timeout gestures should be forwarded immediately. - PushGesture(ET_GESTURE_TAP_DOWN); - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), Gestures(ET_GESTURE_TAP_DOWN)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_DOWN), GetAndResetSentGestures())); @@ -796,8 +732,7 @@ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_LONG_PRESS), GetAndResetSentGestures())); - PushGesture(ET_GESTURE_LONG_TAP); - ReleaseTouchPoint(); + SendPacket(ReleaseTouchPoint(), Gestures(ET_GESTURE_LONG_TAP)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_CANCEL, ET_GESTURE_LONG_TAP), @@ -805,20 +740,18 @@ // If the sequence is disallowed, and there are no preceding gestures, the // timeout gestures should be dropped immediately. - PushGesture(ET_GESTURE_TAP_DOWN); - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), Gestures(ET_GESTURE_TAP_DOWN)); SendTouchConsumedAck(); EXPECT_FALSE(GesturesSent()); SendTimeoutGesture(ET_GESTURE_SHOW_PRESS); EXPECT_FALSE(GesturesSent()); - ReleaseTouchPoint(); + SendPacket(ReleaseTouchPoint(), NoGestures()); SendTouchNotConsumedAck(); // If the sequence has a pending ack, the timeout gestures should // remain queued until the ack is received. - PushGesture(ET_GESTURE_TAP_DOWN); - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), Gestures(ET_GESTURE_TAP_DOWN)); EXPECT_FALSE(GesturesSent()); SendTimeoutGesture(ET_GESTURE_LONG_PRESS); @@ -836,10 +769,8 @@ SendTouchConsumedAck(); EXPECT_FALSE(GesturesSent()); - PushGesture(ET_GESTURE_SCROLL_BEGIN); - PressTouchPoint(1, 1); - PushGesture(ET_GESTURE_SCROLL_UPDATE); - MoveTouchPoint(0, 3,3); + SendPacket(PressTouchPoint(), Gestures(ET_GESTURE_SCROLL_BEGIN)); + SendPacket(MoveTouchPoint(), Gestures(ET_GESTURE_SCROLL_UPDATE)); SendTouchNotConsumedAck(); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_BEGIN, @@ -869,16 +800,14 @@ TEST_F(TouchDispositionGestureFilterTest, ConsumedTouchCancel) { // An unconsumed touch's gesture should be sent. - PushGesture(ET_GESTURE_TAP_DOWN); - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), Gestures(ET_GESTURE_TAP_DOWN)); EXPECT_FALSE(GesturesSent()); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_DOWN), GetAndResetSentGestures())); - PushGesture(ET_GESTURE_TAP_CANCEL); - PushGesture(ET_GESTURE_SCROLL_END); - CancelTouchPoint(); + SendPacket(CancelTouchPoint(), + Gestures(ET_GESTURE_TAP_CANCEL, ET_GESTURE_SCROLL_END)); EXPECT_FALSE(GesturesSent()); SendTouchConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_CANCEL, @@ -887,12 +816,11 @@ } TEST_F(TouchDispositionGestureFilterTest, TimeoutEventAfterRelease) { - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), NoGestures()); SendTouchNotConsumedAck(); EXPECT_FALSE(GesturesSent()); - PushGesture(ET_GESTURE_TAP_DOWN); - PushGesture(ET_GESTURE_TAP_UNCONFIRMED); - ReleaseTouchPoint(); + SendPacket(ReleaseTouchPoint(), + Gestures(ET_GESTURE_TAP_DOWN, ET_GESTURE_TAP_UNCONFIRMED)); SendTouchNotConsumedAck(); EXPECT_TRUE( GesturesMatch(Gestures(ET_GESTURE_TAP_DOWN, ET_GESTURE_TAP_UNCONFIRMED), @@ -904,8 +832,7 @@ } TEST_F(TouchDispositionGestureFilterTest, ShowPressInsertedBeforeTap) { - PushGesture(ET_GESTURE_TAP_DOWN); - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), Gestures(ET_GESTURE_TAP_DOWN)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_DOWN), GetAndResetSentGestures())); @@ -914,8 +841,7 @@ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_UNCONFIRMED), GetAndResetSentGestures())); - PushGesture(ET_GESTURE_TAP); - ReleaseTouchPoint(); + SendPacket(ReleaseTouchPoint(), Gestures(ET_GESTURE_TAP)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SHOW_PRESS, ET_GESTURE_TAP), @@ -923,8 +849,7 @@ } TEST_F(TouchDispositionGestureFilterTest, ShowPressNotInsertedIfAlreadySent) { - PushGesture(ET_GESTURE_TAP_DOWN); - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), Gestures(ET_GESTURE_TAP_DOWN)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_DOWN), GetAndResetSentGestures())); @@ -933,8 +858,7 @@ EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SHOW_PRESS), GetAndResetSentGestures())); - PushGesture(ET_GESTURE_TAP); - ReleaseTouchPoint(); + SendPacket(ReleaseTouchPoint(), Gestures(ET_GESTURE_TAP)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP), GetAndResetSentGestures())); @@ -944,14 +868,13 @@ const gfx::Vector2dF raw_offset(1.3f, 3.7f); SetRawTouchOffset(raw_offset); - PushGesture(ET_GESTURE_TAP_DOWN); - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(1, 1), Gestures(ET_GESTURE_TAP_DOWN)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_DOWN), GetAndResetSentGestures())); // A cancellation motion event should cancel the tap. - CancelTouchPoint(); + SendPacket(CancelTouchPoint(), NoGestures()); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_CANCEL), GetAndResetSentGestures())); @@ -959,15 +882,14 @@ EXPECT_EQ(LastSentGestureLocation(), gfx::PointF(1, 1)); EXPECT_EQ(LastSentGestureRawLocation(), gfx::PointF(1, 1) + raw_offset); - PushGesture(ET_GESTURE_SCROLL_BEGIN); - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(1, 1), Gestures(ET_GESTURE_SCROLL_BEGIN)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_BEGIN), GetAndResetSentGestures())); // A cancellation motion event should end the scroll, even if the touch was // consumed. - CancelTouchPoint(); + SendPacket(CancelTouchPoint(), NoGestures()); SendTouchConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_END), GetAndResetSentGestures())); @@ -979,59 +901,58 @@ TEST_F(TouchDispositionGestureFilterTest, ConsumedScrollUpdateMakesFlingScrollEnd) { // A consumed touch's gesture should not be sent. - PushGesture(ET_GESTURE_BEGIN); - PushGesture(ET_GESTURE_SCROLL_BEGIN); - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), + Gestures(ET_GESTURE_BEGIN, ET_GESTURE_SCROLL_BEGIN)); SendTouchNotConsumedAck(); EXPECT_TRUE( GesturesMatch(Gestures(ET_GESTURE_BEGIN, ET_GESTURE_SCROLL_BEGIN), GetAndResetSentGestures())); - PushGesture(ET_GESTURE_SCROLL_UPDATE); - MoveTouchPoint(0, 2, 2); + SendPacket(MoveTouchPoint(), Gestures(ET_GESTURE_SCROLL_UPDATE)); SendTouchConsumedAck(); EXPECT_FALSE(GesturesSent()); - PushGesture(ET_SCROLL_FLING_START); - PushGesture(ET_SCROLL_FLING_CANCEL); - PushGesture(ET_GESTURE_END); - ReleaseTouchPoint(); + GestureEventDataPacket packet; + packet.Push(CreateGesture(ET_SCROLL_FLING_START)); + packet.Push(CreateGesture(ET_SCROLL_FLING_CANCEL)); + packet.Push(CreateGesture(ET_GESTURE_END, 2, 3, 0)); + SendTouchGestures(ReleaseTouchPoint(), packet); + SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_END, ET_GESTURE_END), GetAndResetSentGestures())); - EXPECT_EQ(LastSentGestureLocation(), gfx::PointF(2, 2)); + EXPECT_EQ(LastSentGestureLocation(), gfx::PointF(2, 3)); - PushGesture(ET_GESTURE_BEGIN); - PushGesture(ET_GESTURE_SCROLL_BEGIN); - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), + Gestures(ET_GESTURE_BEGIN, ET_GESTURE_SCROLL_BEGIN)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_BEGIN, ET_GESTURE_SCROLL_BEGIN), GetAndResetSentGestures())); } TEST_F(TouchDispositionGestureFilterTest, TapCancelledOnTouchCancel) { - PushGesture(ET_GESTURE_TAP_DOWN); - PressTouchPoint(1, 1); + // Touch position is used for synthesized tap cancel. + SendPacket(PressTouchPoint(2, 3), Gestures(ET_GESTURE_TAP_DOWN)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_DOWN), GetAndResetSentGestures())); // A cancellation motion event should cancel the tap. - CancelTouchPoint(); + SendPacket(CancelTouchPoint(), NoGestures()); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_CANCEL), GetAndResetSentGestures())); EXPECT_EQ(CurrentTouchTime(), LastSentGestureTime()); - EXPECT_EQ(LastSentGestureLocation(), gfx::PointF(1, 1)); + EXPECT_EQ(LastSentGestureLocation(), gfx::PointF(2, 3)); } // Test that a GestureEvent whose dispatch causes a cancel event to be fired // won't cause a crash. TEST_F(TouchDispositionGestureFilterTest, TestCancelMidGesture) { SetCancelAfterNextGesture(true); - PushGesture(ET_GESTURE_TAP_DOWN); - PressTouchPoint(1, 1); + // Synthesized tap cancel uses touch position. + SendPacket(PressTouchPoint(1, 1), Gestures(ET_GESTURE_TAP_DOWN)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_DOWN, ET_GESTURE_TAP_CANCEL), @@ -1041,20 +962,17 @@ // Test that a MultiFingerSwipe event is dispatched when appropriate. TEST_F(TouchDispositionGestureFilterTest, TestAllowedMultiFingerSwipe) { - PushGesture(ET_GESTURE_SCROLL_BEGIN); - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), Gestures(ET_GESTURE_SCROLL_BEGIN)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_BEGIN), GetAndResetSentGestures())); - PushGesture(ET_GESTURE_PINCH_BEGIN); - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), Gestures(ET_GESTURE_PINCH_BEGIN)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_PINCH_BEGIN), GetAndResetSentGestures())); - PushGesture(ET_GESTURE_SWIPE); - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), Gestures(ET_GESTURE_SWIPE)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SWIPE), GetAndResetSentGestures())); @@ -1062,49 +980,49 @@ // Test that a MultiFingerSwipe event is dispatched when appropriate. TEST_F(TouchDispositionGestureFilterTest, TestDisallowedMultiFingerSwipe) { - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), NoGestures()); SendTouchNotConsumedAck(); - PushGesture(ET_GESTURE_SCROLL_BEGIN); - MoveTouchPoint(0, 0, 0); + SendPacket(MoveTouchPoint(), Gestures(ET_GESTURE_SCROLL_BEGIN)); SendTouchConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SCROLL_BEGIN), GetAndResetSentGestures())); - PushGesture(ET_GESTURE_PINCH_BEGIN); - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), Gestures(ET_GESTURE_PINCH_BEGIN)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_PINCH_BEGIN), GetAndResetSentGestures())); - PushGesture(ET_GESTURE_SWIPE); - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), Gestures(ET_GESTURE_SWIPE)); SendTouchConsumedAck(); EXPECT_FALSE(GesturesSent()); } TEST_F(TouchDispositionGestureFilterTest, TapCancelOnSecondFingerDown) { - PushGesture(ET_GESTURE_TAP_DOWN); - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), Gestures(ET_GESTURE_TAP_DOWN)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_DOWN), GetAndResetSentGestures())); - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), NoGestures()); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_CANCEL), GetAndResetSentGestures())); } TEST_F(TouchDispositionGestureFilterTest, ShowPressBoundingBox) { - PushGesture(ET_GESTURE_TAP_DOWN, 9, 9, 8); - PressTouchPoint(9, 9); + GestureEventDataPacket press_packet; + press_packet.Push(CreateGesture(ET_GESTURE_TAP_DOWN, 9, 9, 8)); + SendTouchGestures(PressTouchPoint(), press_packet); + SendTouchNotConsumedAck(); EXPECT_TRUE( GesturesMatch(Gestures(ET_GESTURE_TAP_DOWN), GetAndResetSentGestures())); - PushGesture(ET_GESTURE_TAP, 10, 10, 10); - ReleaseTouchPoint(); + GestureEventDataPacket release_packet; + release_packet.Push(CreateGesture(ET_GESTURE_TAP, 10, 10, 10)); + SendTouchGestures(ReleaseTouchPoint(), release_packet); + SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_SHOW_PRESS, ET_GESTURE_TAP), GetAndResetSentGestures())); @@ -1112,9 +1030,8 @@ } TEST_F(TouchDispositionGestureFilterTest, TapCancelledBeforeGestureEnd) { - PushGesture(ET_GESTURE_BEGIN); - PushGesture(ET_GESTURE_TAP_DOWN); - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), + Gestures(ET_GESTURE_BEGIN, ET_GESTURE_TAP_DOWN)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_BEGIN, ET_GESTURE_TAP_DOWN), GetAndResetSentGestures())); @@ -1125,8 +1042,7 @@ SendTimeoutGesture(ET_GESTURE_LONG_PRESS); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_LONG_PRESS), GetAndResetSentGestures())); - PushGesture(ET_GESTURE_END); - CancelTouchPoint(); + SendPacket(CancelTouchPoint(), Gestures(ET_GESTURE_END)); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_CANCEL, ET_GESTURE_END), GetAndResetSentGestures())); @@ -1134,15 +1050,14 @@ TEST_F(TouchDispositionGestureFilterTest, EventFlagPropagation) { // Real gestures should propagate flags from their causal touches. - PushGesture(ET_GESTURE_TAP_DOWN); - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), Gestures(ET_GESTURE_TAP_DOWN)); SendTouchNotConsumedAck(); EXPECT_TRUE( GesturesMatch(Gestures(ET_GESTURE_TAP_DOWN), GetAndResetSentGestures())); EXPECT_EQ(kDefaultEventFlags, LastSentGestureFlags()); // Synthetic gestures lack flags. - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), NoGestures()); SendTouchNotConsumedAck(); EXPECT_TRUE(GesturesMatch(Gestures(ET_GESTURE_TAP_CANCEL), GetAndResetSentGestures())); @@ -1151,8 +1066,7 @@ TEST_F(TouchDispositionGestureFilterTest, PreviousScrollPrevented) { - PushGesture(ET_GESTURE_BEGIN); - PressTouchPoint(1, 1); + SendPacket(PressTouchPoint(), Gestures(ET_GESTURE_BEGIN)); EXPECT_FALSE(GesturesSent()); SendTouchNotConsumedAck(); EXPECT_TRUE( @@ -1160,29 +1074,25 @@ // The sent scroll update should always reflect whether any preceding scroll // update has been dropped. - PushGesture(ET_GESTURE_SCROLL_UPDATE); - MoveTouchPoint(0, 2, 2); + SendPacket(MoveTouchPoint(), Gestures(ET_GESTURE_SCROLL_UPDATE)); SendTouchNotConsumedAck(); ASSERT_TRUE(GesturesSent()); EXPECT_FALSE(last_sent_gesture() .details.previous_scroll_update_in_sequence_prevented()); GetAndResetSentGestures(); - PushGesture(ET_GESTURE_SCROLL_UPDATE); - MoveTouchPoint(0, -2, -2); + SendPacket(MoveTouchPoint(), Gestures(ET_GESTURE_SCROLL_UPDATE)); SendTouchConsumedAck(); EXPECT_FALSE(GesturesSent()); - PushGesture(ET_GESTURE_SCROLL_UPDATE); - MoveTouchPoint(0, 2, 2); + SendPacket(MoveTouchPoint(), Gestures(ET_GESTURE_SCROLL_UPDATE)); SendTouchNotConsumedAck(); ASSERT_TRUE(GesturesSent()); EXPECT_TRUE(last_sent_gesture() .details.previous_scroll_update_in_sequence_prevented()); GetAndResetSentGestures(); - PushGesture(ET_GESTURE_SCROLL_UPDATE); - MoveTouchPoint(0, 2, 2); + SendPacket(MoveTouchPoint(), Gestures(ET_GESTURE_SCROLL_UPDATE)); SendTouchNotConsumedAck(); ASSERT_TRUE(GesturesSent()); EXPECT_TRUE(last_sent_gesture()
diff --git a/ui/events/latency_info.cc b/ui/events/latency_info.cc index 4aadd66..1f88669 100644 --- a/ui/events/latency_info.cc +++ b/ui/events/latency_info.cc
@@ -29,9 +29,6 @@ CASE_TYPE(INPUT_EVENT_LATENCY_ACK_RWH_COMPONENT); CASE_TYPE(WINDOW_SNAPSHOT_FRAME_NUMBER_COMPONENT); CASE_TYPE(WINDOW_OLD_SNAPSHOT_FRAME_NUMBER_COMPONENT); - CASE_TYPE(INPUT_EVENT_BROWSER_COMPOSITE_COMPONENT); - CASE_TYPE(INPUT_EVENT_BROWSER_SWAP_BUFFER_COMPONENT); - CASE_TYPE(INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT); CASE_TYPE(INPUT_EVENT_LATENCY_TERMINATED_MOUSE_COMPONENT); CASE_TYPE(INPUT_EVENT_LATENCY_TERMINATED_TOUCH_COMPONENT); CASE_TYPE(INPUT_EVENT_LATENCY_TERMINATED_GESTURE_COMPONENT);
diff --git a/ui/events/latency_info.h b/ui/events/latency_info.h index 00343af4..454e5618d 100644 --- a/ui/events/latency_info.h +++ b/ui/events/latency_info.h
@@ -54,13 +54,6 @@ WINDOW_OLD_SNAPSHOT_FRAME_NUMBER_COMPONENT, // Timestamp when a tab is requested to be shown. TAB_SHOW_COMPONENT, - // Timestamp of when the Browser process began compositing - INPUT_EVENT_BROWSER_COMPOSITE_COMPONENT, - // Timestamp of when the Browser process began swap buffers - INPUT_EVENT_BROWSER_SWAP_BUFFER_COMPONENT, - // Timestamp of when the gpu service began swap buffers, unlike - // INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT which measure after - INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, // ---------------------------TERMINAL COMPONENT----------------------------- // TERMINAL COMPONENT is when we show the latency end in chrome://tracing. // Timestamp when the mouse event is acked from renderer and it does not @@ -111,7 +104,7 @@ }; // Empirically determined constant based on a typical scroll sequence. - enum { kTypicalMaxComponentsPerLatencyInfo = 9 }; + enum { kTypicalMaxComponentsPerLatencyInfo = 6 }; enum { kMaxInputCoordinates = 2 };
diff --git a/ui/events/ozone/BUILD.gn b/ui/events/ozone/BUILD.gn index d8976e11..57337c7 100644 --- a/ui/events/ozone/BUILD.gn +++ b/ui/events/ozone/BUILD.gn
@@ -44,6 +44,12 @@ } } +config("evdev") { + defines = [ + "USE_EVDEV" + ] +} + config("evdev_gestures") { defines = [ "USE_EVDEV_GESTURES" @@ -63,10 +69,14 @@ "evdev/event_modifiers_evdev.cc", "evdev/event_modifiers_evdev.h", "evdev/events_ozone_evdev_export.h", + "evdev/input_controller_evdev.cc", + "evdev/input_controller_evdev.h", "evdev/input_injector_evdev.cc", "evdev/input_injector_evdev.h", "evdev/keyboard_evdev.cc", "evdev/keyboard_evdev.h", + "evdev/mouse_button_map_evdev.cc", + "evdev/mouse_button_map_evdev.h", "evdev/tablet_event_converter_evdev.cc", "evdev/tablet_event_converter_evdev.h", "evdev/touch_event_converter_evdev.cc", @@ -85,6 +95,10 @@ "//ui/gfx", ] + public_configs = [ + ":evdev", + ] + if (use_ozone_evdev && use_evdev_gestures) { sources += [ "evdev/libgestures_glue/event_reader_libevdev_cros.cc", @@ -99,7 +113,7 @@ "evdev/libgestures_glue/gesture_timer_provider.h", ] - public_configs = [ + public_configs += [ ":evdev_gestures", ]
diff --git a/ui/events/ozone/evdev/event_converter_evdev_impl.cc b/ui/events/ozone/evdev/event_converter_evdev_impl.cc index 870a564..85e48b9 100644 --- a/ui/events/ozone/evdev/event_converter_evdev_impl.cc +++ b/ui/events/ozone/evdev/event_converter_evdev_impl.cc
@@ -19,6 +19,7 @@ base::FilePath path, int id, EventModifiersEvdev* modifiers, + MouseButtonMapEvdev* button_map, CursorDelegateEvdev* cursor, KeyboardEvdev* keyboard, const EventDispatchCallback& callback) @@ -28,6 +29,7 @@ cursor_(cursor), keyboard_(keyboard), modifiers_(modifiers), + button_map_(button_map), callback_(callback) { } @@ -98,11 +100,12 @@ return; unsigned int modifier; - if (input.code == BTN_LEFT) + const int button = button_map_->GetMappedButton(input.code); + if (button == BTN_LEFT) modifier = EVDEV_MODIFIER_LEFT_MOUSE_BUTTON; - else if (input.code == BTN_RIGHT) + else if (button == BTN_RIGHT) modifier = EVDEV_MODIFIER_RIGHT_MOUSE_BUTTON; - else if (input.code == BTN_MIDDLE) + else if (button == BTN_MIDDLE) modifier = EVDEV_MODIFIER_MIDDLE_MOUSE_BUTTON; else return;
diff --git a/ui/events/ozone/evdev/event_converter_evdev_impl.h b/ui/events/ozone/evdev/event_converter_evdev_impl.h index d0eab9f..274b2b4 100644 --- a/ui/events/ozone/evdev/event_converter_evdev_impl.h +++ b/ui/events/ozone/evdev/event_converter_evdev_impl.h
@@ -13,6 +13,7 @@ #include "ui/events/ozone/evdev/event_modifiers_evdev.h" #include "ui/events/ozone/evdev/events_ozone_evdev_export.h" #include "ui/events/ozone/evdev/keyboard_evdev.h" +#include "ui/events/ozone/evdev/mouse_button_map_evdev.h" struct input_event; @@ -25,6 +26,7 @@ base::FilePath path, int id, EventModifiersEvdev* modifiers, + MouseButtonMapEvdev* button_map, CursorDelegateEvdev* cursor, KeyboardEvdev* keyboard, const EventDispatchCallback& callback); @@ -64,6 +66,9 @@ // Modifier key state (shift, ctrl, etc). EventModifiersEvdev* modifiers_; + // Shared mouse button map. + MouseButtonMapEvdev* button_map_; + // Callback for dispatching events. EventDispatchCallback callback_;
diff --git a/ui/events/ozone/evdev/event_converter_evdev_impl_unittest.cc b/ui/events/ozone/evdev/event_converter_evdev_impl_unittest.cc index 94375831..ea3c582 100644 --- a/ui/events/ozone/evdev/event_converter_evdev_impl_unittest.cc +++ b/ui/events/ozone/evdev/event_converter_evdev_impl_unittest.cc
@@ -14,6 +14,7 @@ #include "ui/events/ozone/evdev/cursor_delegate_evdev.h" #include "ui/events/ozone/evdev/event_converter_evdev_impl.h" #include "ui/events/ozone/evdev/keyboard_evdev.h" +#include "ui/events/ozone/evdev/mouse_button_map_evdev.h" namespace ui { @@ -23,6 +24,7 @@ public: MockEventConverterEvdevImpl(int fd, EventModifiersEvdev* modifiers, + MouseButtonMapEvdev* button_map, CursorDelegateEvdev* cursor, KeyboardEvdev* keyboard, const EventDispatchCallback& callback) @@ -30,6 +32,7 @@ base::FilePath(kTestDevicePath), 1, modifiers, + button_map, cursor, keyboard, callback) { @@ -89,23 +92,22 @@ cursor_.reset(new ui::MockCursorEvdev()); modifiers_.reset(new ui::EventModifiersEvdev()); + button_map_.reset(new ui::MouseButtonMapEvdev()); const ui::EventDispatchCallback callback = base::Bind(&EventConverterEvdevImplTest::DispatchEventForTest, base::Unretained(this)); keyboard_.reset(new ui::KeyboardEvdev( modifiers_.get(), callback)); - device_.reset( - new ui::MockEventConverterEvdevImpl(events_in_, - modifiers_.get(), - cursor_.get(), - keyboard_.get(), - callback)); + device_.reset(new ui::MockEventConverterEvdevImpl( + events_in_, modifiers_.get(), button_map_.get(), cursor_.get(), + keyboard_.get(), callback)); } void TearDown() override { device_.reset(); keyboard_.reset(); modifiers_.reset(); + button_map_.reset(); cursor_.reset(); close(events_in_); close(events_out_); @@ -114,6 +116,7 @@ ui::MockCursorEvdev* cursor() { return cursor_.get(); } ui::MockEventConverterEvdevImpl* device() { return device_.get(); } ui::EventModifiersEvdev* modifiers() { return modifiers_.get(); } + ui::MouseButtonMapEvdev* button_map() { return button_map_.get(); } unsigned size() { return dispatched_events_.size(); } ui::KeyEvent* dispatched_event(unsigned index) { @@ -138,6 +141,7 @@ scoped_ptr<ui::MockCursorEvdev> cursor_; scoped_ptr<ui::EventModifiersEvdev> modifiers_; + scoped_ptr<ui::MouseButtonMapEvdev> button_map_; scoped_ptr<ui::KeyboardEvdev> keyboard_; scoped_ptr<ui::MockEventConverterEvdevImpl> device_;
diff --git a/ui/events/ozone/evdev/event_device_info.h b/ui/events/ozone/evdev/event_device_info.h index d7350e5..470c960 100644 --- a/ui/events/ozone/evdev/event_device_info.h +++ b/ui/events/ozone/evdev/event_device_info.h
@@ -19,6 +19,17 @@ namespace ui { +// Input device types. +enum EVENTS_OZONE_EVDEV_EXPORT EventDeviceType { + DT_KEYBOARD, + DT_MOUSE, + DT_TOUCHPAD, + DT_TOUCHSCREEN, + DT_MULTITOUCH, + DT_MULTITOUCH_MOUSE, + DT_ALL, +}; + // Device information for Linux input devices // // This stores and queries information about input devices; in
diff --git a/ui/events/ozone/evdev/event_factory_evdev.cc b/ui/events/ozone/evdev/event_factory_evdev.cc index a6677df..d82465a 100644 --- a/ui/events/ozone/evdev/event_factory_evdev.cc +++ b/ui/events/ozone/evdev/event_factory_evdev.cc
@@ -17,7 +17,6 @@ #include "ui/events/ozone/device/device_manager.h" #include "ui/events/ozone/evdev/cursor_delegate_evdev.h" #include "ui/events/ozone/evdev/event_converter_evdev_impl.h" -#include "ui/events/ozone/evdev/event_device_info.h" #include "ui/events/ozone/evdev/input_injector_evdev.h" #include "ui/events/ozone/evdev/tablet_event_converter_evdev.h" #include "ui/events/ozone/evdev/touch_event_converter_evdev.h" @@ -51,6 +50,7 @@ // State shared between devices. Must not be dereferenced on worker thread. EventModifiersEvdev* modifiers; + MouseButtonMapEvdev* button_map; KeyboardEvdev* keyboard; CursorDelegateEvdev* cursor; #if defined(USE_EVDEV_GESTURES) @@ -79,13 +79,11 @@ // Touchpad or mouse: use gestures library. // EventReaderLibevdevCros -> GestureInterpreterLibevdevCros -> DispatchEvent if (UseGesturesLibraryForDevice(devinfo)) { - scoped_ptr<GestureInterpreterLibevdevCros> gesture_interp = make_scoped_ptr( - new GestureInterpreterLibevdevCros(params.id, - params.modifiers, - params.cursor, - params.keyboard, - params.gesture_property_provider, - params.dispatch_callback)); + scoped_ptr<GestureInterpreterLibevdevCros> gesture_interp = + make_scoped_ptr(new GestureInterpreterLibevdevCros( + params.id, params.modifiers, params.button_map, params.cursor, + params.keyboard, params.gesture_property_provider, + params.dispatch_callback)); return make_scoped_ptr(new EventReaderLibevdevCros( fd, params.path, params.id, gesture_interp.Pass())); } @@ -106,14 +104,9 @@ params.dispatch_callback)); // Everything else: use EventConverterEvdevImpl. - return make_scoped_ptr<EventConverterEvdevImpl>( - new EventConverterEvdevImpl(fd, - params.path, - params.id, - params.modifiers, - params.cursor, - params.keyboard, - params.dispatch_callback)); + return make_scoped_ptr<EventConverterEvdevImpl>(new EventConverterEvdevImpl( + fd, params.path, params.id, params.modifiers, params.button_map, + params.cursor, params.keyboard, params.dispatch_callback)); } // Open an input device. Opening may put the calling thread to sleep, and @@ -179,6 +172,13 @@ #if defined(USE_EVDEV_GESTURES) gesture_property_provider_(new GesturePropertyProvider), #endif + input_controller_(this, + &button_map_ +#if defined(USE_EVDEV_GESTURES) + , + gesture_property_provider_.get() +#endif + ), weak_ptr_factory_(this) { DCHECK(device_manager_); } @@ -235,6 +235,7 @@ params->path = event.path(); params->dispatch_callback = dispatch_callback_; params->modifiers = &modifiers_; + params->button_map = &button_map_; params->keyboard = &keyboard_; params->cursor = cursor_; #if defined(USE_EVDEV_GESTURES) @@ -336,4 +337,21 @@ return ++last_device_id_; } +bool EventFactoryEvdev::GetDeviceIdsByType(const EventDeviceType type, + std::vector<int>* device_ids) { + if (device_ids) + device_ids->clear(); + std::vector<int> ids; + +#if defined(USE_EVDEV_GESTURES) + // Ask GesturePropertyProvider for matching devices. + gesture_property_provider_->GetDeviceIdsByType(type, &ids); +#endif + // In the future we can add other device matching logics here. + + if (device_ids) + device_ids->assign(ids.begin(), ids.end()); + return !ids.empty(); +} + } // namespace ui
diff --git a/ui/events/ozone/evdev/event_factory_evdev.h b/ui/events/ozone/evdev/event_factory_evdev.h index baf454ba..bc7fe864 100644 --- a/ui/events/ozone/evdev/event_factory_evdev.h +++ b/ui/events/ozone/evdev/event_factory_evdev.h
@@ -5,6 +5,8 @@ #ifndef UI_EVENTS_OZONE_EVDEV_EVENT_FACTORY_EVDEV_H_ #define UI_EVENTS_OZONE_EVDEV_EVENT_FACTORY_EVDEV_H_ +#include <vector> + #include "base/callback.h" #include "base/compiler_specific.h" #include "base/files/file_path.h" @@ -12,9 +14,12 @@ #include "base/task_runner.h" #include "ui/events/ozone/device/device_event_observer.h" #include "ui/events/ozone/evdev/event_converter_evdev.h" +#include "ui/events/ozone/evdev/event_device_info.h" #include "ui/events/ozone/evdev/event_modifiers_evdev.h" #include "ui/events/ozone/evdev/events_ozone_evdev_export.h" +#include "ui/events/ozone/evdev/input_controller_evdev.h" #include "ui/events/ozone/evdev/keyboard_evdev.h" +#include "ui/events/ozone/evdev/mouse_button_map_evdev.h" #include "ui/events/platform/platform_event_source.h" #include "ui/gfx/native_widget_types.h" #include "ui/ozone/public/system_input_injector.h" @@ -29,6 +34,10 @@ class DeviceManager; class SystemInputInjector; +#if !defined(USE_EVDEV) +#error Missing dependency on ui/events/ozone:events_ozone_evdev +#endif + #if defined(USE_EVDEV_GESTURES) class GesturePropertyProvider; #endif @@ -41,11 +50,18 @@ DeviceManager* device_manager); ~EventFactoryEvdev() override; + // Get a list of device ids that matches a device type. Return true if the + // list is not empty. |device_ids| can be NULL. + bool GetDeviceIdsByType(const EventDeviceType type, + std::vector<int>* device_ids); + void WarpCursorTo(gfx::AcceleratedWidget widget, const gfx::PointF& location); scoped_ptr<SystemInputInjector> CreateSystemInputInjector(); + InputController* input_controller() { return &input_controller_; } + protected: // DeviceEventObserver overrides: // @@ -90,6 +106,9 @@ // Modifier key state (shift, ctrl, etc). EventModifiersEvdev modifiers_; + // Mouse button map. + MouseButtonMapEvdev button_map_; + // Keyboard state. KeyboardEvdev keyboard_; @@ -101,6 +120,9 @@ scoped_ptr<GesturePropertyProvider> gesture_property_provider_; #endif + // Object for controlling input devices. + InputControllerEvdev input_controller_; + // Support weak pointers for attach & detach callbacks. base::WeakPtrFactory<EventFactoryEvdev> weak_ptr_factory_;
diff --git a/ui/events/ozone/evdev/input_controller_evdev.cc b/ui/events/ozone/evdev/input_controller_evdev.cc new file mode 100644 index 0000000..c7f5967 --- /dev/null +++ b/ui/events/ozone/evdev/input_controller_evdev.cc
@@ -0,0 +1,134 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/events/ozone/evdev/input_controller_evdev.h" + +#include <linux/input.h> +#include <vector> + +#include "ui/events/ozone/evdev/event_factory_evdev.h" +#include "ui/events/ozone/evdev/mouse_button_map_evdev.h" + +#if defined(USE_EVDEV_GESTURES) +#include "ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.h" +#endif + +namespace ui { + +namespace { + +#if defined(USE_EVDEV_GESTURES) +void SetGestureIntProperty(GesturePropertyProvider* provider, + int id, + const std::string& name, + int value) { + GesturesProp* property = provider->GetProperty(id, name); + if (property) { + std::vector<int> values(1, value); + property->SetIntValue(values); + } +} + +void SetGestureBoolProperty(GesturePropertyProvider* provider, + int id, + const std::string& name, + bool value) { + GesturesProp* property = provider->GetProperty(id, name); + if (property) { + std::vector<bool> values(1, value); + property->SetBoolValue(values); + } +} +#endif + +} // namespace + +InputControllerEvdev::InputControllerEvdev( + EventFactoryEvdev* event_factory, + MouseButtonMapEvdev* button_map +#if defined(USE_EVDEV_GESTURES) + , + GesturePropertyProvider* gesture_property_provider +#endif + ) + : event_factory_(event_factory), + button_map_(button_map) +#if defined(USE_EVDEV_GESTURES) + , + gesture_property_provider_(gesture_property_provider) +#endif +{ +} + +InputControllerEvdev::~InputControllerEvdev() { +} + +bool InputControllerEvdev::HasMouse() { + return event_factory_->GetDeviceIdsByType(DT_MOUSE, NULL); +} + +bool InputControllerEvdev::HasTouchpad() { + return event_factory_->GetDeviceIdsByType(DT_TOUCHPAD, NULL); +} + +void InputControllerEvdev::SetIntPropertyForOneType(const EventDeviceType type, + const std::string& name, + int value) { +#if defined(USE_EVDEV_GESTURES) + std::vector<int> ids; + event_factory_->GetDeviceIdsByType(type, &ids); + for (size_t i = 0; i < ids.size(); ++i) { + SetGestureIntProperty(gesture_property_provider_, ids[i], name, value); + } +#endif + // In the future, we may add property setting codes for other non-gesture + // devices. One example would be keyboard settings. + // TODO(sheckylin): See http://crbug.com/398518 for example. +} + +void InputControllerEvdev::SetBoolPropertyForOneType(const EventDeviceType type, + const std::string& name, + bool value) { +#if defined(USE_EVDEV_GESTURES) + std::vector<int> ids; + event_factory_->GetDeviceIdsByType(type, &ids); + for (size_t i = 0; i < ids.size(); ++i) { + SetGestureBoolProperty(gesture_property_provider_, ids[i], name, value); + } +#endif +} + +void InputControllerEvdev::SetTouchpadSensitivity(int value) { + SetIntPropertyForOneType(DT_TOUCHPAD, "Pointer Sensitivity", value); + SetIntPropertyForOneType(DT_TOUCHPAD, "Scroll Sensitivity", value); +} + +void InputControllerEvdev::SetTapToClick(bool enabled) { + SetBoolPropertyForOneType(DT_TOUCHPAD, "Tap Enable", enabled); +} + +void InputControllerEvdev::SetThreeFingerClick(bool enabled) { + SetBoolPropertyForOneType(DT_TOUCHPAD, "T5R2 Three Finger Click Enable", + enabled); +} + +void InputControllerEvdev::SetTapDragging(bool enabled) { + SetBoolPropertyForOneType(DT_TOUCHPAD, "Tap Drag Enable", enabled); +} + +void InputControllerEvdev::SetNaturalScroll(bool enabled) { + SetBoolPropertyForOneType(DT_MULTITOUCH, "Australian Scrolling", enabled); +} + +void InputControllerEvdev::SetMouseSensitivity(int value) { + SetIntPropertyForOneType(DT_MOUSE, "Pointer Sensitivity", value); + SetIntPropertyForOneType(DT_MOUSE, "Scroll Sensitivity", value); +} + +void InputControllerEvdev::SetPrimaryButtonRight(bool right) { + button_map_->UpdateButtonMap(BTN_LEFT, right ? BTN_RIGHT : BTN_LEFT); + button_map_->UpdateButtonMap(BTN_RIGHT, right ? BTN_LEFT : BTN_RIGHT); +} + +} // namespace ui
diff --git a/ui/events/ozone/evdev/input_controller_evdev.h b/ui/events/ozone/evdev/input_controller_evdev.h new file mode 100644 index 0000000..d2a05bd --- /dev/null +++ b/ui/events/ozone/evdev/input_controller_evdev.h
@@ -0,0 +1,74 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_EVENTS_OZONE_EVDEV_INPUT_CONTROLLER_EVDEV_H_ +#define UI_EVENTS_OZONE_EVDEV_INPUT_CONTROLLER_EVDEV_H_ + +#include <string> + +#include "base/basictypes.h" +#include "ui/events/ozone/evdev/event_device_info.h" +#include "ui/events/ozone/evdev/events_ozone_evdev_export.h" +#include "ui/ozone/public/input_controller.h" + +namespace ui { + +class EventFactoryEvdev; +class MouseButtonMapEvdev; + +#if defined(USE_EVDEV_GESTURES) +class GesturePropertyProvider; +#endif + +// Ozone InputController implementation for the Linux input subsystem ("evdev"). +class EVENTS_OZONE_EVDEV_EXPORT InputControllerEvdev : public InputController { + public: + InputControllerEvdev(EventFactoryEvdev* event_factory, + MouseButtonMapEvdev* button_map +#if defined(USE_EVDEV_GESTURES) + , + GesturePropertyProvider* gesture_property_provider +#endif + ); + virtual ~InputControllerEvdev(); + + // InputController overrides: + // + // Interfaces for configuring input devices. + bool HasMouse() override; + bool HasTouchpad() override; + void SetTouchpadSensitivity(int value) override; + void SetTapToClick(bool enabled) override; + void SetThreeFingerClick(bool enabled) override; + void SetTapDragging(bool enabled) override; + void SetNaturalScroll(bool enabled) override; + void SetMouseSensitivity(int value) override; + void SetPrimaryButtonRight(bool right) override; + + private: + // Set a property value for all devices of one type. + void SetIntPropertyForOneType(const EventDeviceType type, + const std::string& name, + int value); + void SetBoolPropertyForOneType(const EventDeviceType type, + const std::string& name, + bool value); + + // Event factory object which manages device event converters. + EventFactoryEvdev* event_factory_; // Not owned. + + // Mouse button map. + MouseButtonMapEvdev* button_map_; // Not owned. + +#if defined(USE_EVDEV_GESTURES) + // Gesture library property provider. + GesturePropertyProvider* gesture_property_provider_; // Not owned. +#endif + + DISALLOW_COPY_AND_ASSIGN(InputControllerEvdev); +}; + +} // namespace ui + +#endif // UI_EVENTS_OZONE_EVDEV_INPUT_CONTROLLER_EVDEV_H_
diff --git a/ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.cc b/ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.cc index b0d02b4..24427278 100644 --- a/ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.cc +++ b/ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.cc
@@ -6,6 +6,7 @@ #include <gestures/gestures.h> #include <libevdev/libevdev.h> +#include <linux/input.h> #include "base/strings/stringprintf.h" #include "base/timer/timer.h" @@ -16,6 +17,7 @@ #include "ui/events/ozone/evdev/keyboard_evdev.h" #include "ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.h" #include "ui/events/ozone/evdev/libgestures_glue/gesture_timer_provider.h" +#include "ui/events/ozone/evdev/mouse_button_map_evdev.h" #include "ui/gfx/geometry/point_f.h" namespace ui { @@ -38,6 +40,24 @@ } } +// Convert Linux button code to libgestures button code. +int GetGestureButton(const MouseButtonMapEvdev::Button code) { + switch (code) { + case BTN_LEFT: + return GESTURES_BUTTON_LEFT; + case BTN_RIGHT: + return GESTURES_BUTTON_RIGHT; + case BTN_MIDDLE: + return GESTURES_BUTTON_MIDDLE; + case BTN_FORWARD: + return GESTURES_BUTTON_FORWARD; + case BTN_BACK: + return GESTURES_BUTTON_BACK; + default: + return GESTURES_BUTTON_NONE; + } +} + // Convert libevdev state to libgestures hardware properties. HardwareProperties GestureHardwareProperties( Evdev* evdev, @@ -86,12 +106,14 @@ GestureInterpreterLibevdevCros::GestureInterpreterLibevdevCros( int id, EventModifiersEvdev* modifiers, + MouseButtonMapEvdev* button_map, CursorDelegateEvdev* cursor, KeyboardEvdev* keyboard, GesturePropertyProvider* property_provider, const EventDispatchCallback& callback) : id_(id), modifiers_(modifiers), + button_map_(button_map), cursor_(cursor), keyboard_(keyboard), property_provider_(property_provider), @@ -191,12 +213,18 @@ hwstate.fingers = fingers; // Buttons. - if (Event_Get_Button_Left(evdev)) - hwstate.buttons_down |= GESTURES_BUTTON_LEFT; - if (Event_Get_Button_Middle(evdev)) - hwstate.buttons_down |= GESTURES_BUTTON_MIDDLE; - if (Event_Get_Button_Right(evdev)) - hwstate.buttons_down |= GESTURES_BUTTON_RIGHT; + if (Event_Get_Button_Left(evdev)) { + hwstate.buttons_down |= + GetGestureButton(button_map_->GetMappedButton(BTN_LEFT)); + } + if (Event_Get_Button_Middle(evdev)) { + hwstate.buttons_down |= + GetGestureButton(button_map_->GetMappedButton(BTN_MIDDLE)); + } + if (Event_Get_Button_Right(evdev)) { + hwstate.buttons_down |= + GetGestureButton(button_map_->GetMappedButton(BTN_RIGHT)); + } GestureInterpreterPushHardwareState(interpreter_, &hwstate); }
diff --git a/ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.h b/ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.h index 125f8ed..1f2293cd 100644 --- a/ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.h +++ b/ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.h
@@ -20,6 +20,7 @@ class EventDeviceInfo; class EventModifiersEvdev; +class MouseButtonMapEvdev; class CursorDelegateEvdev; class KeyboardEvdev; class GestureDeviceProperties; @@ -43,6 +44,7 @@ public: GestureInterpreterLibevdevCros(int id, EventModifiersEvdev* modifiers, + MouseButtonMapEvdev* button_map, CursorDelegateEvdev* cursor, KeyboardEvdev* keyboard, GesturePropertyProvider* property_provider, @@ -86,6 +88,9 @@ // Shared modifier state. EventModifiersEvdev* modifiers_; + // Shared mouse button map. + MouseButtonMapEvdev* button_map_; + // Shared cursor state. CursorDelegateEvdev* cursor_;
diff --git a/ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.cc b/ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.cc index 5f49a7ad..02b97c2 100644 --- a/ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.cc +++ b/ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.cc
@@ -11,10 +11,7 @@ #include <stdint.h> #include <string.h> #include <algorithm> -#include <iostream> -#include <vector> -#include "base/basictypes.h" #include "base/containers/hash_tables.h" #include "base/files/file_enumerator.h" #include "base/files/file_util.h" @@ -31,128 +28,104 @@ #define GPROP_LOG DVLOG #define INFO_SEVERITY 1 -/* Implementation of GesturesProp declared in gestures.h - * - * libgestures requires that this be in the top level namespace. - * */ -class GesturesProp { - public: - typedef ui::GesturePropertyProvider::PropertyType PropertyType; +// GesturesProp implementation. +// +// Check the header file for its definition. +GesturesProp::GesturesProp(const std::string& name, + const PropertyType type, + const size_t count) + : name_(name), + type_(type), + count_(count), + get_(NULL), + set_(NULL), + handler_data_(NULL) { +} - GesturesProp(const std::string& name, - const PropertyType type, - const size_t count) - : name_(name), - type_(type), - count_(count), - get_(NULL), - set_(NULL), - handler_data_(NULL) {} - virtual ~GesturesProp() {} +std::vector<int> GesturesProp::GetIntValue() const { + NOTREACHED(); + return std::vector<int>(); +} - // Variant-ish interfaces for accessing the property value. Each type of - // property should override the corresponding interfaces for it. - virtual std::vector<int> GetIntValue() const { - NOTREACHED(); - return std::vector<int>(); - } - virtual bool SetIntValue(const std::vector<int>& value) { - NOTREACHED(); - return false; - } - virtual std::vector<int16_t> GetShortValue() const { - NOTREACHED(); - return std::vector<int16_t>(); - } - virtual bool SetShortValue(const std::vector<int16_t>& value) { - NOTREACHED(); - return false; - } - virtual std::vector<bool> GetBoolValue() const { - NOTREACHED(); - return std::vector<bool>(); - } - virtual bool SetBoolValue(const std::vector<bool>& value) { - NOTREACHED(); - return false; - } - virtual std::string GetStringValue() const { - NOTREACHED(); - return std::string(); - } - virtual bool SetStringValue(const std::string& value) { - NOTREACHED(); - return false; - } - virtual std::vector<double> GetDoubleValue() const { - NOTREACHED(); - return std::vector<double>(); - } - virtual bool SetDoubleValue(const std::vector<double>& value) { - NOTREACHED(); - return false; - } +bool GesturesProp::SetIntValue(const std::vector<int>& value) { + NOTREACHED(); + return false; +} - // Set property access handlers. - void SetHandlers(GesturesPropGetHandler get, - GesturesPropSetHandler set, - void* data) { - get_ = get; - set_ = set; - handler_data_ = data; - } +std::vector<int16_t> GesturesProp::GetShortValue() const { + NOTREACHED(); + return std::vector<int16_t>(); +} - // Accessors. - const std::string& name() const { return name_; } - PropertyType type() const { return type_; } - size_t count() const { return count_; } - virtual bool IsReadOnly() const = 0; +bool GesturesProp::SetShortValue(const std::vector<int16_t>& value) { + NOTREACHED(); + return false; +} - protected: - void OnGet() const { - // We don't have the X server now so there is currently nothing to do when - // the get handler returns true. - // TODO(sheckylin): Re-visit this if we use handlers that modifies the - // property. - if (get_) - get_(handler_data_); - } +std::vector<bool> GesturesProp::GetBoolValue() const { + NOTREACHED(); + return std::vector<bool>(); +} - void OnSet() const { - // Call the property set handler if available. - if (set_) - set_(handler_data_); - } +bool GesturesProp::SetBoolValue(const std::vector<bool>& value) { + NOTREACHED(); + return false; +} - private: - // For logging purpose. - friend std::ostream& operator<<(std::ostream& os, - const GesturesProp& property); +std::string GesturesProp::GetStringValue() const { + NOTREACHED(); + return std::string(); +} - // Interfaces for getting internal pointers and stuff. - virtual const char** GetStringWritebackPtr() const { - NOTREACHED(); - return NULL; - } - virtual bool IsAllocated() const { - NOTREACHED(); - return false; - } +bool GesturesProp::SetStringValue(const std::string& value) { + NOTREACHED(); + return false; +} - // Property name, type and number of elements. - std::string name_; - PropertyType type_; - size_t count_; +std::vector<double> GesturesProp::GetDoubleValue() const { + NOTREACHED(); + return std::vector<double>(); +} - // Handler function pointers and the data to be passed to them when the - // property is accessed. - GesturesPropGetHandler get_; - GesturesPropSetHandler set_; - void* handler_data_; +bool GesturesProp::SetDoubleValue(const std::vector<double>& value) { + NOTREACHED(); + return false; +} - DISALLOW_COPY_AND_ASSIGN(GesturesProp); -}; +void GesturesProp::SetHandlers(GesturesPropGetHandler get, + GesturesPropSetHandler set, + void* data) { + get_ = get; + set_ = set; + handler_data_ = data; +} +void GesturesProp::OnGet() const { + // We don't have the X server now so there is currently nothing to do when + // the get handler returns true. + // TODO(sheckylin): Re-visit this if we use handlers that modifies the + // property. + if (get_) + get_(handler_data_); +} + +void GesturesProp::OnSet() const { + // Call the property set handler if available. + if (set_) + set_(handler_data_); +} + +const char** GesturesProp::GetStringWritebackPtr() const { + NOTREACHED(); + return NULL; +} + +bool GesturesProp::IsAllocated() const { + NOTREACHED(); + return false; +} + +// Type-templated GesturesProp. template <typename T> class TypedGesturesProp : public GesturesProp { public: @@ -458,34 +431,36 @@ // Check if a device falls into one device type category. bool IsDeviceOfType(const ui::GesturePropertyProvider::DevicePtr device, - const ui::GesturePropertyProvider::DeviceType type) { + const ui::EventDeviceType type) { EvdevClass evdev_class = device->info.evdev_class; switch (type) { - case ui::GesturePropertyProvider::DT_MOUSE: + case ui::DT_KEYBOARD: + return (evdev_class == EvdevClassKeyboard); + break; + case ui::DT_MOUSE: return (evdev_class == EvdevClassMouse || evdev_class == EvdevClassMultitouchMouse); break; - case ui::GesturePropertyProvider::DT_TOUCHPAD: + case ui::DT_TOUCHPAD: // Note that the behavior here is different from the inputcontrol script // which actually returns touchscreen devices as well. return (evdev_class == EvdevClassTouchpad); break; - case ui::GesturePropertyProvider::DT_TOUCHSCREEN: + case ui::DT_TOUCHSCREEN: return (evdev_class == EvdevClassTouchscreen); break; - case ui::GesturePropertyProvider::DT_MULTITOUCH: + case ui::DT_MULTITOUCH: return (evdev_class == EvdevClassTouchpad || evdev_class == EvdevClassTouchscreen || evdev_class == EvdevClassMultitouchMouse); break; - case ui::GesturePropertyProvider::DT_MULTITOUCH_MOUSE: + case ui::DT_MULTITOUCH_MOUSE: return (evdev_class == EvdevClassMultitouchMouse); break; - case ui::GesturePropertyProvider::DT_ALL: + case ui::DT_ALL: return true; break; default: - NOTREACHED(); break; } return false; @@ -874,14 +849,19 @@ GesturePropertyProvider::~GesturePropertyProvider() { } -void GesturePropertyProvider::GetDeviceIdsByType( - const DeviceType type, +bool GesturePropertyProvider::GetDeviceIdsByType( + const EventDeviceType type, std::vector<DeviceId>* device_ids) { - device_ids->clear(); + bool exists = false; DeviceMap::const_iterator it = device_map_.begin(); - for (; it != device_map_.end(); ++it) - if (IsDeviceOfType(it->second, type)) - device_ids->push_back(it->first); + for (; it != device_map_.end(); ++it) { + if (IsDeviceOfType(it->second, type)) { + exists = true; + if (device_ids) + device_ids->push_back(it->first); + } + } + return exists; } GesturesProp* GesturePropertyProvider::GetProperty(const DeviceId device_id, @@ -1098,9 +1078,7 @@ // Otherwise, look for valid entries according to the spec. if (has_checked_section_type) { if (piece == "Driver") { - // TODO(sheckylin): Support "Driver" so that we can force a device - // not to use the gesture lib. - NOTIMPLEMENTED(); + // "Driver" field is meaningless for non-X11 setup. break; } else if (piece == "Identifier") { is_parsing = true;
diff --git a/ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.h b/ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.h index dd7afb2..f59793d 100644 --- a/ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.h +++ b/ui/events/ozone/evdev/libgestures_glue/gesture_property_provider.h
@@ -9,10 +9,14 @@ #include <libevdev/libevdev.h> #include <map> +#include <ostream> #include <string> +#include <vector> +#include "base/basictypes.h" #include "base/containers/scoped_ptr_hash_map.h" #include "base/memory/scoped_vector.h" +#include "ui/events/ozone/evdev/event_device_info.h" #include "ui/events/ozone/evdev/events_ozone_evdev_export.h" namespace ui { @@ -52,16 +56,6 @@ // builds. class EVENTS_OZONE_EVDEV_EXPORT GesturePropertyProvider { public: - // Device types. - enum DeviceType { - DT_MOUSE, - DT_TOUCHPAD, - DT_TOUCHSCREEN, - DT_MULTITOUCH, - DT_MULTITOUCH_MOUSE, - DT_ALL, - }; - // Property types. enum PropertyType { PT_INT, @@ -82,8 +76,10 @@ GesturePropertyProvider(); ~GesturePropertyProvider(); - // Get a list of device ids that matches a device type. - void GetDeviceIdsByType(const DeviceType type, + // Get a list of device ids that matches a device type. Return true if the + // list is not empty. |device_ids| can be NULL. Existing data in |device_ids| + // won't be deleted. + bool GetDeviceIdsByType(const EventDeviceType type, std::vector<DeviceId>* device_ids); // Get the GesturesProp object. Returns NULL if not found. @@ -260,4 +256,73 @@ } // namspace ui +// GesturesProp logging function. +std::ostream& operator<<(std::ostream& os, const GesturesProp& prop); + +// Implementation of GesturesProp declared in gestures.h +// +// libgestures requires that this be in the top level namespace. We have also +// to put it in the header file so that other classes will be able to use the +// gesture property objects. +class GesturesProp { + public: + typedef ui::GesturePropertyProvider::PropertyType PropertyType; + + GesturesProp(const std::string& name, + const PropertyType type, + const size_t count); + virtual ~GesturesProp() {} + + // Variant-ish interfaces for accessing the property value. Each type of + // property should override the corresponding interfaces for it. + virtual std::vector<int> GetIntValue() const; + virtual bool SetIntValue(const std::vector<int>& value); + virtual std::vector<int16_t> GetShortValue() const; + virtual bool SetShortValue(const std::vector<int16_t>& value); + virtual std::vector<bool> GetBoolValue() const; + virtual bool SetBoolValue(const std::vector<bool>& value); + virtual std::string GetStringValue() const; + virtual bool SetStringValue(const std::string& value); + virtual std::vector<double> GetDoubleValue() const; + virtual bool SetDoubleValue(const std::vector<double>& value); + + // Set property access handlers. + void SetHandlers(GesturesPropGetHandler get, + GesturesPropSetHandler set, + void* data); + + // Accessors. + const std::string& name() const { return name_; } + PropertyType type() const { return type_; } + size_t count() const { return count_; } + virtual bool IsReadOnly() const = 0; + + protected: + // Functions to be called when the property value was accessed. + void OnGet() const; + void OnSet() const; + + private: + // For logging purpose. + friend std::ostream& operator<<(std::ostream& os, + const GesturesProp& property); + + // Interfaces for getting internal pointers and stuff. + virtual const char** GetStringWritebackPtr() const; + virtual bool IsAllocated() const; + + // Property name, type and number of elements. + std::string name_; + PropertyType type_; + size_t count_; + + // Handler function pointers and the data to be passed to them when the + // property is accessed. + GesturesPropGetHandler get_; + GesturesPropSetHandler set_; + void* handler_data_; + + DISALLOW_COPY_AND_ASSIGN(GesturesProp); +}; + #endif // UI_EVENTS_OZONE_EVDEV_LIBGESTURES_GLUE_GESTURE_PROPERTY_PROVIDER_H_
diff --git a/ui/events/ozone/evdev/mouse_button_map_evdev.cc b/ui/events/ozone/evdev/mouse_button_map_evdev.cc new file mode 100644 index 0000000..c8f8e1f --- /dev/null +++ b/ui/events/ozone/evdev/mouse_button_map_evdev.cc
@@ -0,0 +1,52 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/events/ozone/evdev/mouse_button_map_evdev.h" + +#include <linux/input.h> + +#include "base/logging.h" + +namespace ui { + +namespace { + +// Defines the range of button codes that we support. +// +// Check linux/input.h for more info. +const MouseButtonMapEvdev::Button kMinMouseButtonCode = BTN_MISC; +const MouseButtonMapEvdev::Button kMaxMouseButtonCode = BTN_GEAR_UP; + +bool IsMouseButton(const MouseButtonMapEvdev::Button button) { + return (button >= kMinMouseButtonCode && button <= kMaxMouseButtonCode); +} + +} // namespace + +MouseButtonMapEvdev::MouseButtonMapEvdev() { + ResetButtonMap(); +} + +MouseButtonMapEvdev::~MouseButtonMapEvdev() { +} + +void MouseButtonMapEvdev::UpdateButtonMap(Button button_from, + Button button_to) { + DCHECK(IsMouseButton(button_from) && IsMouseButton(button_to)); + button_map_[button_from] = button_to; +} + +void MouseButtonMapEvdev::ResetButtonMap() { + button_map_.clear(); + for (Button i = kMinMouseButtonCode; i <= kMaxMouseButtonCode; ++i) + button_map_[i] = i; +} + +int MouseButtonMapEvdev::GetMappedButton(const Button button) const { + ButtonMap::const_iterator it = button_map_.find(button); + DCHECK(it != button_map_.end()); + return it->second; +} + +} // namespace ui
diff --git a/ui/events/ozone/evdev/mouse_button_map_evdev.h b/ui/events/ozone/evdev/mouse_button_map_evdev.h new file mode 100644 index 0000000..5cc240d --- /dev/null +++ b/ui/events/ozone/evdev/mouse_button_map_evdev.h
@@ -0,0 +1,53 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_EVENTS_OZONE_EVDEV_MOUSE_BUTTON_MAP_EVDEV_H_ +#define UI_EVENTS_OZONE_EVDEV_MOUSE_BUTTON_MAP_EVDEV_H_ + +#include <map> + +#include "base/basictypes.h" +#include "ui/events/ozone/evdev/events_ozone_evdev_export.h" + +namespace ui { + +// Mouse button map for Evdev. +// +// Chrome relies on the underlying OS to interpret mouse buttons. The Linux +// input subsystem does not assign any special meaning to these keys, so +// this work must happen at a higher layer (normally X11 or the console driver). +// When using evdev directly, we must do it ourselves. +// +// The mouse button map is shared between all input devices connected to the +// system. +class EVENTS_OZONE_EVDEV_EXPORT MouseButtonMapEvdev { + public: + typedef uint32_t Button; + typedef std::map<uint32_t, uint32_t> ButtonMap; + + MouseButtonMapEvdev(); + ~MouseButtonMapEvdev(); + + // Set mapping for one button. + void UpdateButtonMap(Button button_from, Button button_to); + + // Reset the button map to the system default. + void ResetButtonMap(); + + // Return the mapped button. + int GetMappedButton(const Button button) const; + + // Return current button map to use for incoming events. + const ButtonMap& button_map() { return button_map_; } + + private: + // Mouse button map. + ButtonMap button_map_; + + DISALLOW_COPY_AND_ASSIGN(MouseButtonMapEvdev); +}; + +} // namspace ui + +#endif // UI_EVENTS_OZONE_EVDEV_MOUSE_BUTTON_MAP_EVDEV_H_
diff --git a/ui/events/ozone/events_ozone.gyp b/ui/events/ozone/events_ozone.gyp index 1d3c3f5..987de17f 100644 --- a/ui/events/ozone/events_ozone.gyp +++ b/ui/events/ozone/events_ozone.gyp
@@ -56,7 +56,13 @@ ], 'defines': [ 'EVENTS_OZONE_EVDEV_IMPLEMENTATION', + 'USE_EVDEV', ], + 'direct_dependent_settings': { + 'defines': [ + 'USE_EVDEV', + ], + }, 'sources': [ 'evdev/libgestures_glue/event_reader_libevdev_cros.cc', 'evdev/libgestures_glue/event_reader_libevdev_cros.h', @@ -79,10 +85,14 @@ 'evdev/event_modifiers_evdev.cc', 'evdev/event_modifiers_evdev.h', 'evdev/events_ozone_evdev_export.h', + 'evdev/input_controller_evdev.cc', + 'evdev/input_controller_evdev.h', 'evdev/input_injector_evdev.cc', 'evdev/input_injector_evdev.h', 'evdev/keyboard_evdev.cc', 'evdev/keyboard_evdev.h', + 'evdev/mouse_button_map_evdev.cc', + 'evdev/mouse_button_map_evdev.h', 'evdev/tablet_event_converter_evdev.cc', 'evdev/tablet_event_converter_evdev.h', 'evdev/touch_event_converter_evdev.cc',
diff --git a/ui/file_manager/file_manager/background/js/compiled_resources.gyp b/ui/file_manager/file_manager/background/js/compiled_resources.gyp index be13541..157fef1 100644 --- a/ui/file_manager/file_manager/background/js/compiled_resources.gyp +++ b/ui/file_manager/file_manager/background/js/compiled_resources.gyp
@@ -30,6 +30,7 @@ 'drive_sync_handler.js', 'file_operation_handler.js', 'file_operation_manager.js', + 'file_operation_util.js', 'import_history.js', 'media_scanner.js', 'progress_center.js',
diff --git a/ui/file_manager/file_manager/background/js/file_operation_manager.js b/ui/file_manager/file_manager/background/js/file_operation_manager.js index 6f93247..694c1db 100644 --- a/ui/file_manager/file_manager/background/js/file_operation_manager.js +++ b/ui/file_manager/file_manager/background/js/file_operation_manager.js
@@ -3,364 +3,6 @@ // found in the LICENSE file. /** - * Utilities for FileOperationManager. - */ -var fileOperationUtil = {}; - -/** - * Resolves a path to either a DirectoryEntry or a FileEntry, regardless of - * whether the path is a directory or file. - * - * @param {DirectoryEntry} root The root of the filesystem to search. - * @param {string} path The path to be resolved. - * @return {Promise} Promise fulfilled with the resolved entry, or rejected with - * FileError. - */ -fileOperationUtil.resolvePath = function(root, path) { - if (path === '' || path === '/') - return Promise.resolve(root); - return new Promise(root.getFile.bind(root, path, {create: false})). - catch(function(error) { - if (error.name === util.FileError.TYPE_MISMATCH_ERR) { - // Bah. It's a directory, ask again. - return new Promise( - root.getDirectory.bind(root, path, {create: false})); - } else { - return Promise.reject(error); - } - }); -}; - -/** - * Checks if an entry exists at |relativePath| in |dirEntry|. - * If exists, tries to deduplicate the path by inserting parenthesized number, - * such as " (1)", before the extension. If it still exists, tries the - * deduplication again by increasing the number up to 10 times. - * For example, suppose "file.txt" is given, "file.txt", "file (1).txt", - * "file (2).txt", ..., "file (9).txt" will be tried. - * - * @param {DirectoryEntry} dirEntry The target directory entry. - * @param {string} relativePath The path to be deduplicated. - * @param {function(string)=} opt_successCallback Callback run with the - * deduplicated path on success. - * @param {function(FileOperationManager.Error)=} opt_errorCallback Callback run - * on error. - * @return {Promise} Promise fulfilled with available path. - */ -fileOperationUtil.deduplicatePath = function( - dirEntry, relativePath, opt_successCallback, opt_errorCallback) { - // The trial is up to 10. - var MAX_RETRY = 10; - - // Crack the path into three part. The parenthesized number (if exists) will - // be replaced by incremented number for retry. For example, suppose - // |relativePath| is "file (10).txt", the second check path will be - // "file (11).txt". - var match = /^(.*?)(?: \((\d+)\))?(\.[^.]*?)?$/.exec(relativePath); - var prefix = match[1]; - var ext = match[3] || ''; - - // Check to see if the target exists. - var resolvePath = function(trialPath, numRetry, copyNumber) { - return fileOperationUtil.resolvePath(dirEntry, trialPath).then(function() { - if (numRetry <= 1) { - // Hit the limit of the number of retrial. - // Note that we cannot create FileError object directly, so here we - // use Object.create instead. - return Promise.reject( - util.createDOMError(util.FileError.PATH_EXISTS_ERR)); - } - var newTrialPath = prefix + ' (' + copyNumber + ')' + ext; - return resolvePath(newTrialPath, numRetry - 1, copyNumber + 1); - }, function(error) { - // We expect to be unable to resolve the target file, since we're - // going to create it during the copy. However, if the resolve fails - // with anything other than NOT_FOUND, that's trouble. - if (error.name === util.FileError.NOT_FOUND_ERR) - return trialPath; - else - return Promise.reject(error); - }); - }; - - var promise = resolvePath(relativePath, MAX_RETRY, 1).catch(function(error) { - var targetPromise; - if (error.name === util.FileError.PATH_EXISTS_ERR) { - // Failed to uniquify the file path. There should be an existing - // entry, so return the error with it. - targetPromise = fileOperationUtil.resolvePath(dirEntry, relativePath); - } else { - targetPromise = Promise.reject(error); - } - return targetPromise.then(function(entry) { - return Promise.reject(new FileOperationManager.Error( - util.FileOperationErrorType.TARGET_EXISTS, entry)); - }, function(/** (Error|DOMError) */ inError) { - if (inError instanceof Error) - return Promise.reject(inError); - return Promise.reject(new FileOperationManager.Error( - util.FileOperationErrorType.FILESYSTEM_ERROR, inError)); - }); - }); - if (opt_successCallback) - promise.then(opt_successCallback, opt_errorCallback); - return promise; -}; - -/** - * Traverses files/subdirectories of the given entry, and returns them. - * In addition, this method annotate the size of each entry. The result will - * include the entry itself. - * - * @param {Entry} entry The root Entry for traversing. - * @param {function(Array.<Entry>)} successCallback Called when the traverse - * is successfully done with the array of the entries. - * @param {function(DOMError)} errorCallback Called on error with the first - * occurred error (i.e. following errors will just be discarded). - */ -fileOperationUtil.resolveRecursively = function( - entry, successCallback, errorCallback) { - var result = []; - var error = null; - var numRunningTasks = 0; - - var maybeInvokeCallback = function() { - // If there still remain some running tasks, wait their finishing. - if (numRunningTasks > 0) - return; - - if (error) - errorCallback(error); - else - successCallback(result); - }; - - // The error handling can be shared. - var onError = function(fileError) { - // If this is the first error, remember it. - if (!error) - error = fileError; - --numRunningTasks; - maybeInvokeCallback(); - }; - - var process = function(entry) { - numRunningTasks++; - result.push(entry); - if (entry.isDirectory) { - // The size of a directory is 1 bytes here, so that the progress bar - // will work smoother. - // TODO(hidehiko): Remove this hack. - entry.size = 1; - - // Recursively traverse children. - var reader = entry.createReader(); - reader.readEntries( - function processSubEntries(subEntries) { - if (error || subEntries.length == 0) { - // If an error is found already, or this is the completion - // callback, then finish the process. - --numRunningTasks; - maybeInvokeCallback(); - return; - } - - for (var i = 0; i < subEntries.length; i++) - process(subEntries[i]); - - // Continue to read remaining children. - reader.readEntries(processSubEntries, onError); - }, - onError); - } else { - // For a file, annotate the file size. - entry.getMetadata(function(metadata) { - entry.size = metadata.size; - --numRunningTasks; - maybeInvokeCallback(); - }, onError); - } - }; - - process(entry); -}; - -/** - * Copies source to parent with the name newName recursively. - * This should work very similar to FileSystem API's copyTo. The difference is; - * - The progress callback is supported. - * - The cancellation is supported. - * - * @param {Entry} source The entry to be copied. - * @param {DirectoryEntry} parent The entry of the destination directory. - * @param {string} newName The name of copied file. - * @param {function(Entry, Entry)} entryChangedCallback - * Callback invoked when an entry is created with the source Entry and - * the destination Entry. - * @param {function(Entry, number)} progressCallback Callback invoked - * periodically during the copying. It takes the source Entry and the - * processed bytes of it. - * @param {function(Entry)} successCallback Callback invoked when the copy - * is successfully done with the Entry of the created entry. - * @param {function(DOMError)} errorCallback Callback invoked when an error - * is found. - * @return {function()} Callback to cancel the current file copy operation. - * When the cancel is done, errorCallback will be called. The returned - * callback must not be called more than once. - */ -fileOperationUtil.copyTo = function( - source, parent, newName, entryChangedCallback, progressCallback, - successCallback, errorCallback) { - var copyId = null; - var pendingCallbacks = []; - - // Makes the callback called in order they were invoked. - var callbackQueue = new AsyncUtil.Queue(); - - var onCopyProgress = function(progressCopyId, status) { - callbackQueue.run(function(callback) { - if (copyId === null) { - // If the copyId is not yet available, wait for it. - pendingCallbacks.push( - onCopyProgress.bind(null, progressCopyId, status)); - callback(); - return; - } - - // This is not what we're interested in. - if (progressCopyId != copyId) { - callback(); - return; - } - - switch (status.type) { - case 'begin_copy_entry': - callback(); - break; - - case 'end_copy_entry': - // TODO(mtomasz): Convert URL to Entry in custom bindings. - (source.isFile ? parent.getFile : parent.getDirectory).call( - parent, - newName, - null, - function(entry) { - entryChangedCallback(status.sourceUrl, entry); - callback(); - }, - function() { - entryChangedCallback(status.sourceUrl, null); - callback(); - }); - break; - - case 'progress': - progressCallback(status.sourceUrl, status.size); - callback(); - break; - - case 'success': - chrome.fileManagerPrivate.onCopyProgress.removeListener( - onCopyProgress); - // TODO(mtomasz): Convert URL to Entry in custom bindings. - util.URLsToEntries( - [status.destinationUrl], function(destinationEntries) { - successCallback(destinationEntries[0] || null); - callback(); - }); - break; - - case 'error': - chrome.fileManagerPrivate.onCopyProgress.removeListener( - onCopyProgress); - errorCallback(util.createDOMError(status.error)); - callback(); - break; - - default: - // Found unknown state. Cancel the task, and return an error. - console.error('Unknown progress type: ' + status.type); - chrome.fileManagerPrivate.onCopyProgress.removeListener( - onCopyProgress); - chrome.fileManagerPrivate.cancelCopy(copyId); - errorCallback(util.createDOMError( - util.FileError.INVALID_STATE_ERR)); - callback(); - } - }); - }; - - // Register the listener before calling startCopy. Otherwise some events - // would be lost. - chrome.fileManagerPrivate.onCopyProgress.addListener(onCopyProgress); - - // Then starts the copy. - // TODO(mtomasz): Convert URL to Entry in custom bindings. - chrome.fileManagerPrivate.startCopy( - source.toURL(), parent.toURL(), newName, function(startCopyId) { - // last error contains the FileError code on error. - if (chrome.runtime.lastError) { - // Unsubscribe the progress listener. - chrome.fileManagerPrivate.onCopyProgress.removeListener( - onCopyProgress); - errorCallback(util.createDOMError( - chrome.runtime.lastError.message || '')); - return; - } - - copyId = startCopyId; - for (var i = 0; i < pendingCallbacks.length; i++) { - pendingCallbacks[i](); - } - }); - - return function() { - // If copyId is not yet available, wait for it. - if (copyId == null) { - pendingCallbacks.push(function() { - chrome.fileManagerPrivate.cancelCopy(copyId); - }); - return; - } - - chrome.fileManagerPrivate.cancelCopy(copyId); - }; -}; - -/** - * Thin wrapper of chrome.fileManagerPrivate.zipSelection to adapt its - * interface similar to copyTo(). - * - * @param {Array.<Entry>} sources The array of entries to be archived. - * @param {DirectoryEntry} parent The entry of the destination directory. - * @param {string} newName The name of the archive to be created. - * @param {function(FileEntry)} successCallback Callback invoked when the - * operation is successfully done with the entry of the created archive. - * @param {function(DOMError)} errorCallback Callback invoked when an error - * is found. - */ -fileOperationUtil.zipSelection = function( - sources, parent, newName, successCallback, errorCallback) { - // TODO(mtomasz): Move conversion from entry to url to custom bindings. - // crbug.com/345527. - chrome.fileManagerPrivate.zipSelection( - parent.toURL(), - util.entriesToURLs(sources), - newName, function(success) { - if (!success) { - // Failed to create a zip archive. - errorCallback( - util.createDOMError(util.FileError.INVALID_MODIFICATION_ERR)); - return; - } - - // Returns the created entry via callback. - parent.getFile( - newName, {create: false}, successCallback, errorCallback); - }); -}; - -/** * @constructor * @extends {cr.EventTarget} */ @@ -403,7 +45,7 @@ * @param {Object} status Current FileOperationManager's status. See also * FileOperationManager.Task.getStatus(). * @param {string} taskId ID of task related with the event. - * @param {FileOperationManager.Error=} opt_error The info for the error. This + * @param {fileOperationUtil.Error=} opt_error The info for the error. This * should be set iff the reason is "ERROR". */ FileOperationManager.EventRouter.prototype.sendProgressEvent = function( @@ -480,637 +122,6 @@ }; /** - * A record of a queued copy operation. - * - * Multiple copy operations may be queued at any given time. Additional - * Tasks may be added while the queue is being serviced. Though a - * cancel operation cancels everything in the queue. - * - * @param {util.FileOperationType} operationType The type of this operation. - * @param {Array.<Entry>} sourceEntries Array of source entries. - * @param {DirectoryEntry} targetDirEntry Target directory. - * @constructor - */ -FileOperationManager.Task = function( - operationType, sourceEntries, targetDirEntry) { - this.operationType = operationType; - this.sourceEntries = sourceEntries; - this.targetDirEntry = targetDirEntry; - - /** - * An array of map from url to Entry being processed. - * @type {Array.<Object<string, Entry>>} - */ - this.processingEntries = null; - - /** - * Total number of bytes to be processed. Filled in initialize(). - * Use 1 as an initial value to indicate that the task is not completed. - * @type {number} - */ - this.totalBytes = 1; - - /** - * Total number of already processed bytes. Updated periodically. - * @type {number} - */ - this.processedBytes = 0; - - /** - * Index of the progressing entry in sourceEntries. - * @type {number} - * @private - */ - this.processingSourceIndex_ = 0; - - /** - * Set to true when cancel is requested. - * @private {boolean} - */ - this.cancelRequested_ = false; - - /** - * Callback to cancel the running process. - * @private {?function()} - */ - this.cancelCallback_ = null; - - // TODO(hidehiko): After we support recursive copy, we don't need this. - // If directory already exists, we try to make a copy named 'dir (X)', - // where X is a number. When we do this, all subsequent copies from - // inside the subtree should be mapped to the new directory name. - // For example, if 'dir' was copied as 'dir (1)', then 'dir/file.txt' should - // become 'dir (1)/file.txt'. - this.renamedDirectories_ = []; -}; - -/** - * @param {function()} callback When entries resolved. - */ -FileOperationManager.Task.prototype.initialize = function(callback) { -}; - -/** - * Requests cancellation of this task. - * When the cancellation is done, it is notified via callbacks of run(). - */ -FileOperationManager.Task.prototype.requestCancel = function() { - this.cancelRequested_ = true; - if (this.cancelCallback_) { - this.cancelCallback_(); - this.cancelCallback_ = null; - } -}; - -/** - * Runs the task. Sub classes must implement this method. - * - * @param {function(util.EntryChangedKind, Entry)} entryChangedCallback - * Callback invoked when an entry is changed. - * @param {function()} progressCallback Callback invoked periodically during - * the operation. - * @param {function()} successCallback Callback run on success. - * @param {function(FileOperationManager.Error)} errorCallback Callback run on - * error. - */ -FileOperationManager.Task.prototype.run = function( - entryChangedCallback, progressCallback, successCallback, errorCallback) { -}; - -/** - * Get states of the task. - * TOOD(hirono): Removes this method and sets a task to progress events. - * @return {Object} Status object. - */ -FileOperationManager.Task.prototype.getStatus = function() { - var processingEntry = this.sourceEntries[this.processingSourceIndex_]; - return { - operationType: this.operationType, - numRemainingItems: this.sourceEntries.length - this.processingSourceIndex_, - totalBytes: this.totalBytes, - processedBytes: this.processedBytes, - processingEntryName: processingEntry ? processingEntry.name : '' - }; -}; - -/** - * Obtains the number of total processed bytes. - * @return {number} Number of total processed bytes. - * @private - */ -FileOperationManager.Task.prototype.calcProcessedBytes_ = function() { - var bytes = 0; - for (var i = 0; i < this.processingSourceIndex_ + 1; i++) { - var entryMap = this.processingEntries[i]; - if (!entryMap) - break; - for (var name in entryMap) { - bytes += i < this.processingSourceIndex_ ? - entryMap[name].size : entryMap[name].processedBytes; - } - } - return bytes; -}; - -/** - * Task to copy entries. - * - * @param {Array.<Entry>} sourceEntries Array of source entries. - * @param {DirectoryEntry} targetDirEntry Target directory. - * @param {boolean} deleteAfterCopy Whether the delete original files after - * copy. - * @constructor - * @extends {FileOperationManager.Task} - */ -FileOperationManager.CopyTask = function(sourceEntries, - targetDirEntry, - deleteAfterCopy) { - FileOperationManager.Task.call( - this, - deleteAfterCopy ? - util.FileOperationType.MOVE : util.FileOperationType.COPY, - sourceEntries, - targetDirEntry); - this.deleteAfterCopy = deleteAfterCopy; - - /** - * Rate limiter which is used to avoid sending update request for progress bar - * too frequently. - * @type {AsyncUtil.RateLimiter} - * @private - */ - this.updateProgressRateLimiter_ = null; -}; - -/** - * Extends FileOperationManager.Task. - */ -FileOperationManager.CopyTask.prototype.__proto__ = - FileOperationManager.Task.prototype; - -/** - * Initializes the CopyTask. - * @param {function()} callback Called when the initialize is completed. - */ -FileOperationManager.CopyTask.prototype.initialize = function(callback) { - var group = new AsyncUtil.Group(); - // Correct all entries to be copied for status update. - this.processingEntries = []; - for (var i = 0; i < this.sourceEntries.length; i++) { - group.add(function(index, callback) { - fileOperationUtil.resolveRecursively( - this.sourceEntries[index], - function(resolvedEntries) { - var resolvedEntryMap = {}; - for (var j = 0; j < resolvedEntries.length; ++j) { - var entry = resolvedEntries[j]; - entry.processedBytes = 0; - resolvedEntryMap[entry.toURL()] = entry; - } - this.processingEntries[index] = resolvedEntryMap; - callback(); - }.bind(this), - function(error) { - console.error( - 'Failed to resolve for copy: %s', error.name); - callback(); - }); - }.bind(this, i)); - } - - group.run(function() { - // Fill totalBytes. - this.totalBytes = 0; - for (var i = 0; i < this.processingEntries.length; i++) { - for (var entryURL in this.processingEntries[i]) - this.totalBytes += this.processingEntries[i][entryURL].size; - } - - callback(); - }.bind(this)); -}; - -/** - * Copies all entries to the target directory. - * Note: this method contains also the operation of "Move" due to historical - * reason. - * - * @param {function(util.EntryChangedKind, Entry)} entryChangedCallback - * Callback invoked when an entry is changed. - * @param {function()} progressCallback Callback invoked periodically during - * the copying. - * @param {function()} successCallback On success. - * @param {function(FileOperationManager.Error)} errorCallback On error. - * @override - */ -FileOperationManager.CopyTask.prototype.run = function( - entryChangedCallback, progressCallback, successCallback, errorCallback) { - // TODO(hidehiko): We should be able to share the code to iterate on entries - // with serviceMoveTask_(). - if (this.sourceEntries.length == 0) { - successCallback(); - return; - } - - // TODO(hidehiko): Delete after copy is the implementation of Move. - // Migrate the part into MoveTask.run(). - var deleteOriginals = function() { - var count = this.sourceEntries.length; - - var onEntryDeleted = function(entry) { - entryChangedCallback(util.EntryChangedKind.DELETED, entry); - count--; - if (!count) - successCallback(); - }; - - var onFilesystemError = function(err) { - errorCallback(new FileOperationManager.Error( - util.FileOperationErrorType.FILESYSTEM_ERROR, err)); - }; - - for (var i = 0; i < this.sourceEntries.length; i++) { - var entry = this.sourceEntries[i]; - util.removeFileOrDirectory( - entry, onEntryDeleted.bind(null, entry), onFilesystemError); - } - }.bind(this); - - /** - * Accumulates processed bytes and call |progressCallback| if needed. - * - * @param {number} index The index of processing source. - * @param {string} sourceEntryUrl URL of the entry which has been processed. - * @param {number=} opt_size Processed bytes of the |sourceEntry|. If it is - * dropped, all bytes of the entry are considered to be processed. - */ - var updateProgress = function(index, sourceEntryUrl, opt_size) { - if (!sourceEntryUrl) - return; - - var processedEntry = this.processingEntries[index][sourceEntryUrl]; - if (!processedEntry) - return; - - // Accumulates newly processed bytes. - var size = opt_size !== undefined ? opt_size : processedEntry.size; - this.processedBytes += size - processedEntry.processedBytes; - processedEntry.processedBytes = size; - - // Updates progress bar in limited frequency so that intervals between - // updates have at least 200ms. - this.updateProgressRateLimiter_.run(); - }; - updateProgress = updateProgress.bind(this); - - this.updateProgressRateLimiter_ = new AsyncUtil.RateLimiter(progressCallback); - - AsyncUtil.forEach( - this.sourceEntries, - function(callback, entry, index) { - if (this.cancelRequested_) { - errorCallback(new FileOperationManager.Error( - util.FileOperationErrorType.FILESYSTEM_ERROR, - util.createDOMError(util.FileError.ABORT_ERR))); - return; - } - progressCallback(); - this.processEntry_( - entry, this.targetDirEntry, - function(sourceEntryUrl, destinationEntry) { - updateProgress(index, sourceEntryUrl); - // The destination entry may be null, if the copied file got - // deleted just after copying. - if (destinationEntry) { - entryChangedCallback( - util.EntryChangedKind.CREATED, destinationEntry); - } - }, - function(sourceEntryUrl, size) { - updateProgress(index, sourceEntryUrl, size); - }, - function() { - // Finishes off delayed updates if necessary. - this.updateProgressRateLimiter_.runImmediately(); - // Update current source index and processing bytes. - this.processingSourceIndex_ = index + 1; - this.processedBytes = this.calcProcessedBytes_(); - callback(); - }.bind(this), - function(error) { - // Finishes off delayed updates if necessary. - this.updateProgressRateLimiter_.runImmediately(); - errorCallback(error); - }.bind(this)); - }, - function() { - if (this.deleteAfterCopy) { - deleteOriginals(); - } else { - successCallback(); - } - }.bind(this), - this); -}; - -/** - * Copies the source entry to the target directory. - * - * @param {Entry} sourceEntry An entry to be copied. - * @param {DirectoryEntry} destinationEntry The entry which will contain the - * copied entry. - * @param {function(Entry, Entry)} entryChangedCallback - * Callback invoked when an entry is created with the source Entry and - * the destination Entry. - * @param {function(Entry, number)} progressCallback Callback invoked - * periodically during the copying. - * @param {function()} successCallback On success. - * @param {function(FileOperationManager.Error)} errorCallback On error. - * @private - */ -FileOperationManager.CopyTask.prototype.processEntry_ = function( - sourceEntry, destinationEntry, entryChangedCallback, progressCallback, - successCallback, errorCallback) { - fileOperationUtil.deduplicatePath( - destinationEntry, sourceEntry.name, - function(destinationName) { - if (this.cancelRequested_) { - errorCallback(new FileOperationManager.Error( - util.FileOperationErrorType.FILESYSTEM_ERROR, - util.createDOMError(util.FileError.ABORT_ERR))); - return; - } - this.cancelCallback_ = fileOperationUtil.copyTo( - sourceEntry, destinationEntry, destinationName, - entryChangedCallback, progressCallback, - function(entry) { - this.cancelCallback_ = null; - successCallback(); - }.bind(this), - function(error) { - this.cancelCallback_ = null; - errorCallback(new FileOperationManager.Error( - util.FileOperationErrorType.FILESYSTEM_ERROR, error)); - }.bind(this)); - }.bind(this), - errorCallback); -}; - -/** - * Task to move entries. - * - * @param {Array.<Entry>} sourceEntries Array of source entries. - * @param {DirectoryEntry} targetDirEntry Target directory. - * @constructor - * @extends {FileOperationManager.Task} - */ -FileOperationManager.MoveTask = function(sourceEntries, targetDirEntry) { - FileOperationManager.Task.call( - this, util.FileOperationType.MOVE, sourceEntries, targetDirEntry); -}; - -/** - * Extends FileOperationManager.Task. - */ -FileOperationManager.MoveTask.prototype.__proto__ = - FileOperationManager.Task.prototype; - -/** - * Initializes the MoveTask. - * @param {function()} callback Called when the initialize is completed. - */ -FileOperationManager.MoveTask.prototype.initialize = function(callback) { - // This may be moving from search results, where it fails if we - // move parent entries earlier than child entries. We should - // process the deepest entry first. Since move of each entry is - // done by a single moveTo() call, we don't need to care about the - // recursive traversal order. - this.sourceEntries.sort(function(entry1, entry2) { - return entry2.toURL().length - entry1.toURL().length; - }); - - this.processingEntries = []; - for (var i = 0; i < this.sourceEntries.length; i++) { - var processingEntryMap = {}; - var entry = this.sourceEntries[i]; - - // The move should be done with updating the metadata. So here we assume - // all the file size is 1 byte. (Avoiding 0, so that progress bar can - // move smoothly). - // TODO(hidehiko): Remove this hack. - entry.size = 1; - processingEntryMap[entry.toURL()] = entry; - this.processingEntries[i] = processingEntryMap; - } - - callback(); -}; - -/** - * Moves all entries in the task. - * - * @param {function(util.EntryChangedKind, Entry)} entryChangedCallback - * Callback invoked when an entry is changed. - * @param {function()} progressCallback Callback invoked periodically during - * the moving. - * @param {function()} successCallback On success. - * @param {function(FileOperationManager.Error)} errorCallback On error. - * @override - */ -FileOperationManager.MoveTask.prototype.run = function( - entryChangedCallback, progressCallback, successCallback, errorCallback) { - if (this.sourceEntries.length == 0) { - successCallback(); - return; - } - - AsyncUtil.forEach( - this.sourceEntries, - function(callback, entry, index) { - if (this.cancelRequested_) { - errorCallback(new FileOperationManager.Error( - util.FileOperationErrorType.FILESYSTEM_ERROR, - util.createDOMError(util.FileError.ABORT_ERR))); - return; - } - progressCallback(); - FileOperationManager.MoveTask.processEntry_( - entry, this.targetDirEntry, entryChangedCallback, - function() { - // Update current source index. - this.processingSourceIndex_ = index + 1; - this.processedBytes = this.calcProcessedBytes_(); - callback(); - }.bind(this), - errorCallback); - }, - function() { - successCallback(); - }.bind(this), - this); -}; - -/** - * Moves the sourceEntry to the targetDirEntry in this task. - * - * @param {Entry} sourceEntry An entry to be moved. - * @param {!DirectoryEntry} destinationEntry The entry of the destination - * directory. - * @param {function(util.EntryChangedKind, Entry)} entryChangedCallback - * Callback invoked when an entry is changed. - * @param {function()} successCallback On success. - * @param {function(FileOperationManager.Error)} errorCallback On error. - * @private - */ -FileOperationManager.MoveTask.processEntry_ = function( - sourceEntry, destinationEntry, entryChangedCallback, successCallback, - errorCallback) { - fileOperationUtil.deduplicatePath( - destinationEntry, - sourceEntry.name, - function(destinationName) { - sourceEntry.moveTo( - destinationEntry, destinationName, - function(movedEntry) { - entryChangedCallback(util.EntryChangedKind.CREATED, movedEntry); - entryChangedCallback(util.EntryChangedKind.DELETED, sourceEntry); - successCallback(); - }, - function(error) { - errorCallback(new FileOperationManager.Error( - util.FileOperationErrorType.FILESYSTEM_ERROR, error)); - }); - }, - errorCallback); -}; - -/** - * Task to create a zip archive. - * - * @param {Array.<Entry>} sourceEntries Array of source entries. - * @param {DirectoryEntry} targetDirEntry Target directory. - * @param {DirectoryEntry} zipBaseDirEntry Base directory dealt as a root - * in ZIP archive. - * @constructor - * @extends {FileOperationManager.Task} - */ -FileOperationManager.ZipTask = function( - sourceEntries, targetDirEntry, zipBaseDirEntry) { - FileOperationManager.Task.call( - this, util.FileOperationType.ZIP, sourceEntries, targetDirEntry); - this.zipBaseDirEntry = zipBaseDirEntry; -}; - -/** - * Extends FileOperationManager.Task. - */ -FileOperationManager.ZipTask.prototype.__proto__ = - FileOperationManager.Task.prototype; - - -/** - * Initializes the ZipTask. - * @param {function()} callback Called when the initialize is completed. - */ -FileOperationManager.ZipTask.prototype.initialize = function(callback) { - var resolvedEntryMap = {}; - var group = new AsyncUtil.Group(); - for (var i = 0; i < this.sourceEntries.length; i++) { - group.add(function(index, callback) { - fileOperationUtil.resolveRecursively( - this.sourceEntries[index], - function(entries) { - for (var j = 0; j < entries.length; j++) - resolvedEntryMap[entries[j].toURL()] = entries[j]; - callback(); - }, - callback); - }.bind(this, i)); - } - - group.run(function() { - // For zip archiving, all the entries are processed at once. - this.processingEntries = [resolvedEntryMap]; - - this.totalBytes = 0; - for (var url in resolvedEntryMap) - this.totalBytes += resolvedEntryMap[url].size; - - callback(); - }.bind(this)); -}; - -/** - * Runs a zip file creation task. - * - * @param {function(util.EntryChangedKind, Entry)} entryChangedCallback - * Callback invoked when an entry is changed. - * @param {function()} progressCallback Callback invoked periodically during - * the moving. - * @param {function()} successCallback On complete. - * @param {function(FileOperationManager.Error)} errorCallback On error. - * @override - */ -FileOperationManager.ZipTask.prototype.run = function( - entryChangedCallback, progressCallback, successCallback, errorCallback) { - // TODO(hidehiko): we should localize the name. - var destName = 'Archive'; - if (this.sourceEntries.length == 1) { - var entryName = this.sourceEntries[0].name; - var i = entryName.lastIndexOf('.'); - destName = ((i < 0) ? entryName : entryName.substr(0, i)); - } - - fileOperationUtil.deduplicatePath( - this.targetDirEntry, destName + '.zip', - function(destPath) { - // TODO: per-entry zip progress update with accurate byte count. - // For now just set completedBytes to 0 so that it is not full until - // the zip operatoin is done. - this.processedBytes = 0; - progressCallback(); - - // The number of elements in processingEntries is 1. See also - // initialize(). - var entries = []; - for (var url in this.processingEntries[0]) - entries.push(this.processingEntries[0][url]); - - fileOperationUtil.zipSelection( - entries, - this.zipBaseDirEntry, - destPath, - function(entry) { - this.processedBytes = this.totalBytes; - entryChangedCallback(util.EntryChangedKind.CREATED, entry); - successCallback(); - }.bind(this), - function(error) { - errorCallback(new FileOperationManager.Error( - util.FileOperationErrorType.FILESYSTEM_ERROR, error)); - }); - }.bind(this), - errorCallback); -}; - -/** - * Error class used to report problems with a copy operation. - * If the code is UNEXPECTED_SOURCE_FILE, data should be a path of the file. - * If the code is TARGET_EXISTS, data should be the existing Entry. - * If the code is FILESYSTEM_ERROR, data should be the FileError. - * - * @param {util.FileOperationErrorType} code Error type. - * @param {string|Entry|DOMError} data Additional data. - * @constructor - */ -FileOperationManager.Error = function(code, data) { - this.code = code; - this.data = data; -}; - -// FileOperationManager methods. - -/** * Adds an event listener for the tasks. * @param {string} type The name of the event. * @param {EventListenerType} handler The handler for the event. This is called @@ -1265,21 +276,23 @@ FileOperationManager.prototype.queueCopy_ = function( targetDirEntry, entries, isMove, opt_taskId) { var task; + var taskId = opt_taskId || this.generateTaskId(); if (isMove) { // When moving between different volumes, moving is implemented as a copy // and delete. This is because moving between volumes is slow, and moveTo() // is not cancellable nor provides progress feedback. if (util.isSameFileSystem(entries[0].filesystem, targetDirEntry.filesystem)) { - task = new FileOperationManager.MoveTask(entries, targetDirEntry); + task = new fileOperationUtil.MoveTask(taskId, entries, targetDirEntry); } else { - task = new FileOperationManager.CopyTask(entries, targetDirEntry, true); + task = + new fileOperationUtil.CopyTask(taskId, entries, targetDirEntry, true); } } else { - task = new FileOperationManager.CopyTask(entries, targetDirEntry, false); + task = + new fileOperationUtil.CopyTask(taskId, entries, targetDirEntry, false); } - task.taskId = opt_taskId || this.generateTaskId(); this.eventRouter_.sendProgressEvent('BEGIN', task.getStatus(), task.taskId); task.initialize(function() { this.copyTasks_.push(task); @@ -1353,7 +366,7 @@ * @param {Array.<Entry>} entries The entries. */ FileOperationManager.prototype.deleteEntries = function(entries) { - // TODO(hirono): Make FileOperationManager.DeleteTask. + // TODO(hirono): Make fileOperationUtil.DeleteTask. var task = Object.seal({ entries: entries, taskId: this.generateTaskId(), @@ -1465,10 +478,8 @@ */ FileOperationManager.prototype.zipSelection = function( dirEntry, selectionEntries) { - var zipTask = new FileOperationManager.ZipTask( - selectionEntries, dirEntry, dirEntry); - zipTask.taskId = this.generateTaskId(); - zipTask.zip = true; + var zipTask = new fileOperationUtil.ZipTask( + this.generateTaskId(), selectionEntries, dirEntry, dirEntry); this.eventRouter_.sendProgressEvent('BEGIN', zipTask.getStatus(), zipTask.taskId);
diff --git a/ui/file_manager/file_manager/background/js/file_operation_util.js b/ui/file_manager/file_manager/background/js/file_operation_util.js new file mode 100644 index 0000000..fb0246b --- /dev/null +++ b/ui/file_manager/file_manager/background/js/file_operation_util.js
@@ -0,0 +1,1008 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * Utilities for file operations. + */ +var fileOperationUtil = {}; + +/** + * Resolves a path to either a DirectoryEntry or a FileEntry, regardless of + * whether the path is a directory or file. + * + * @param {DirectoryEntry} root The root of the filesystem to search. + * @param {string} path The path to be resolved. + * @return {Promise} Promise fulfilled with the resolved entry, or rejected with + * FileError. + */ +fileOperationUtil.resolvePath = function(root, path) { + if (path === '' || path === '/') + return Promise.resolve(root); + return new Promise(root.getFile.bind(root, path, {create: false})). + catch(function(error) { + if (error.name === util.FileError.TYPE_MISMATCH_ERR) { + // Bah. It's a directory, ask again. + return new Promise( + root.getDirectory.bind(root, path, {create: false})); + } else { + return Promise.reject(error); + } + }); +}; + +/** + * Checks if an entry exists at |relativePath| in |dirEntry|. + * If exists, tries to deduplicate the path by inserting parenthesized number, + * such as " (1)", before the extension. If it still exists, tries the + * deduplication again by increasing the number up to 10 times. + * For example, suppose "file.txt" is given, "file.txt", "file (1).txt", + * "file (2).txt", ..., "file (9).txt" will be tried. + * + * @param {DirectoryEntry} dirEntry The target directory entry. + * @param {string} relativePath The path to be deduplicated. + * @param {function(string)=} opt_successCallback Callback run with the + * deduplicated path on success. + * @param {function(fileOperationUtil.Error)=} opt_errorCallback Callback run + * on error. + * @return {Promise} Promise fulfilled with available path. + */ +fileOperationUtil.deduplicatePath = function( + dirEntry, relativePath, opt_successCallback, opt_errorCallback) { + // The trial is up to 10. + var MAX_RETRY = 10; + + // Crack the path into three part. The parenthesized number (if exists) will + // be replaced by incremented number for retry. For example, suppose + // |relativePath| is "file (10).txt", the second check path will be + // "file (11).txt". + var match = /^(.*?)(?: \((\d+)\))?(\.[^.]*?)?$/.exec(relativePath); + var prefix = match[1]; + var ext = match[3] || ''; + + // Check to see if the target exists. + var resolvePath = function(trialPath, numRetry, copyNumber) { + return fileOperationUtil.resolvePath(dirEntry, trialPath).then(function() { + if (numRetry <= 1) { + // Hit the limit of the number of retrial. + // Note that we cannot create FileError object directly, so here we + // use Object.create instead. + return Promise.reject( + util.createDOMError(util.FileError.PATH_EXISTS_ERR)); + } + var newTrialPath = prefix + ' (' + copyNumber + ')' + ext; + return resolvePath(newTrialPath, numRetry - 1, copyNumber + 1); + }, function(error) { + // We expect to be unable to resolve the target file, since we're + // going to create it during the copy. However, if the resolve fails + // with anything other than NOT_FOUND, that's trouble. + if (error.name === util.FileError.NOT_FOUND_ERR) + return trialPath; + else + return Promise.reject(error); + }); + }; + + var promise = resolvePath(relativePath, MAX_RETRY, 1).catch(function(error) { + var targetPromise; + if (error.name === util.FileError.PATH_EXISTS_ERR) { + // Failed to uniquify the file path. There should be an existing + // entry, so return the error with it. + targetPromise = fileOperationUtil.resolvePath(dirEntry, relativePath); + } else { + targetPromise = Promise.reject(error); + } + return targetPromise.then(function(entry) { + return Promise.reject(new fileOperationUtil.Error( + util.FileOperationErrorType.TARGET_EXISTS, entry)); + }, function(/** (Error|DOMError) */ inError) { + if (inError instanceof Error) + return Promise.reject(inError); + return Promise.reject(new fileOperationUtil.Error( + util.FileOperationErrorType.FILESYSTEM_ERROR, inError)); + }); + }); + if (opt_successCallback) + promise.then(opt_successCallback, opt_errorCallback); + return promise; +}; + +/** + * Traverses files/subdirectories of the given entry, and returns them. + * In addition, this method annotate the size of each entry. The result will + * include the entry itself. + * + * @param {Entry} entry The root Entry for traversing. + * @param {function(Array.<Entry>)} successCallback Called when the traverse + * is successfully done with the array of the entries. + * @param {function(DOMError)} errorCallback Called on error with the first + * occurred error (i.e. following errors will just be discarded). + */ +fileOperationUtil.resolveRecursively = function( + entry, successCallback, errorCallback) { + var result = []; + var error = null; + var numRunningTasks = 0; + + var maybeInvokeCallback = function() { + // If there still remain some running tasks, wait their finishing. + if (numRunningTasks > 0) + return; + + if (error) + errorCallback(error); + else + successCallback(result); + }; + + // The error handling can be shared. + var onError = function(fileError) { + // If this is the first error, remember it. + if (!error) + error = fileError; + --numRunningTasks; + maybeInvokeCallback(); + }; + + var process = function(entry) { + numRunningTasks++; + result.push(entry); + if (entry.isDirectory) { + // The size of a directory is 1 bytes here, so that the progress bar + // will work smoother. + // TODO(hidehiko): Remove this hack. + entry.size = 1; + + // Recursively traverse children. + var reader = entry.createReader(); + reader.readEntries( + function processSubEntries(subEntries) { + if (error || subEntries.length == 0) { + // If an error is found already, or this is the completion + // callback, then finish the process. + --numRunningTasks; + maybeInvokeCallback(); + return; + } + + for (var i = 0; i < subEntries.length; i++) + process(subEntries[i]); + + // Continue to read remaining children. + reader.readEntries(processSubEntries, onError); + }, + onError); + } else { + // For a file, annotate the file size. + entry.getMetadata(function(metadata) { + entry.size = metadata.size; + --numRunningTasks; + maybeInvokeCallback(); + }, onError); + } + }; + + process(entry); +}; + +/** + * Copies source to parent with the name newName recursively. + * This should work very similar to FileSystem API's copyTo. The difference is; + * - The progress callback is supported. + * - The cancellation is supported. + * + * @param {Entry} source The entry to be copied. + * @param {DirectoryEntry} parent The entry of the destination directory. + * @param {string} newName The name of copied file. + * @param {function(Entry, Entry)} entryChangedCallback + * Callback invoked when an entry is created with the source Entry and + * the destination Entry. + * @param {function(Entry, number)} progressCallback Callback invoked + * periodically during the copying. It takes the source Entry and the + * processed bytes of it. + * @param {function(Entry)} successCallback Callback invoked when the copy + * is successfully done with the Entry of the created entry. + * @param {function(DOMError)} errorCallback Callback invoked when an error + * is found. + * @return {function()} Callback to cancel the current file copy operation. + * When the cancel is done, errorCallback will be called. The returned + * callback must not be called more than once. + */ +fileOperationUtil.copyTo = function( + source, parent, newName, entryChangedCallback, progressCallback, + successCallback, errorCallback) { + var copyId = null; + var pendingCallbacks = []; + + // Makes the callback called in order they were invoked. + var callbackQueue = new AsyncUtil.Queue(); + + var onCopyProgress = function(progressCopyId, status) { + callbackQueue.run(function(callback) { + if (copyId === null) { + // If the copyId is not yet available, wait for it. + pendingCallbacks.push( + onCopyProgress.bind(null, progressCopyId, status)); + callback(); + return; + } + + // This is not what we're interested in. + if (progressCopyId != copyId) { + callback(); + return; + } + + switch (status.type) { + case 'begin_copy_entry': + callback(); + break; + + case 'end_copy_entry': + // TODO(mtomasz): Convert URL to Entry in custom bindings. + (source.isFile ? parent.getFile : parent.getDirectory).call( + parent, + newName, + null, + function(entry) { + entryChangedCallback(status.sourceUrl, entry); + callback(); + }, + function() { + entryChangedCallback(status.sourceUrl, null); + callback(); + }); + break; + + case 'progress': + progressCallback(status.sourceUrl, status.size); + callback(); + break; + + case 'success': + chrome.fileManagerPrivate.onCopyProgress.removeListener( + onCopyProgress); + // TODO(mtomasz): Convert URL to Entry in custom bindings. + util.URLsToEntries( + [status.destinationUrl], function(destinationEntries) { + successCallback(destinationEntries[0] || null); + callback(); + }); + break; + + case 'error': + chrome.fileManagerPrivate.onCopyProgress.removeListener( + onCopyProgress); + errorCallback(util.createDOMError(status.error)); + callback(); + break; + + default: + // Found unknown state. Cancel the task, and return an error. + console.error('Unknown progress type: ' + status.type); + chrome.fileManagerPrivate.onCopyProgress.removeListener( + onCopyProgress); + chrome.fileManagerPrivate.cancelCopy(copyId); + errorCallback(util.createDOMError( + util.FileError.INVALID_STATE_ERR)); + callback(); + } + }); + }; + + // Register the listener before calling startCopy. Otherwise some events + // would be lost. + chrome.fileManagerPrivate.onCopyProgress.addListener(onCopyProgress); + + // Then starts the copy. + // TODO(mtomasz): Convert URL to Entry in custom bindings. + chrome.fileManagerPrivate.startCopy( + source.toURL(), parent.toURL(), newName, function(startCopyId) { + // last error contains the FileError code on error. + if (chrome.runtime.lastError) { + // Unsubscribe the progress listener. + chrome.fileManagerPrivate.onCopyProgress.removeListener( + onCopyProgress); + errorCallback(util.createDOMError( + chrome.runtime.lastError.message || '')); + return; + } + + copyId = startCopyId; + for (var i = 0; i < pendingCallbacks.length; i++) { + pendingCallbacks[i](); + } + }); + + return function() { + // If copyId is not yet available, wait for it. + if (copyId == null) { + pendingCallbacks.push(function() { + chrome.fileManagerPrivate.cancelCopy(copyId); + }); + return; + } + + chrome.fileManagerPrivate.cancelCopy(copyId); + }; +}; + +/** + * Thin wrapper of chrome.fileManagerPrivate.zipSelection to adapt its + * interface similar to copyTo(). + * + * @param {Array.<Entry>} sources The array of entries to be archived. + * @param {DirectoryEntry} parent The entry of the destination directory. + * @param {string} newName The name of the archive to be created. + * @param {function(FileEntry)} successCallback Callback invoked when the + * operation is successfully done with the entry of the created archive. + * @param {function(DOMError)} errorCallback Callback invoked when an error + * is found. + */ +fileOperationUtil.zipSelection = function( + sources, parent, newName, successCallback, errorCallback) { + // TODO(mtomasz): Move conversion from entry to url to custom bindings. + // crbug.com/345527. + chrome.fileManagerPrivate.zipSelection( + parent.toURL(), + util.entriesToURLs(sources), + newName, function(success) { + if (!success) { + // Failed to create a zip archive. + errorCallback( + util.createDOMError(util.FileError.INVALID_MODIFICATION_ERR)); + return; + } + + // Returns the created entry via callback. + parent.getFile( + newName, {create: false}, successCallback, errorCallback); + }); +}; + +/** + * A record of a queued copy operation. + * + * Multiple copy operations may be queued at any given time. Additional + * Tasks may be added while the queue is being serviced. Though a + * cancel operation cancels everything in the queue. + * + * @param {string} taskId A unique ID for identifying this task. + * @param {util.FileOperationType} operationType The type of this operation. + * @param {Array.<Entry>} sourceEntries Array of source entries. + * @param {DirectoryEntry} targetDirEntry Target directory. + * @constructor + * @struct + */ +fileOperationUtil.Task = function( + taskId, operationType, sourceEntries, targetDirEntry) { + /** @type {string} */ + this.taskId = taskId; + + /** @type {util.FileOperationType} */ + this.operationType = operationType; + + /** @type {Array.<Entry>} */ + this.sourceEntries = sourceEntries; + + /** @type {DirectoryEntry} */ + this.targetDirEntry = targetDirEntry; + + /** + * An array of map from url to Entry being processed. + * @type {Array.<Object<string, Entry>>} + */ + this.processingEntries = null; + + /** + * Total number of bytes to be processed. Filled in initialize(). + * Use 1 as an initial value to indicate that the task is not completed. + * @type {number} + */ + this.totalBytes = 1; + + /** + * Total number of already processed bytes. Updated periodically. + * @type {number} + */ + this.processedBytes = 0; + + /** + * Index of the progressing entry in sourceEntries. + * @private {number} + */ + this.processingSourceIndex_ = 0; + + /** + * Set to true when cancel is requested. + * @private {boolean} + */ + this.cancelRequested_ = false; + + /** + * Callback to cancel the running process. + * @private {?function()} + */ + this.cancelCallback_ = null; + + // TODO(hidehiko): After we support recursive copy, we don't need this. + // If directory already exists, we try to make a copy named 'dir (X)', + // where X is a number. When we do this, all subsequent copies from + // inside the subtree should be mapped to the new directory name. + // For example, if 'dir' was copied as 'dir (1)', then 'dir/file.txt' should + // become 'dir (1)/file.txt'. + this.renamedDirectories_ = []; +}; + +/** + * @param {function()} callback When entries resolved. + */ +fileOperationUtil.Task.prototype.initialize = function(callback) { +}; + +/** + * Requests cancellation of this task. + * When the cancellation is done, it is notified via callbacks of run(). + */ +fileOperationUtil.Task.prototype.requestCancel = function() { + this.cancelRequested_ = true; + if (this.cancelCallback_) { + this.cancelCallback_(); + this.cancelCallback_ = null; + } +}; + +/** + * Runs the task. Sub classes must implement this method. + * + * @param {function(util.EntryChangedKind, Entry)} entryChangedCallback + * Callback invoked when an entry is changed. + * @param {function()} progressCallback Callback invoked periodically during + * the operation. + * @param {function()} successCallback Callback run on success. + * @param {function(fileOperationUtil.Error)} errorCallback Callback run on + * error. + */ +fileOperationUtil.Task.prototype.run = function( + entryChangedCallback, progressCallback, successCallback, errorCallback) { +}; + +/** + * Get states of the task. + * TOOD(hirono): Removes this method and sets a task to progress events. + * @return {Object} Status object. + */ +fileOperationUtil.Task.prototype.getStatus = function() { + var processingEntry = this.sourceEntries[this.processingSourceIndex_]; + return { + operationType: this.operationType, + numRemainingItems: this.sourceEntries.length - this.processingSourceIndex_, + totalBytes: this.totalBytes, + processedBytes: this.processedBytes, + processingEntryName: processingEntry ? processingEntry.name : '' + }; +}; + +/** + * Obtains the number of total processed bytes. + * @return {number} Number of total processed bytes. + * @private + */ +fileOperationUtil.Task.prototype.calcProcessedBytes_ = function() { + var bytes = 0; + for (var i = 0; i < this.processingSourceIndex_ + 1; i++) { + var entryMap = this.processingEntries[i]; + if (!entryMap) + break; + for (var name in entryMap) { + bytes += i < this.processingSourceIndex_ ? + entryMap[name].size : entryMap[name].processedBytes; + } + } + return bytes; +}; + +/** + * Task to copy entries. + * + * @param {string} taskId A unique ID for identifying this task. + * @param {Array.<Entry>} sourceEntries Array of source entries. + * @param {DirectoryEntry} targetDirEntry Target directory. + * @param {boolean} deleteAfterCopy Whether the delete original files after + * copy. + * @constructor + * @extends {fileOperationUtil.Task} + * @struct + */ +fileOperationUtil.CopyTask = function( + taskId, sourceEntries, targetDirEntry, deleteAfterCopy) { + fileOperationUtil.Task.call( + this, + taskId, + deleteAfterCopy ? + util.FileOperationType.MOVE : util.FileOperationType.COPY, + sourceEntries, + targetDirEntry); + this.deleteAfterCopy = deleteAfterCopy; + + /** + * Rate limiter which is used to avoid sending update request for progress bar + * too frequently. + * @type {AsyncUtil.RateLimiter} + * @private + */ + this.updateProgressRateLimiter_ = null; +}; + +/** + * Extends fileOperationUtil.Task. + */ +fileOperationUtil.CopyTask.prototype.__proto__ = + fileOperationUtil.Task.prototype; + +/** + * Initializes the CopyTask. + * @param {function()} callback Called when the initialize is completed. + */ +fileOperationUtil.CopyTask.prototype.initialize = function(callback) { + var group = new AsyncUtil.Group(); + // Correct all entries to be copied for status update. + this.processingEntries = []; + for (var i = 0; i < this.sourceEntries.length; i++) { + group.add(function(index, callback) { + fileOperationUtil.resolveRecursively( + this.sourceEntries[index], + function(resolvedEntries) { + var resolvedEntryMap = {}; + for (var j = 0; j < resolvedEntries.length; ++j) { + var entry = resolvedEntries[j]; + entry.processedBytes = 0; + resolvedEntryMap[entry.toURL()] = entry; + } + this.processingEntries[index] = resolvedEntryMap; + callback(); + }.bind(this), + function(error) { + console.error( + 'Failed to resolve for copy: %s', error.name); + callback(); + }); + }.bind(this, i)); + } + + group.run(function() { + // Fill totalBytes. + this.totalBytes = 0; + for (var i = 0; i < this.processingEntries.length; i++) { + for (var entryURL in this.processingEntries[i]) + this.totalBytes += this.processingEntries[i][entryURL].size; + } + + callback(); + }.bind(this)); +}; + +/** + * Copies all entries to the target directory. + * Note: this method contains also the operation of "Move" due to historical + * reason. + * + * @param {function(util.EntryChangedKind, Entry)} entryChangedCallback + * Callback invoked when an entry is changed. + * @param {function()} progressCallback Callback invoked periodically during + * the copying. + * @param {function()} successCallback On success. + * @param {function(fileOperationUtil.Error)} errorCallback On error. + * @override + */ +fileOperationUtil.CopyTask.prototype.run = function( + entryChangedCallback, progressCallback, successCallback, errorCallback) { + // TODO(hidehiko): We should be able to share the code to iterate on entries + // with serviceMoveTask_(). + if (this.sourceEntries.length == 0) { + successCallback(); + return; + } + + // TODO(hidehiko): Delete after copy is the implementation of Move. + // Migrate the part into MoveTask.run(). + var deleteOriginals = function() { + var count = this.sourceEntries.length; + + var onEntryDeleted = function(entry) { + entryChangedCallback(util.EntryChangedKind.DELETED, entry); + count--; + if (!count) + successCallback(); + }; + + var onFilesystemError = function(err) { + errorCallback(new fileOperationUtil.Error( + util.FileOperationErrorType.FILESYSTEM_ERROR, err)); + }; + + for (var i = 0; i < this.sourceEntries.length; i++) { + var entry = this.sourceEntries[i]; + util.removeFileOrDirectory( + entry, onEntryDeleted.bind(null, entry), onFilesystemError); + } + }.bind(this); + + /** + * Accumulates processed bytes and call |progressCallback| if needed. + * + * @param {number} index The index of processing source. + * @param {string} sourceEntryUrl URL of the entry which has been processed. + * @param {number=} opt_size Processed bytes of the |sourceEntry|. If it is + * dropped, all bytes of the entry are considered to be processed. + */ + var updateProgress = function(index, sourceEntryUrl, opt_size) { + if (!sourceEntryUrl) + return; + + var processedEntry = this.processingEntries[index][sourceEntryUrl]; + if (!processedEntry) + return; + + // Accumulates newly processed bytes. + var size = opt_size !== undefined ? opt_size : processedEntry.size; + this.processedBytes += size - processedEntry.processedBytes; + processedEntry.processedBytes = size; + + // Updates progress bar in limited frequency so that intervals between + // updates have at least 200ms. + this.updateProgressRateLimiter_.run(); + }; + updateProgress = updateProgress.bind(this); + + this.updateProgressRateLimiter_ = new AsyncUtil.RateLimiter(progressCallback); + + AsyncUtil.forEach( + this.sourceEntries, + function(callback, entry, index) { + if (this.cancelRequested_) { + errorCallback(new fileOperationUtil.Error( + util.FileOperationErrorType.FILESYSTEM_ERROR, + util.createDOMError(util.FileError.ABORT_ERR))); + return; + } + progressCallback(); + this.processEntry_( + entry, this.targetDirEntry, + function(sourceEntryUrl, destinationEntry) { + updateProgress(index, sourceEntryUrl); + // The destination entry may be null, if the copied file got + // deleted just after copying. + if (destinationEntry) { + entryChangedCallback( + util.EntryChangedKind.CREATED, destinationEntry); + } + }, + function(sourceEntryUrl, size) { + updateProgress(index, sourceEntryUrl, size); + }, + function() { + // Finishes off delayed updates if necessary. + this.updateProgressRateLimiter_.runImmediately(); + // Update current source index and processing bytes. + this.processingSourceIndex_ = index + 1; + this.processedBytes = this.calcProcessedBytes_(); + callback(); + }.bind(this), + function(error) { + // Finishes off delayed updates if necessary. + this.updateProgressRateLimiter_.runImmediately(); + errorCallback(error); + }.bind(this)); + }, + function() { + if (this.deleteAfterCopy) { + deleteOriginals(); + } else { + successCallback(); + } + }.bind(this), + this); +}; + +/** + * Copies the source entry to the target directory. + * + * @param {Entry} sourceEntry An entry to be copied. + * @param {DirectoryEntry} destinationEntry The entry which will contain the + * copied entry. + * @param {function(Entry, Entry)} entryChangedCallback + * Callback invoked when an entry is created with the source Entry and + * the destination Entry. + * @param {function(Entry, number)} progressCallback Callback invoked + * periodically during the copying. + * @param {function()} successCallback On success. + * @param {function(fileOperationUtil.Error)} errorCallback On error. + * @private + */ +fileOperationUtil.CopyTask.prototype.processEntry_ = function( + sourceEntry, destinationEntry, entryChangedCallback, progressCallback, + successCallback, errorCallback) { + fileOperationUtil.deduplicatePath( + destinationEntry, sourceEntry.name, + function(destinationName) { + if (this.cancelRequested_) { + errorCallback(new fileOperationUtil.Error( + util.FileOperationErrorType.FILESYSTEM_ERROR, + util.createDOMError(util.FileError.ABORT_ERR))); + return; + } + this.cancelCallback_ = fileOperationUtil.copyTo( + sourceEntry, destinationEntry, destinationName, + entryChangedCallback, progressCallback, + function(entry) { + this.cancelCallback_ = null; + successCallback(); + }.bind(this), + function(error) { + this.cancelCallback_ = null; + errorCallback(new fileOperationUtil.Error( + util.FileOperationErrorType.FILESYSTEM_ERROR, error)); + }.bind(this)); + }.bind(this), + errorCallback); +}; + +/** + * Task to move entries. + * + * @param {string} taskId A unique ID for identifying this task. + * @param {Array.<Entry>} sourceEntries Array of source entries. + * @param {DirectoryEntry} targetDirEntry Target directory. + * @constructor + * @extends {fileOperationUtil.Task} + * @struct + */ +fileOperationUtil.MoveTask = function(taskId, sourceEntries, targetDirEntry) { + fileOperationUtil.Task.call( + this, taskId, util.FileOperationType.MOVE, sourceEntries, targetDirEntry); +}; + +/** + * Extends fileOperationUtil.Task. + */ +fileOperationUtil.MoveTask.prototype.__proto__ = + fileOperationUtil.Task.prototype; + +/** + * Initializes the MoveTask. + * @param {function()} callback Called when the initialize is completed. + */ +fileOperationUtil.MoveTask.prototype.initialize = function(callback) { + // This may be moving from search results, where it fails if we + // move parent entries earlier than child entries. We should + // process the deepest entry first. Since move of each entry is + // done by a single moveTo() call, we don't need to care about the + // recursive traversal order. + this.sourceEntries.sort(function(entry1, entry2) { + return entry2.toURL().length - entry1.toURL().length; + }); + + this.processingEntries = []; + for (var i = 0; i < this.sourceEntries.length; i++) { + var processingEntryMap = {}; + var entry = this.sourceEntries[i]; + + // The move should be done with updating the metadata. So here we assume + // all the file size is 1 byte. (Avoiding 0, so that progress bar can + // move smoothly). + // TODO(hidehiko): Remove this hack. + entry.size = 1; + processingEntryMap[entry.toURL()] = entry; + this.processingEntries[i] = processingEntryMap; + } + + callback(); +}; + +/** + * Moves all entries in the task. + * + * @param {function(util.EntryChangedKind, Entry)} entryChangedCallback + * Callback invoked when an entry is changed. + * @param {function()} progressCallback Callback invoked periodically during + * the moving. + * @param {function()} successCallback On success. + * @param {function(fileOperationUtil.Error)} errorCallback On error. + * @override + */ +fileOperationUtil.MoveTask.prototype.run = function( + entryChangedCallback, progressCallback, successCallback, errorCallback) { + if (this.sourceEntries.length == 0) { + successCallback(); + return; + } + + AsyncUtil.forEach( + this.sourceEntries, + function(callback, entry, index) { + if (this.cancelRequested_) { + errorCallback(new fileOperationUtil.Error( + util.FileOperationErrorType.FILESYSTEM_ERROR, + util.createDOMError(util.FileError.ABORT_ERR))); + return; + } + progressCallback(); + fileOperationUtil.MoveTask.processEntry_( + entry, this.targetDirEntry, entryChangedCallback, + function() { + // Update current source index. + this.processingSourceIndex_ = index + 1; + this.processedBytes = this.calcProcessedBytes_(); + callback(); + }.bind(this), + errorCallback); + }, + function() { + successCallback(); + }.bind(this), + this); +}; + +/** + * Moves the sourceEntry to the targetDirEntry in this task. + * + * @param {Entry} sourceEntry An entry to be moved. + * @param {!DirectoryEntry} destinationEntry The entry of the destination + * directory. + * @param {function(util.EntryChangedKind, Entry)} entryChangedCallback + * Callback invoked when an entry is changed. + * @param {function()} successCallback On success. + * @param {function(fileOperationUtil.Error)} errorCallback On error. + * @private + */ +fileOperationUtil.MoveTask.processEntry_ = function( + sourceEntry, destinationEntry, entryChangedCallback, successCallback, + errorCallback) { + fileOperationUtil.deduplicatePath( + destinationEntry, + sourceEntry.name, + function(destinationName) { + sourceEntry.moveTo( + destinationEntry, destinationName, + function(movedEntry) { + entryChangedCallback(util.EntryChangedKind.CREATED, movedEntry); + entryChangedCallback(util.EntryChangedKind.DELETED, sourceEntry); + successCallback(); + }, + function(error) { + errorCallback(new fileOperationUtil.Error( + util.FileOperationErrorType.FILESYSTEM_ERROR, error)); + }); + }, + errorCallback); +}; + +/** + * Task to create a zip archive. + * + * @param {string} taskId A unique ID for identifying this task. + * @param {Array.<Entry>} sourceEntries Array of source entries. + * @param {DirectoryEntry} targetDirEntry Target directory. + * @param {DirectoryEntry} zipBaseDirEntry Base directory dealt as a root + * in ZIP archive. + * @constructor + * @extends {fileOperationUtil.Task} + * @struct + */ +fileOperationUtil.ZipTask = function( + taskId, sourceEntries, targetDirEntry, zipBaseDirEntry) { + fileOperationUtil.Task.call( + this, taskId, util.FileOperationType.ZIP, sourceEntries, targetDirEntry); + this.zipBaseDirEntry = zipBaseDirEntry; + + /** @type {boolean} */ + this.zip = true; +}; + +/** + * Extends fileOperationUtil.Task. + */ +fileOperationUtil.ZipTask.prototype.__proto__ = + fileOperationUtil.Task.prototype; + + +/** + * Initializes the ZipTask. + * @param {function()} callback Called when the initialize is completed. + */ +fileOperationUtil.ZipTask.prototype.initialize = function(callback) { + var resolvedEntryMap = {}; + var group = new AsyncUtil.Group(); + for (var i = 0; i < this.sourceEntries.length; i++) { + group.add(function(index, callback) { + fileOperationUtil.resolveRecursively( + this.sourceEntries[index], + function(entries) { + for (var j = 0; j < entries.length; j++) + resolvedEntryMap[entries[j].toURL()] = entries[j]; + callback(); + }, + callback); + }.bind(this, i)); + } + + group.run(function() { + // For zip archiving, all the entries are processed at once. + this.processingEntries = [resolvedEntryMap]; + + this.totalBytes = 0; + for (var url in resolvedEntryMap) + this.totalBytes += resolvedEntryMap[url].size; + + callback(); + }.bind(this)); +}; + +/** + * Runs a zip file creation task. + * + * @param {function(util.EntryChangedKind, Entry)} entryChangedCallback + * Callback invoked when an entry is changed. + * @param {function()} progressCallback Callback invoked periodically during + * the moving. + * @param {function()} successCallback On complete. + * @param {function(fileOperationUtil.Error)} errorCallback On error. + * @override + */ +fileOperationUtil.ZipTask.prototype.run = function( + entryChangedCallback, progressCallback, successCallback, errorCallback) { + // TODO(hidehiko): we should localize the name. + var destName = 'Archive'; + if (this.sourceEntries.length == 1) { + var entryName = this.sourceEntries[0].name; + var i = entryName.lastIndexOf('.'); + destName = ((i < 0) ? entryName : entryName.substr(0, i)); + } + + fileOperationUtil.deduplicatePath( + this.targetDirEntry, destName + '.zip', + function(destPath) { + // TODO: per-entry zip progress update with accurate byte count. + // For now just set completedBytes to 0 so that it is not full until + // the zip operatoin is done. + this.processedBytes = 0; + progressCallback(); + + // The number of elements in processingEntries is 1. See also + // initialize(). + var entries = []; + for (var url in this.processingEntries[0]) + entries.push(this.processingEntries[0][url]); + + fileOperationUtil.zipSelection( + entries, + this.zipBaseDirEntry, + destPath, + function(entry) { + this.processedBytes = this.totalBytes; + entryChangedCallback(util.EntryChangedKind.CREATED, entry); + successCallback(); + }.bind(this), + function(error) { + errorCallback(new fileOperationUtil.Error( + util.FileOperationErrorType.FILESYSTEM_ERROR, error)); + }); + }.bind(this), + errorCallback); +}; + +/** + * Error class used to report problems with a copy operation. + * If the code is UNEXPECTED_SOURCE_FILE, data should be a path of the file. + * If the code is TARGET_EXISTS, data should be the existing Entry. + * If the code is FILESYSTEM_ERROR, data should be the FileError. + * + * @param {util.FileOperationErrorType} code Error type. + * @param {string|Entry|DOMError} data Additional data. + * @constructor + */ +fileOperationUtil.Error = function(code, data) { + this.code = code; + this.data = data; +};
diff --git a/ui/file_manager/file_manager/background/js/volume_manager.js b/ui/file_manager/file_manager/background/js/volume_manager.js index f472b78..a3f8236 100644 --- a/ui/file_manager/file_manager/background/js/volume_manager.js +++ b/ui/file_manager/file_manager/background/js/volume_manager.js
@@ -6,6 +6,8 @@ * Represents each volume, such as "drive", "download directory", each "USB * flush storage", or "mounted zip archive" etc. * + * @constructor + * * @param {VolumeManagerCommon.VolumeType} volumeType The type of the volume. * @param {string} volumeId ID of the volume. * @param {FileSystem} fileSystem The file system object for this volume. @@ -21,7 +23,8 @@ * @param {string} label Label of the volume. * @param {(string|undefined)} extensionId Id of the extension providing this * volume. Empty for native volumes. - * @constructor + * @param {boolean} hasMedia When true the volume has been identified + * as containing media such as photos or videos. */ function VolumeInfo( volumeType, @@ -33,7 +36,8 @@ isReadOnly, profile, label, - extensionId) { + extensionId, + hasMedia) { this.volumeType_ = volumeType; this.volumeId_ = volumeId; this.fileSystem_ = fileSystem; @@ -71,6 +75,7 @@ this.isReadOnly_ = isReadOnly; this.profile_ = Object.freeze(profile); this.extensionId_ = extensionId; + this.hasMedia_ = hasMedia; Object.seal(this); } @@ -148,10 +153,25 @@ */ get extensionId() { return this.extensionId_; + }, + /** + * @return {boolean} True if the volume contains media. + */ + get hasMedia() { + return this.hasMedia_; } }; /** + * Provides short hand checking of volume type. + * @param {VolumeManagerCommon.VolumeType} type + * @return {boolean} True if the volume is of the specified type. + */ +VolumeInfo.prototype.isType = function(type) { + return type === this.volumeType_; +}; + +/** * Starts resolving the display root and obtains it. It may take long time for * Drive. Once resolved, it is cached. * @@ -247,7 +267,8 @@ volumeMetadata.isReadOnly, volumeMetadata.profile, localizedLabel, - volumeMetadata.extensionId)); + volumeMetadata.extensionId, + volumeMetadata.hasMedia)); return; } @@ -277,7 +298,8 @@ volumeMetadata.isReadOnly, volumeMetadata.profile, localizedLabel, - volumeMetadata.extensionId)); + volumeMetadata.extensionId, + volumeMetadata.hasMedia)); }); };
diff --git a/ui/file_manager/file_manager/common/js/externs.js b/ui/file_manager/file_manager/common/js/externs.js index 4eaf8f3..b3854a4 100644 --- a/ui/file_manager/file_manager/common/js/externs.js +++ b/ui/file_manager/file_manager/common/js/externs.js
@@ -37,7 +37,7 @@ /** @type {string} */ FileOperationProgressEvent.prototype.reason; -/** @type {(FileOperationManager.Error|undefined)} */ +/** @type {(fileOperationUtil.Error|undefined)} */ FileOperationProgressEvent.prototype.error;
diff --git a/ui/file_manager/file_manager/common/js/importer_common.js b/ui/file_manager/file_manager/common/js/importer_common.js index c0d8f8ee..ea6faa2 100644 --- a/ui/file_manager/file_manager/common/js/importer_common.js +++ b/ui/file_manager/file_manager/common/js/importer_common.js
@@ -15,30 +15,75 @@ /** * Returns true if the entry is cloud import eligible. * + * @param {VolumeManagerCommon.VolumeInfoProvider} volumeInfoProvider * @param {Entry} entry - * @param {!VolumeManagerCommon.VolumeInfoProvider} volumeInfoProvider * @return {boolean} */ -importer.isEligibleEntry = function(entry, volumeInfoProvider) { - // TODO(smckay): Check that entry is for media type. - if (entry && entry.isFile) { - var info = volumeInfoProvider.getVolumeInfo(entry); - if (info && info.volumeType == VolumeManagerCommon.VolumeType.REMOVABLE) { - return entry.fullPath.indexOf('/DCIM/') == 0; +importer.isEligibleEntry = function(volumeInfoProvider, entry) { + assert(volumeInfoProvider != null); + if (entry && entry.isFile && FileType.isImageOrVideo(entry)) { + var volumeInfo = volumeInfoProvider.getVolumeInfo(entry); + if (volumeInfo && + volumeInfo.volumeType == VolumeManagerCommon.VolumeType.REMOVABLE) { + return entry.fullPath.indexOf('/DCIM/') === 0; } } return false; }; /** + * Returns true if the entry represents a media directory for the purposes + * of cloud import. + * + * @param {Entry} entry + * @param {VolumeManagerCommon.VolumeInfoProvider} volumeInfoProvider + * @return {boolean} + */ +importer.isMediaDirectory = function(entry, volumeInfoProvider) { + if (!entry || !entry.isDirectory || !entry.fullPath) { + return false; + } + + if (entry.fullPath !== '/DCIM') { + return false; + } + + assert(volumeInfoProvider != null); + var volumeInfo = volumeInfoProvider.getVolumeInfo(entry); + return !!volumeInfo && + volumeInfo.isType(VolumeManagerCommon.VolumeType.REMOVABLE) && + volumeInfo.hasMedia; +}; + +/** * @return {!Promise.<boolean>} Resolves with true when Cloud Import feature * is enabled. */ importer.importEnabled = function() { + // TODO(smckay): Also verify that Drive is enabled and we're + // not running in guest mode. return new Promise( function(resolve, reject) { chrome.commandLinePrivate.hasSwitch( 'enable-cloud-backup', - resolve); + /** + * @param {boolean} enabled + */ + function(enabled) { + importer.lastKnownImportEnabled = enabled; + resolve(enabled); + }); }); }; + +/** + * The last known state for the cloud import feature being enabled. + * + * <p>NOTE: The "command" framework is fully synchronous, meaning + * we have to answer questions, like "can execute" synchronously. + * For this reason we cache the last result from importer.importEnabled(). + * It might be wrong once, but it won't be wrong for long. + * + * @type {boolean} + */ +importer.lastKnownImportEnabled = false;
diff --git a/ui/file_manager/file_manager/foreground/js/compiled_resources.gyp b/ui/file_manager/file_manager/foreground/js/compiled_resources.gyp index c84fdc5..831561a 100644 --- a/ui/file_manager/file_manager/foreground/js/compiled_resources.gyp +++ b/ui/file_manager/file_manager/foreground/js/compiled_resources.gyp
@@ -47,6 +47,7 @@ '../../common/js/util.js', '../../common/js/progress_center_common.js', '../../background/js/file_operation_manager.js', + '../../background/js/file_operation_util.js', '../../background/js/file_operation_handler.js', '../../background/js/device_handler.js', '../../background/js/drive_sync_handler.js',
diff --git a/ui/file_manager/file_manager/foreground/js/dialog_action_controller.js b/ui/file_manager/file_manager/foreground/js/dialog_action_controller.js index 369161c..300a193 100644 --- a/ui/file_manager/file_manager/foreground/js/dialog_action_controller.js +++ b/ui/file_manager/file_manager/foreground/js/dialog_action_controller.js
@@ -116,7 +116,8 @@ dialogFooter.filenameInput.addEventListener( 'input', this.updateOkButton_.bind(this)); fileSelectionHandler.addEventListener( - 'change', this.onFileSelectionChanged_.bind(this)); + FileSelectionHandler.EventType.CHANGE_THROTTLED, + this.onFileSelectionChanged_.bind(this)); dialogFooter.initFileTypeFilter( this.fileTypes_, launchParam.includeAllFiles); @@ -411,7 +412,13 @@ this.dialogFooter_.filenameInput.value = selection.entries[0].name; } - this.updateOkButton_(); + selection.completeInit().then(function() { + if (this.fileSelectionHandler_.selection !== selection) + return; + this.updateOkButton_(); + if (!this.dialogFooter_.okButton.disabled) + util.testSendMessage('dialog-ready'); + }.bind(this)); }; /** @@ -442,27 +449,19 @@ return; } - var isDriveOffline = - this.volumeManager_.getDriveConnectionState().type === - VolumeManagerCommon.DriveConnectionType.OFFLINE; - var filesAvailable = - !this.directoryModel_.isOnDrive() || - !isDriveOffline || - selection.allDriveFilesPresent; - if (this.dialogType_ === DialogType.SELECT_OPEN_FILE) { this.dialogFooter_.okButton.disabled = - !filesAvailable || selection.directoryCount !== 0 || - selection.fileCount !== 1; + selection.fileCount !== 1 || + !this.fileSelectionHandler_.isAvailable(); return; } if (this.dialogType_ === DialogType.SELECT_OPEN_MULTI_FILE) { this.dialogFooter_.okButton.disabled = - !filesAvailable || selection.directoryCount !== 0 || - selection.fileCount === 0; + selection.fileCount === 0 || + !this.fileSelectionHandler_.isAvailable(); return; }
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager.js b/ui/file_manager/file_manager/foreground/js/file_manager.js index 5ce128d3..3b42382 100644 --- a/ui/file_manager/file_manager/foreground/js/file_manager.js +++ b/ui/file_manager/file_manager/foreground/js/file_manager.js
@@ -236,13 +236,6 @@ */ this.initializeQueue_ = new AsyncUtil.Group(); - /** - * Count of the SourceNotFound error. - * @type {number} - * @private - */ - this.sourceNotFoundErrorCount_ = 0; - // Object.seal() has big performance/memory overhead for now, so we use // Object.preventExtensions() here. crbug.com/412239. Object.preventExtensions(this); @@ -311,6 +304,12 @@ return this.historyLoader_; }, /** + * @return {MetadataCache} + */ + get metadataCache() { + return this.metadataCache_; + }, + /** * @return {FileManagerUI} */ get ui() { @@ -482,43 +481,17 @@ if (this.dialogType != DialogType.FULL_PAGE) return; - var controller = this.fileTransferController_ = - new FileTransferController( - this.document_, - this.fileOperationManager_, - this.metadataCache_, - this.directoryModel_, - this.volumeManager_, - this.ui_.multiProfileShareDialog, - this.backgroundPage_.background.progressCenter); - controller.attachDragSource(this.ui_.listContainer.table.list); - controller.attachFileListDropTarget(this.ui_.listContainer.table.list); - controller.attachDragSource(this.ui_.listContainer.grid); - controller.attachFileListDropTarget(this.ui_.listContainer.grid); - controller.attachTreeDropTarget(this.ui_.directoryTree); - controller.attachCopyPasteHandlers(); - controller.addEventListener('selection-copied', - this.blinkSelection.bind(this)); - controller.addEventListener('selection-cut', - this.blinkSelection.bind(this)); - controller.addEventListener('source-not-found', - this.onSourceNotFound_.bind(this)); - }; - - /** - * Handles an error that the source entry of file operation is not found. - * @private - */ - FileManager.prototype.onSourceNotFound_ = function(event) { - var item = new ProgressCenterItem(); - item.id = 'source-not-found-' + this.sourceNotFoundErrorCount_; - if (event.progressType === ProgressItemType.COPY) - item.message = strf('COPY_SOURCE_NOT_FOUND_ERROR', event.fileName); - else if (event.progressType === ProgressItemType.MOVE) - item.message = strf('MOVE_SOURCE_NOT_FOUND_ERROR', event.fileName); - item.state = ProgressItemState.ERROR; - this.backgroundPage_.background.progressCenter.updateItem(item); - this.sourceNotFoundErrorCount_++; + this.fileTransferController_ = new FileTransferController( + assert(this.document_), + assert(this.ui_.listContainer), + assert(this.ui_.directoryTree), + this.ui_.multiProfileShareDialog, + assert(this.backgroundPage_.background.progressCenter), + assert(this.fileOperationManager_), + assert(this.metadataCache_), + assert(this.directoryModel_), + assert(this.volumeManager_), + assert(this.selectionHandler_)); }; /** @@ -637,6 +610,11 @@ // Initialize the member variables that depend this.launchParams_. this.dialogType = this.launchParams_.type; + + // Kick the import enabled promise to be sure it is loaded + // (and cached) for use by code that requires synchronous + // access (e.g. Commands). + importer.importEnabled(); callback(); }; @@ -779,7 +757,8 @@ PreviewPanel.VisibilityType.AUTO, this.metadataCache_, this.volumeManager_, - this.historyLoader_), + this.historyLoader_, + this.isCommandEnabled_.bind(this)), new LocationLine( queryRequiredElement(dom, '#location-breadcrumbs'), queryRequiredElement(dom, '#location-volume-icon'), @@ -1269,35 +1248,6 @@ }; /** - * Blinks the selection. Used to give feedback when copying or cutting the - * selection. - */ - FileManager.prototype.blinkSelection = function() { - var selection = this.getSelection(); - if (!selection || selection.totalCount == 0) - return; - - for (var i = 0; i < selection.entries.length; i++) { - var selectedIndex = selection.indexes[i]; - var listItem = - this.ui.listContainer.currentList.getListItemByIndex(selectedIndex); - if (listItem) - this.blinkListItem_(listItem); - } - }; - - /** - * @param {Element} listItem List item element. - * @private - */ - FileManager.prototype.blinkListItem_ = function(listItem) { - listItem.classList.add('blink'); - setTimeout(function() { - listItem.classList.remove('blink'); - }, 100); - }; - - /** * @private */ FileManager.prototype.dispatchSelectionAction_ = function() { @@ -1469,6 +1419,27 @@ }; /** + * Returns true if the command is known to be enabled according + * to the command handler. + * + * <p>NOTE: This delegating method is necessary as the consumer + * (PreviewPanel) is initialized prior to the CommandHandler. + * This allows us to inject a "command enabled" check function + * into PreviewPanel. + * TODO(mtomasz): Refactor to initialize PreviewPanel after CommandHandler, + * then directly inject the check using CommandHandler.isCommandEnabled. + * See crbug.com/436957. + * + * @param {string} id Command id. + * @return {boolean} True if the command is known to be enabled (very + * recently). + * @private + */ + FileManager.prototype.isCommandEnabled_ = function(id) { + return !!this.commandHandler && this.commandHandler.isCommandEnabled(id); + }; + + /** * @return {!cr.ui.List} Current list object. */ FileManager.prototype.getCurrentList = function() {
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js index ecb5281..22359ed 100644 --- a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js +++ b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
@@ -107,23 +107,6 @@ }; /** - * Returns a single selected/passed entry or null. - * @param {!Event} event Command event. - * @param {!FileManager} fileManager FileManager to use. - * @return {FileEntry} The entry or null. - */ -CommandUtil.getSingleEntry = function(event, fileManager) { - if (event.target.entry) { - return event.target.entry; - } - var selection = fileManager.getSelection(); - if (selection.totalCount == 1) { - return selection.entries[0]; - } - return null; -}; - -/** * Obtains target entries that can be pinned from the selection. * If directories are included in the selection, it just returns an empty * array to avoid confusing because pinning directory is not supported @@ -236,7 +219,7 @@ return null; if (!selection.entries[0].isDirectory) return null; - return selection.entries[0]; + return /** @type {!DirectoryEntry} */(selection.entries[0]); }; /** @@ -288,6 +271,16 @@ }; /** + * @param {string} id Command id + * @return {boolean} True if the specified command was "very recently" + * known to be enabled. + */ +CommandHandler.prototype.isCommandEnabled = function(id) { + var command = this.commands_[id]; + return !!command && !command.disabled; +}; + +/** * Checks if the handler should ignore the current event, eg. since there is * a popup dialog currently opened. * @@ -1037,6 +1030,57 @@ }); /** + * Initiates cloud import. + * @type {Command} + */ +CommandHandler.COMMANDS_['cloud-import'] = /** @type {Command} */ ({ + /** + * @param {!Event} event Command event. + * @param {!FileManager} fileManager FileManager to use. + */ + execute: function(event, fileManager) { + // TODO(smckay): Initiate import. + }, + /** + * @param {!Event} event Command event. + * @param {!FileManager} fileManager FileManager to use. + */ + canExecute: function(event, fileManager) { + + /** + * @return {boolean} True if CloudImport is enabled and + * applicable to the current location and/or selection. + */ + var isCloudImportEnabled = function() { + if (!importer.lastKnownImportEnabled) { + return false; + } + + var entries = fileManager.getSelection().entries; + + // Enabled if user has a selection and it consists entirely of files + // that: + // 1) are of a recognized media type + // 2) reside on a removable media device + // 3) in the DCIM dir + if (entries.length) { + return entries.every( + importer.isEligibleEntry.bind(null, fileManager.volumeManager)); + } + + // Enabled if the current dir is the DCIM dir on a removable media device. + return importer.isMediaDirectory( + fileManager.getCurrentDirectoryEntry(), + fileManager.volumeManager); + }; + + event.command.label = str('CLOUD_IMPORT_BUTTON_LABEL'); + event.canExecute = isCloudImportEnabled(); + event.command.setHidden(!event.canExecute); + } +}); + +/** * Creates a shortcut of the selected folder (single only). * @type {Command} */
diff --git a/ui/file_manager/file_manager/foreground/js/file_selection.js b/ui/file_manager/file_manager/foreground/js/file_selection.js index 354df0eb..50d05302 100644 --- a/ui/file_manager/file_manager/foreground/js/file_selection.js +++ b/ui/file_manager/file_manager/foreground/js/file_selection.js
@@ -5,26 +5,99 @@ /** * The current selection object. * - * @param {FileManager} fileManager FileManager instance. - * @param {Array.<number>} indexes Selected indexes. + * @param {!FileManager} fileManager FileManager instance. + * @param {!Array.<number>} indexes Selected indexes. * @constructor + * @struct */ function FileSelection(fileManager, indexes) { + /** + * @type {!FileManager} + * @private + * @const + */ this.fileManager_ = fileManager; + + /** + * @type {number} + * @private + */ this.computeBytesSequence_ = 0; + + /** + * @type {!Array.<number>} + * @const + */ this.indexes = indexes; + + /** + * @type {!Array.<!Entry>} + * @const + */ this.entries = []; + + /** + * @type {number} + */ this.totalCount = 0; + + /** + * @type {number} + */ this.fileCount = 0; + + /** + * @type {number} + */ this.directoryCount = 0; + + /** + * @type {number} + */ this.bytes = 0; + + /** + * @type {boolean} + */ this.showBytes = false; - this.allDriveFilesPresent = false, + + /** + * @type {boolean} + */ + this.allDriveFilesPresent = false; + + /** + * @type {?string} + */ this.iconType = null; + + /** + * @type {boolean} + */ this.bytesKnown = false; + + /** + * @type {boolean} + * @private + */ this.mustBeHidden_ = false; + + /** + * @type {Array.<string>} + */ this.mimeTypes = null; + /** + * @type {!FileTasks} + */ + this.tasks = new FileTasks(this.fileManager_); + + /** + * @type {Promise} + * @private + */ + this.asyncInitPromise_ = null; + // Synchronously compute what we can. for (var i = 0; i < this.indexes.length; i++) { var entry = /** @type {!Entry} */ @@ -49,39 +122,36 @@ } this.totalCount++; } - - this.tasks = new FileTasks(this.fileManager_); - - Object.seal(this); } /** * Computes data required to get file tasks and requests the tasks. - * - * @param {function()} callback The callback. + * @return {!Promise} */ -FileSelection.prototype.createTasks = function(callback) { - if (!this.fileManager_.isOnDrive()) { - this.tasks.init(this.entries); - callback(); - return; - } - - this.fileManager_.metadataCache_.get( - this.entries, 'external', function(props) { +FileSelection.prototype.completeInit = function() { + if (!this.asyncInitPromise_) { + if (!this.fileManager_.isOnDrive()) { + this.asyncInitPromise_ = Promise.resolve(); + this.tasks.init(this.entries); + this.allDriveFilesPresent = true; + } else { + this.asyncInitPromise_ = new Promise(function(fulfill) { + this.fileManager_.metadataCache.get(this.entries, 'external', fulfill); + }.bind(this)).then(function(props) { var present = props.filter(function(p) { return p && p.availableOffline; }); this.allDriveFilesPresent = present.length == props.length; - - // Collect all of the mime types and push that info into the selection. + // Collect all of the mime types and push that info into the + // selection. this.mimeTypes = props.map(function(value) { return (value && value.contentMimeType) || ''; }); - this.tasks.init(this.entries, this.mimeTypes); - callback(); }.bind(this)); + } + } + return this.asyncInitPromise_; }; /** @@ -150,7 +220,7 @@ /** * This object encapsulates everything related to current selection. * - * @param {FileManager} fileManager File manager instance. + * @param {!FileManager} fileManager File manager instance. * @extends {cr.EventTarget} * @constructor * @struct @@ -187,6 +257,23 @@ } /** + * @enum {string} + */ +FileSelectionHandler.EventType = { + /** + * Dispatched every time when selection is changed. + */ + CHANGE: 'change', + + /** + * Dispatched 200ms later after the selecton is changed. + * If multiple changes are happened during the term, only one CHANGE_THROTTLED + * event is dispatched. + */ + CHANGE_THROTTLED: 'changethrottled' +}; + +/** * Create the temporary disabled action item. * @return {Object} Created disabled item. * @private @@ -275,25 +362,27 @@ this.selectionUpdateTimer_ = setTimeout(function() { this.selectionUpdateTimer_ = null; if (this.selection == selection) - this.updateFileSelectionAsync(selection); + this.updateFileSelectionAsync_(selection); }.bind(this), updateDelay); - cr.dispatchSimpleEvent(this, 'change'); + cr.dispatchSimpleEvent(this, FileSelectionHandler.EventType.CHANGE); }; /** * Calculates async selection stats and updates secondary UI elements. * * @param {FileSelection} selection The selection object. + * @private */ -FileSelectionHandler.prototype.updateFileSelectionAsync = function(selection) { - if (this.selection != selection) return; +FileSelectionHandler.prototype.updateFileSelectionAsync_ = function(selection) { + if (this.selection !== selection) + return; // Update the file tasks. if (this.fileManager_.dialogType === DialogType.FULL_PAGE && selection.directoryCount === 0 && selection.fileCount > 0) { - selection.createTasks(function() { - if (this.selection != selection) + selection.completeInit().then(function() { + if (this.selection !== selection) return; selection.tasks.display(this.taskMenuButton_); selection.tasks.updateMenuItem(); @@ -316,7 +405,17 @@ if (this.fileManager_.commandHandler) this.fileManager_.commandHandler.updateAvailability(); - // Inform tests it's OK to click buttons now. - if (selection.totalCount > 0) - util.testSendMessage('selection-change-complete'); + cr.dispatchSimpleEvent(this, FileSelectionHandler.EventType.CHANGE_THROTTLED); +}; + +/** + * Returns whether all the selected files are available currently or not. + * Should be called after the selection initialized. + * @return {boolean} + */ +FileSelectionHandler.prototype.isAvailable = function() { + return !this.fileManager_.isOnDrive() || + this.fileManager_.volumeManager.getDriveConnectionState().type !== + VolumeManagerCommon.DriveConnectionType.OFFLINE || + this.selection.allDriveFilesPresent; };
diff --git a/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js b/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js index 6a4a5b2..8d33ce7a 100644 --- a/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js +++ b/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js
@@ -16,43 +16,93 @@ var FileAsyncData; /** - * @param {HTMLDocument} doc Owning document. - * @param {FileOperationManager} fileOperationManager File operation manager - * instance. - * @param {MetadataCache} metadataCache Metadata cache service. - * @param {DirectoryModel} directoryModel Directory model instance. - * @param {VolumeManagerWrapper} volumeManager Volume manager instance. - * @param {MultiProfileShareDialog} multiProfileShareDialog Share dialog to be + * @param {!HTMLDocument} doc Owning document. + * @param {!DirectoryTree} directoryTree Directory tree. + * @param {!ListContainer} listContainer List container. + * @param {!MultiProfileShareDialog} multiProfileShareDialog Share dialog to be * used to share files from another profile. - * @param {ProgressCenter} progressCenter To notify starting copy operation. + * @param {!ProgressCenter} progressCenter To notify starting copy operation. + * @param {!FileOperationManager} fileOperationManager File operation manager + * instance. + * @param {!MetadataCache} metadataCache Metadata cache service. + * @param {!DirectoryModel} directoryModel Directory model instance. + * @param {!VolumeManagerWrapper} volumeManager Volume manager instance. + * @param {!FileSelectionHandler} selectionHandler Selection handler. + * @struct * @constructor - * @extends {cr.EventTarget} */ function FileTransferController(doc, + listContainer, + directoryTree, + multiProfileShareDialog, + progressCenter, fileOperationManager, metadataCache, directoryModel, volumeManager, - multiProfileShareDialog, - progressCenter) { + selectionHandler) { + /** + * @type {!HTMLDocument} + * @private + * @const + */ this.document_ = doc; - this.fileOperationManager_ = fileOperationManager; - this.metadataCache_ = metadataCache; - this.directoryModel_ = directoryModel; - this.volumeManager_ = volumeManager; - this.multiProfileShareDialog_ = multiProfileShareDialog; - this.progressCenter_ = progressCenter; - this.directoryModel_.getFileList().addEventListener( - 'change', - function(event) { - if (this.directoryModel_.getFileListSelection(). - getIndexSelected(event.index)) { - this.onSelectionChanged_(); - } - }.bind(this)); - this.directoryModel_.getFileListSelection().addEventListener('change', - this.onSelectionChanged_.bind(this)); + /** + * @type {!ListContainer} + * @private + * @const + */ + this.listContainer_ = listContainer; + + /** + * @type {!FileOperationManager} + * @private + * @const + */ + this.fileOperationManager_ = fileOperationManager; + + /** + * @type {!MetadataCache} + * @private + * @const + */ + this.metadataCache_ = metadataCache; + + /** + * @type {!DirectoryModel} + * @private + * @const + */ + this.directoryModel_ = directoryModel; + + /** + * @type {!VolumeManagerWrapper} + * @private + * @const + */ + this.volumeManager_ = volumeManager; + + /** + * @type {!FileSelectionHandler} + * @private + * @const + */ + this.selectionHandler_ = selectionHandler; + + /** + * @type {!MultiProfileShareDialog} + * @private + * @const + */ + this.multiProfileShareDialog_ = multiProfileShareDialog; + + /** + * @type {!ProgressCenter} + * @private + * @const + */ + this.progressCenter_ = progressCenter; /** * The array of pending task ID. @@ -91,11 +141,55 @@ this.touching_ = false; /** - * Task ID counter. + * Count of the SourceNotFound error. * @type {number} * @private */ - this.taskIdCounter_ = 0; + this.sourceNotFoundErrorCount_ = 0; + + /** + * @type {!Element} + * @private + * @const + */ + this.copyCommand_ = queryRequiredElement(this.document_, 'command#copy'); + + /** + * @type {DirectoryEntry} + * @private + */ + this.destinationEntry_ = null; + + /** + * @type {EventTarget} + * @private + */ + this.lastEnteredTarget_ = null; + + /** + * @type {Element} + * @private + */ + this.dropTarget_ = null; + + /** + * @type {number} + */ + this.navigateTimer_ = 0; + + // Register the events. + selectionHandler.addEventListener( + FileSelectionHandler.EventType.CHANGE, + this.onFileSelectionChanged_.bind(this)); + selectionHandler.addEventListener( + FileSelectionHandler.EventType.CHANGE_THROTTLED, + this.onFileSelectionChangedThrottled_.bind(this)); + this.attachDragSource_(listContainer.table.list); + this.attachFileListDropTarget_(listContainer.table.list); + this.attachDragSource_(listContainer.grid); + this.attachFileListDropTarget_(listContainer.grid); + this.attachTreeDropTarget_(directoryTree); + this.attachCopyPasteHandlers_(); } /** @@ -107,64 +201,11 @@ */ FileTransferController.DRAG_THUMBNAIL_SIZE_ = 64; -FileTransferController.prototype = { - __proto__: cr.EventTarget.prototype, - - /** - * Obains directory that is displaying now. - * @return {DirectoryEntry} Entry of directry that is displaying now. - */ - get currentDirectoryContentEntry() { - return this.directoryModel_.getCurrentDirEntry(); - }, - - /** - * @return {boolean} True if the current directory is read only. - */ - get readonly() { - return this.directoryModel_.isReadOnly(); - }, - - /** - * @return {boolean} True if the current directory is on Drive. - */ - get isOnDrive() { - var currentDir = this.directoryModel_.getCurrentDirEntry(); - if (!currentDir) - return false; - var locationInfo = this.volumeManager_.getLocationInfo(currentDir); - if (!locationInfo) - return false; - return locationInfo.isDriveBased; - }, - - /** - * @return {Array.<Entry>} Array of the selected entries. - */ - get selectedEntries_() { - var list = this.directoryModel_.getFileList(); - var selectedIndexes = this.directoryModel_.getFileListSelection(). - selectedIndexes; - var entries = selectedIndexes.map(function(index) { - return list.item(index); - }); - - // TODO(serya): Diagnostics for http://crbug/129642 - if (entries.indexOf(undefined) !== -1) { - var index = entries.indexOf(undefined); - entries = entries.filter(function(e) { return !!e; }); - console.error('Invalid selection found: list items: ', list.length, - 'wrong indexe value: ', selectedIndexes[index], - 'Stack trace: ', new Error().stack); - } - return entries; - } -}; - /** - * @param {cr.ui.List} list Items in the list will be draggable. + * @param {!cr.ui.List} list Items in the list will be draggable. + * @private */ -FileTransferController.prototype.attachDragSource = function(list) { +FileTransferController.prototype.attachDragSource_ = function(list) { list.style.webkitUserDrag = 'element'; list.addEventListener('dragstart', this.onDragStart_.bind(this, list)); list.addEventListener('dragend', this.onDragEnd_.bind(this, list)); @@ -176,13 +217,14 @@ }; /** - * @param {cr.ui.List} list List itself and its directory items will could + * @param {!cr.ui.List} list List itself and its directory items will could * be drop target. * @param {boolean=} opt_onlyIntoDirectories If true only directory list * items could be drop targets. Otherwise any other place of the list * accetps files (putting it into the current directory). + * @private */ -FileTransferController.prototype.attachFileListDropTarget = +FileTransferController.prototype.attachFileListDropTarget_ = function(list, opt_onlyIntoDirectories) { list.addEventListener('dragover', this.onDragOver_.bind(this, !!opt_onlyIntoDirectories, list)); @@ -194,9 +236,10 @@ }; /** - * @param {DirectoryTree} tree Its sub items will could be drop target. + * @param {!DirectoryTree} tree Its sub items will could be drop target. + * @private */ -FileTransferController.prototype.attachTreeDropTarget = function(tree) { +FileTransferController.prototype.attachTreeDropTarget_ = function(tree) { tree.addEventListener('dragover', this.onDragOver_.bind(this, true, tree)); tree.addEventListener('dragenter', this.onDragEnterTree_.bind(this, tree)); tree.addEventListener('dragleave', this.onDragLeave_.bind(this, tree)); @@ -205,8 +248,9 @@ /** * Attach handlers of copy, cut and paste operations to the document. + * @private */ -FileTransferController.prototype.attachCopyPasteHandlers = function() { +FileTransferController.prototype.attachCopyPasteHandlers_ = function() { this.document_.addEventListener('beforecopy', this.onBeforeCopy_.bind(this)); this.document_.addEventListener('copy', @@ -219,7 +263,6 @@ this.onBeforePaste_.bind(this)); this.document_.addEventListener('paste', this.onPaste_.bind(this)); - this.copyCommand_ = this.document_.querySelector('command#copy'); }; /** @@ -234,20 +277,20 @@ function(clipboardData, effectAllowed) { // Existence of the volumeInfo is checked in canXXX methods. var volumeInfo = this.volumeManager_.getVolumeInfo( - this.currentDirectoryContentEntry); + this.directoryModel_.getCurrentDirEntry()); // Tag to check it's filemanager data. clipboardData.setData('fs/tag', 'filemanager-data'); clipboardData.setData('fs/sourceRootURL', volumeInfo.fileSystem.root.toURL()); - var sourceURLs = util.entriesToURLs(this.selectedEntries_); + var sourceURLs = util.entriesToURLs(this.selectionHandler_.selection.entries); clipboardData.setData('fs/sources', sourceURLs.join('\n')); clipboardData.effectAllowed = effectAllowed; clipboardData.setData('fs/effectallowed', effectAllowed); clipboardData.setData('fs/missingFileContents', - (!this.isAllSelectedFilesAvailable_()).toString()); + (!this.selectionHandler_.isAvailable()).toString()); var externalFileUrl; - for (var i = 0; i < this.selectedEntries_.length; i++) { - var url = this.selectedEntries_[i].toURL(); + for (var i = 0; i < this.selectionHandler_.selection.entries.length; i++) { + var url = this.selectionHandler_.selection.entries[i].toURL(); if (!this.selectedAsyncData_[url]) continue; if (this.selectedAsyncData_[url].file) @@ -255,7 +298,8 @@ if (!externalFileUrl) externalFileUrl = this.selectedAsyncData_[url].externalFileUrl; } - clipboardData.setData('text/uri-list', externalFileUrl); + if (externalFileUrl) + clipboardData.setData('text/uri-list', externalFileUrl); }; /** @@ -408,7 +452,7 @@ (!util.isDropEffectAllowed(effectAllowed, 'copy') || opt_effect === 'move'); var destinationEntry = - opt_destinationEntry || this.currentDirectoryContentEntry; + opt_destinationEntry || this.directoryModel_.getCurrentDirEntry(); var entries = []; var failureUrls; var taskId = this.fileOperationManager_.generateTaskId(); @@ -472,15 +516,19 @@ entries, destinationEntry, toMove, taskId); this.pendingTaskIds.splice(this.pendingTaskIds.indexOf(taskId), 1); - // Publish events for failureUrls. + // Publish source not found error item. for (var i = 0; i < failureUrls.length; i++) { var fileName = decodeURIComponent(failureUrls[i].replace(/^.+\//, '')); - var event = new Event('source-not-found'); - event.fileName = fileName; - event.progressType = - toMove ? ProgressItemType.MOVE : ProgressItemType.COPY; - this.dispatchEvent(event); + var item = new ProgressCenterItem(); + item.id = 'source-not-found-' + this.sourceNotFoundErrorCount_; + if (toMove) + item.message = strf('MOVE_SOURCE_NOT_FOUND_ERROR', fileName); + else + item.message = strf('COPY_SOURCE_NOT_FOUND_ERROR', fileName); + item.state = ProgressItemState.ERROR; + this.progressCenter_.updateItem(item); + this.sourceNotFoundErrorCount_++; } }.bind(this)).catch(function(error) { if (error !== 'ABORT') @@ -532,12 +580,11 @@ /** * Renders a drag-and-drop thumbnail. * - * @return {Element} Element containing the thumbnail. + * @return {!Element} Element containing the thumbnail. * @private */ FileTransferController.prototype.renderThumbnail_ = function() { - var length = this.selectedEntries_.length; - + var length = this.selectionHandler_.selection.entries.length; var container = this.document_.querySelector('#drag-container'); var contents = this.document_.createElement('div'); contents.className = 'drag-contents'; @@ -585,7 +632,7 @@ } // Option 3. Thumbnail not available. Render an icon and a label. - var entry = this.selectedEntries_[0]; + var entry = this.selectionHandler_.selection.entries[0]; var icon = this.document_.createElement('div'); icon.className = 'detail-icon'; icon.setAttribute('file-type-icon', FileType.getIcon(entry)); @@ -598,8 +645,8 @@ }; /** - * @param {cr.ui.List} list Drop target list - * @param {Event} event A dragstart event of DOM. + * @param {!cr.ui.List} list Drop target list + * @param {!Event} event A dragstart event of DOM. * @private */ FileTransferController.prototype.onDragStart_ = function(list, event) { @@ -613,7 +660,7 @@ } // Nothing selected. - if (!this.selectedEntries_.length) { + if (!this.selectionHandler_.selection.entries.length) { event.preventDefault(); return; } @@ -644,8 +691,8 @@ }; /** - * @param {cr.ui.List} list Drop target list. - * @param {Event} event A dragend event of DOM. + * @param {!cr.ui.List} list Drop target list. + * @param {!Event} event A dragend event of DOM. * @private */ FileTransferController.prototype.onDragEnd_ = function(list, event) { @@ -662,22 +709,23 @@ /** * @param {boolean} onlyIntoDirectories True if the drag is only into * directories. - * @param {(cr.ui.List|DirectoryTree)} list Drop target list. + * @param {(!cr.ui.List|!DirectoryTree)} list Drop target list. * @param {Event} event A dragover event of DOM. * @private */ FileTransferController.prototype.onDragOver_ = function(onlyIntoDirectories, list, event) { event.preventDefault(); - var entry = this.destinationEntry_ || - (!onlyIntoDirectories && this.currentDirectoryContentEntry); + var entry = this.destinationEntry_; + if (!entry && !onlyIntoDirectories) + entry = this.directoryModel_.getCurrentDirEntry(); event.dataTransfer.dropEffect = this.selectDropEffect_(event, entry); event.preventDefault(); }; /** - * @param {(cr.ui.List|DirectoryTree)} list Drop target list. - * @param {Event} event A dragenter event of DOM. + * @param {(!cr.ui.List|!DirectoryTree)} list Drop target list. + * @param {!Event} event A dragenter event of DOM. * @private */ FileTransferController.prototype.onDragEnterFileList_ = function(list, event) { @@ -697,8 +745,8 @@ }; /** - * @param {DirectoryTree} tree Drop target tree. - * @param {Event} event A dragenter event of DOM. + * @param {!DirectoryTree} tree Drop target tree. + * @param {!Event} event A dragenter event of DOM. * @private */ FileTransferController.prototype.onDragEnterTree_ = function(tree, event) { @@ -741,7 +789,7 @@ /** * @param {boolean} onlyIntoDirectories True if the drag is only into * directories. - * @param {Event} event A dragleave event of DOM. + * @param {!Event} event A dragleave event of DOM. * @private */ FileTransferController.prototype.onDrop_ = @@ -749,7 +797,7 @@ if (onlyIntoDirectories && !this.dropTarget_) return; var destinationEntry = this.destinationEntry_ || - this.currentDirectoryContentEntry; + this.directoryModel_.getCurrentDirEntry(); if (!this.canPasteOrDrop_(event.dataTransfer, destinationEntry)) return; event.preventDefault(); @@ -763,7 +811,7 @@ * * @param {Element} domElement Target of the drop. * @param {!ClipboardData} clipboardData Data transfer object. - * @param {DirectoryEntry} destinationEntry Destination entry. + * @param {!DirectoryEntry} destinationEntry Destination entry. * @private */ FileTransferController.prototype.setDropTarget_ = @@ -828,7 +876,7 @@ this.destinationEntry_ = null; if (this.navigateTimer_ !== undefined) { clearTimeout(this.navigateTimer_); - this.navigateTimer_ = undefined; + this.navigateTimer_ = 0; } }; @@ -843,7 +891,7 @@ }; /** - * @param {Event} event + * @param {!Event} event * @private */ FileTransferController.prototype.onCopy_ = function(event) { @@ -853,11 +901,11 @@ } event.preventDefault(); this.cutOrCopy_(assert(event.clipboardData), 'copy'); - this.notify_('selection-copied'); + this.blinkSelection_(); }; /** - * @param {Event} event + * @param {!Event} event * @private */ FileTransferController.prototype.onBeforeCopy_ = function(event) { @@ -870,36 +918,17 @@ }; /** - * @return {boolean} Returns true if all selected files are available to be - * copied. - * @private - */ -FileTransferController.prototype.isAllSelectedFilesAvailable_ = function() { - if (!this.currentDirectoryContentEntry) - return false; - var volumeInfo = this.volumeManager_.getVolumeInfo( - this.currentDirectoryContentEntry); - if (!volumeInfo) - return false; - var isDriveOffline = this.volumeManager_.getDriveConnectionState().type === - VolumeManagerCommon.DriveConnectionType.OFFLINE; - if (this.isOnDrive && isDriveOffline && !this.allDriveFilesAvailable) - return false; - return true; -}; - -/** * @return {boolean} Returns true if some files are selected and all the file * on drive is available to be copied. Otherwise, returns false. * @private */ FileTransferController.prototype.canCopyOrDrag_ = function() { - return this.isAllSelectedFilesAvailable_() && - this.selectedEntries_.length > 0; + return this.selectionHandler_.isAvailable() && + this.selectionHandler_.selection.entries.length > 0; }; /** - * @param {Event} event + * @param {!Event} event * @private */ FileTransferController.prototype.onCut_ = function(event) { @@ -909,11 +938,11 @@ } event.preventDefault(); this.cutOrCopy_(assert(event.clipboardData), 'move'); - this.notify_('selection-cut'); + this.blinkSelection_(); }; /** - * @param {Event} event + * @param {!Event} event * @private */ FileTransferController.prototype.onBeforeCut_ = function(event) { @@ -929,17 +958,19 @@ * @private */ FileTransferController.prototype.canCutOrDrag_ = function() { - return !this.readonly && this.selectedEntries_.length > 0; + return !this.directoryModel_.isReadOnly() && + this.selectionHandler_.selection.entries.length > 0; }; /** - * @param {Event} event + * @param {!Event} event * @private */ FileTransferController.prototype.onPaste_ = function(event) { // If the event has destDirectory property, paste files into the directory. // This occurs when the command fires from menu item 'Paste into folder'. - var destination = event.destDirectory || this.currentDirectoryContentEntry; + var destination = + event.destDirectory || this.directoryModel_.getCurrentDirEntry(); // Need to update here since 'beforepaste' doesn't fire. if (!this.isDocumentWideEvent_() || @@ -960,7 +991,7 @@ }; /** - * @param {Event} event + * @param {!Event} event * @private */ FileTransferController.prototype.onBeforePaste_ = function(event) { @@ -968,7 +999,7 @@ return; // queryCommandEnabled returns true if event.defaultPrevented is true. if (this.canPasteOrDrop_(assert(event.clipboardData), - this.currentDirectoryContentEntry)) { + this.directoryModel_.getCurrentDirEntry())) { event.preventDefault(); } }; @@ -1016,7 +1047,7 @@ var result; this.simulateCommand_('paste', function(event) { result = this.canPasteOrDrop_(event.clipboardData, - this.currentDirectoryContentEntry); + this.directoryModel_.getCurrentDirEntry()); }.bind(this)); return result; }; @@ -1037,20 +1068,25 @@ }; /** - * @param {Event} event * @private */ -FileTransferController.prototype.onSelectionChanged_ = function(event) { - var entries = this.selectedEntries_; - var asyncData = this.selectedAsyncData_ = {}; +FileTransferController.prototype.onFileSelectionChanged_ = function() { this.preloadedThumbnailImagePromise_ = null; + this.selectedAsyncData_ = {}; +}; +/** + * @private + */ +FileTransferController.prototype.onFileSelectionChangedThrottled_ = function() { + var entries = this.selectionHandler_.selection.entries; + var asyncData = this.selectedAsyncData_; var fileEntries = []; for (var i = 0; i < entries.length; i++) { if (entries[i].isFile) fileEntries.push(entries[i]); } - var containsDirectory = fileEntries.length !== entries.length; + var containsDirectory = this.selectionHandler_.selection.directoryCount > 0; // File object must be prepeared in advance for clipboard operations // (copy, paste and drag). DataTransfer object closes for write after @@ -1058,7 +1094,7 @@ // asynchronous operations. if (!containsDirectory) { for (var i = 0; i < fileEntries.length; i++) { - asyncData[fileEntries[i].toURL()] = {}; + asyncData[fileEntries[i].toURL()] = {externalFileUrl: '', file: null}; fileEntries[i].file(function(data, file) { data.file = file; }.bind(null, asyncData[fileEntries[i].toURL()])); @@ -1072,16 +1108,8 @@ this.preloadThumbnailImage_(entries[0]); } - this.allDriveFilesAvailable = false; this.metadataCache_.get(entries, 'external', function(metadataList) { - // We consider directories not available offline for the purposes of - // file transfer since we cannot afford to recursive traversal. - this.allDriveFilesAvailable = - !containsDirectory && - metadataList.every(function(metadata) { - return metadata && metadata.availableOffline; - }); - // |Copy| is the only menu item affected by allDriveFilesAvailable. + // |Copy| is the only menu item affected by allDriveFilesAvailable_. // It could be open right now, update its UI. this.copyCommand_.disabled = !this.canCopyOrDrag_(); @@ -1095,19 +1123,7 @@ }; /** - * @param {string} eventName - * @private - */ -FileTransferController.prototype.notify_ = function(eventName) { - var self = this; - // Set timeout to avoid recursive events. - setTimeout(function() { - cr.dispatchSimpleEvent(self, eventName); - }, 0); -}; - -/** - * @param {Event} event Drag event. + * @param {!Event} event Drag event. * @param {DirectoryEntry} destinationEntry Destination entry. * @return {string} Returns the appropriate drop query type ('none', 'move' * or copy') to the current modifiers status and the destination. @@ -1139,3 +1155,31 @@ } return 'copy'; }; + +/** + * Blinks the selection. Used to give feedback when copying or cutting the + * selection. + * @private + */ +FileTransferController.prototype.blinkSelection_ = function() { + var selection = this.selectionHandler_.selection; + if (!selection || selection.totalCount == 0) + return; + + var listItems = []; + for (var i = 0; i < selection.entries.length; i++) { + var selectedIndex = selection.indexes[i]; + var listItem = + this.listContainer_.currentList.getListItemByIndex(selectedIndex); + if (listItem) { + listItem.classList.add('blink'); + listItems.push(listItem); + } + } + + setTimeout(function() { + for (var i = 0; i < listItems.length; i++) { + listItems[i].classList.remove('blink'); + } + }, 100); +};
diff --git a/ui/file_manager/file_manager/foreground/js/thumbnail_loader.js b/ui/file_manager/file_manager/foreground/js/thumbnail_loader.js index 51d1115..ca86716 100644 --- a/ui/file_manager/file_manager/foreground/js/thumbnail_loader.js +++ b/ui/file_manager/file_manager/foreground/js/thumbnail_loader.js
@@ -37,17 +37,6 @@ if (opt_metadata.external && opt_metadata.external.customIconUrl) this.fallbackUrl_ = opt_metadata.external.customIconUrl; - // Fetch the rotation from the external properties (if available). - var externalTransform; - if (opt_metadata.external && - opt_metadata.external.imageRotation !== undefined) { - externalTransform = { - scaleX: 1, - scaleY: 1, - rotate90: opt_metadata.external.imageRotation / 90 - }; - } - if (((opt_metadata.thumbnail && opt_metadata.thumbnail.url) || (opt_metadata.external && opt_metadata.external.thumbnailUrl)) && opt_useEmbedded === ThumbnailLoader.UseEmbedded.USE_EMBEDDED) { @@ -57,12 +46,11 @@ this.thumbnailUrl_ = (opt_metadata.thumbnail && opt_metadata.thumbnail.url) || (opt_metadata.external && opt_metadata.external.thumbnailUrl); - this.transform_ = externalTransform !== undefined ? externalTransform : - (opt_metadata.thumbnail && opt_metadata.thumbnail.transform); + this.transform_ = + opt_metadata.thumbnail && opt_metadata.thumbnail.transform; } else if (FileType.isImage(entry)) { this.thumbnailUrl_ = entry.toURL(); - this.transform_ = externalTransform !== undefined ? externalTransform : - opt_metadata.media && opt_metadata.media.imageTransform; + this.transform_ = opt_metadata.media && opt_metadata.media.imageTransform; } else if (this.fallbackUrl_) { // Use fallback as the primary thumbnail. this.thumbnailUrl_ = this.fallbackUrl_;
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_grid.js b/ui/file_manager/file_manager/foreground/js/ui/file_grid.js index 3d68dd4f..fc20538 100644 --- a/ui/file_manager/file_manager/foreground/js/ui/file_grid.js +++ b/ui/file_manager/file_manager/foreground/js/ui/file_grid.js
@@ -51,40 +51,20 @@ /** * Map of URL and ListItem generated at the previous update time. * This is used for updating existing item synchronously. - * @type {Object.<string, !cr.ui.ListItem>} + * @type {Object.<string, !FileGrid.Item>} * @private * @const */ self.previousItems_ = {}; self.itemConstructor = function(entry) { - var item = self.previousItems_[entry.toURL()]; - if (item) { - // At this point, previous items that are needed to be replaced have been - // removed. - assert(item.parentElement == null); - - // If the thumbnail has already been loaded, mark it cached to prevent - // playing fadein animation. Then update the thumbnail. - var img = item.querySelector('img'); - if (img) { - img.classList.add('cached'); - FileGrid.decorateThumbnailBox( - item.querySelector('.thumbnail-frame div'), - entry, - self.metadataCache_, - self.volumeManager_, - self.historyLoader_, - ThumbnailLoader.FillMode.AUTO, - FileGrid.ThumbnailQuality.LOW, - /* animation */ false); - } - return item; - } - item = self.ownerDocument.createElement('LI'); - FileGrid.Item.decorate(item, entry, /** @type {FileGrid} */ (self)); - self.previousItems_[entry.toURL()] = - /** @type {!FileGrid.Item} */ (item); + var item = self.ownerDocument.createElement('LI'); + FileGrid.Item.decorate( + item, + entry, + /** @type {FileGrid} */ (self), + self.previousItems_[entry.toURL()]); + self.previousItems_[entry.toURL()] = /** @type {!FileGrid.Item} */ (item); return item; }; @@ -157,9 +137,18 @@ * @param {MetadataCache} metadataCache To retrieve metadata. * @param {VolumeManagerWrapper} volumeManager Volume manager instance. * @param {!importer.HistoryLoader} historyLoader + * @param {FileGrid.Item} previousItem Existing grid item. Usually it is the + * item used for the same entry before calling redraw() method. If it is + * non-null, the item show the thumbnail immediately until the new thumbanil + * is loaded. */ -FileGrid.decorateThumbnail = - function(li, entry, metadataCache, volumeManager, historyLoader) { +FileGrid.decorateThumbnail = function( + li, + entry, + metadataCache, + volumeManager, + historyLoader, + previousItem) { li.className = 'thumbnail-item'; if (entry) filelist.decorateListItem(li, entry, metadataCache); @@ -168,16 +157,33 @@ frame.className = 'thumbnail-frame'; li.appendChild(frame); - var box = li.ownerDocument.createElement('div'); - if (entry) { - FileGrid.decorateThumbnailBox(box, - entry, - metadataCache, - volumeManager, - historyLoader, - ThumbnailLoader.FillMode.AUTO, - FileGrid.ThumbnailQuality.LOW, - /* animation */ true); + var previousBox = + previousItem ? previousItem.querySelector('.img-container') : null; + var box; + var shouldLoadThumbnail; + if (previousItem) { + box = previousBox; + var previousImage = box.querySelector('img'); + if (previousImage) { + previousImage.classList.add('cached'); + shouldLoadThumbnail = !!entry; + } else { + shouldLoadThumbnail = false; + } + } else { + box = li.ownerDocument.createElement('div'); + shouldLoadThumbnail = !!entry; + } + if (shouldLoadThumbnail) { + FileGrid.decorateThumbnailBox( + box, + entry, + metadataCache, + volumeManager, + historyLoader, + ThumbnailLoader.FillMode.AUTO, + FileGrid.ThumbnailQuality.LOW, + /* animation */ !previousBox); } frame.appendChild(box); @@ -210,7 +216,7 @@ var locationInfo = volumeManager.getLocationInfo(entry); box.className = 'img-container'; - if (importer.isEligibleEntry(entry, volumeManager)) { + if (importer.isEligibleEntry(volumeManager, entry)) { historyLoader.getHistory().then( FileGrid.applyHistoryBadges_.bind( null, @@ -261,8 +267,7 @@ fillMode, ThumbnailLoader.OptimizationMode.DISCARD_DETACHED, function(image, transform) { - if (animation == false) - image.classList.add('cached'); + image.classList.toggle('cached', !animation); if (opt_imageLoadCallback) opt_imageLoadCallback(image); }); @@ -322,14 +327,23 @@ * @param {Element} li List item element. * @param {Entry} entry File entry. * @param {FileGrid} grid Owner. + * @param {FileGrid.Item} previousItem Existing grid item. Usually it is the + * item used for the same entry before calling redraw() method. If it is + * non-null, the item show the thumbnail immediately until the new thumbanil + * is loaded. */ -FileGrid.Item.decorate = function(li, entry, grid) { +FileGrid.Item.decorate = function(li, entry, grid, previousItem) { li.__proto__ = FileGrid.Item.prototype; li = /** @type {!FileGrid.Item} */ (li); // TODO(mtomasz): Pass the metadata cache and the volume manager directly // instead of accessing private members of grid. FileGrid.decorateThumbnail( - li, entry, grid.metadataCache_, grid.volumeManager_, grid.historyLoader_); + li, + entry, + grid.metadataCache_, + grid.volumeManager_, + grid.historyLoader_, + previousItem); // Override the default role 'listitem' to 'option' to match the parent's // role (listbox).
diff --git a/ui/file_manager/file_manager/foreground/js/ui/preview_panel.js b/ui/file_manager/file_manager/foreground/js/ui/preview_panel.js index e908166..1a33f9c 100644 --- a/ui/file_manager/file_manager/foreground/js/ui/preview_panel.js +++ b/ui/file_manager/file_manager/foreground/js/ui/preview_panel.js
@@ -10,6 +10,8 @@ * @param {MetadataCache} metadataCache Metadata cache. * @param {VolumeManagerWrapper} volumeManager Volume manager. * @param {!importer.HistoryLoader} historyLoader + * @param {function(string): boolean} commandEnabledTest A function + * that returns true if the named command is enabled. * @constructor * @extends {cr.EventTarget} */ @@ -17,7 +19,8 @@ visibilityType, metadataCache, volumeManager, - historyLoader) { + historyLoader, + commandEnabledTest) { /** * The cached height of preview panel. * @type {number} @@ -96,6 +99,21 @@ */ this.volumeManager_ = volumeManager; + /** + * List of command ids that are should be checked when determining + * auto-visibility. + * + * @private {Array.<string>} + */ + this.autoVisibilityCommandIds_ = []; + + /** + * A function that returns true if a named command is enabled. + * This is used when determining visibility of the preview panel. + * @private {function(string): boolean} + */ + this.commandEnabled_ = commandEnabledTest; + cr.EventTarget.call(this); }; @@ -186,6 +204,8 @@ PreviewPanel.prototype.initialize = function() { this.element_.addEventListener('webkitTransitionEnd', this.onTransitionEnd_.bind(this)); + + this.autoVisibilityCommandIds_ = this.findAutoVisibilityCommandIds_(); this.updateVisibility_(); // Also update the preview area contents, because the update is suppressed // while the visibility is hiding or hidden. @@ -193,6 +213,37 @@ }; /** + * @return {Array.<string>} List of command ids for the "AUTO" visibility type + * (which currently happen to correspond to "full-page" commands). + * @private + */ +PreviewPanel.prototype.findAutoVisibilityCommandIds_ = function() { + if (this.visibilityType_ != PreviewPanel.VisibilityType.AUTO) { + return []; + } + // Find all relevent command elements. Convert the resulting NodeList + // to an Array. + var elements = Array.prototype.slice.call( + this.element_.querySelectorAll('div[class~=buttonbar] button[command]')); + + return elements.map( + function(e) { + // We can assume that the command attribute starts with '#'; + return e.getAttribute('command').substring(1); + }); +}; + +/** + * @return {boolean} True if one of the known "auto visibility" + * (non-dialog mode) commands is enabled. + * @private + */ +PreviewPanel.prototype.hasEnabledAutoVisibilityCommand_ = function() { + return this.autoVisibilityCommandIds_.some( + this.commandEnabled_.bind(this)); +}; + +/** * Apply the selection and update the view of the preview panel. * @param {FileSelection} selection Selection to be applied. */ @@ -216,7 +267,8 @@ newVisible = true; break; case PreviewPanel.VisibilityType.AUTO: - newVisible = this.selection_.entries.length !== 0; + newVisible = this.selection_.entries.length !== 0 || + this.hasEnabledAutoVisibilityCommand_(); break; case PreviewPanel.VisibilityType.ALWAYS_HIDDEN: newVisible = false;
diff --git a/ui/file_manager/file_manager/foreground/js/ui/share_dialog.js b/ui/file_manager/file_manager/foreground/js/ui/share_dialog.js index e898edd..f03e386 100644 --- a/ui/file_manager/file_manager/foreground/js/ui/share_dialog.js +++ b/ui/file_manager/file_manager/foreground/js/ui/share_dialog.js
@@ -211,7 +211,7 @@ /** * Shows the dialog. - * @param {FileEntry} entry Entry to share. + * @param {!Entry} entry Entry to share. * @param {function(ShareDialog.Result)} callback Callback to be called when the * showing task is completed. The argument is whether to succeed or not. * Note that cancel is regarded as success.
diff --git a/ui/file_manager/file_manager/main.html b/ui/file_manager/file_manager/main.html index 9cd91d1..63a2ed2 100644 --- a/ui/file_manager/file_manager/main.html +++ b/ui/file_manager/file_manager/main.html
@@ -209,6 +209,8 @@ <command id="share" i18n-values="label:SHARE_BUTTON_LABEL" shortcut="U+00BE" hide-shortcut-text><!-- Shortcut: '.' --> + <command id="cloud-import" i18n-values="label:CLOUD_IMPORT_BUTTON_LABEL"> + <command id="zoom-in" shortcut="U+00BB-Ctrl"> <command id="zoom-out" shortcut="U+00BD-Ctrl"> <command id="zoom-reset" shortcut="U+0030-Ctrl"> @@ -371,11 +373,13 @@ </div> </div> <div class="right buttonbar" visibleif="full-page"> - <button id="share-button" command="#share" tabindex="10" + <button id="cloud-import-button" command="#cloud-import" tabindex="10" + i18n-values="aria-label:CLOUD_IMPORT_BUTTON_LABEL"></button> + <button id="share-button" command="#share" tabindex="11" i18n-values="aria-label:SHARE_BUTTON_LABEL"></button> <button id="tasks" class="combobutton" menu="#tasks-menu" - tabindex="11"></button> - <button id="delete-button" command="#delete" tabindex="12" + tabindex="12"></button> + <button id="delete-button" command="#delete" tabindex="13" i18n-values="aria-label:DELETE_BUTTON_LABEL"></button> </div> <div class="preparing-label" i18n-content="PREPARING_LABEL"></div> @@ -386,9 +390,9 @@ visibleif="open-file open-multi-file folder upload-folder"> <select class="file-type" hidden></select> <button i18n-content="NEW_FOLDER_BUTTON_LABEL" - visibleif="folder" command="#new-folder" tabindex="13"></button> - <button class="ok" disabled tabindex="14"></button> - <button class="cancel" i18n-content="CANCEL_LABEL" tabindex="15"></button> + visibleif="folder" command="#new-folder" tabindex="14"></button> + <button class="ok" disabled tabindex="15"></button> + <button class="cancel" i18n-content="CANCEL_LABEL" tabindex="16"></button> </div> </div> <div id="unmounted-panel"></div>
diff --git a/ui/file_manager/file_manager/manifest.json b/ui/file_manager/file_manager/manifest.json index 50d0adb..1dbaeb1 100644 --- a/ui/file_manager/file_manager/manifest.json +++ b/ui/file_manager/file_manager/manifest.json
@@ -180,6 +180,7 @@ "background/js/drive_sync_handler.js", "background/js/file_operation_handler.js", "background/js/file_operation_manager.js", + "background/js/file_operation_util.js", "background/js/import_history.js", "background/js/media_scanner.js", "background/js/progress_center.js",
diff --git a/ui/file_manager/file_manager_resources.grd b/ui/file_manager/file_manager_resources.grd index ee03a72..11a574c9 100644 --- a/ui/file_manager/file_manager_resources.grd +++ b/ui/file_manager/file_manager_resources.grd
@@ -32,6 +32,7 @@ <include name="IDR_FILE_MANAGER_DRIVE_SYNC_HANDLER_JS" file="file_manager/background/js/drive_sync_handler.js" flattenhtml="false" type="BINDATA" /> <include name="IDR_FILE_MANAGER_FILE_OPERATION_HANDLER_JS" file="file_manager/background/js/file_operation_handler.js" flattenhtml="false" type="BINDATA" /> <include name="IDR_FILE_MANAGER_FILE_OPERATION_MANAGER_JS" file="file_manager/background/js/file_operation_manager.js" flattenhtml="false" type="BINDATA" /> + <include name="IDR_FILE_MANAGER_FILE_OPERATION_UTIL_JS" file="file_manager/background/js/file_operation_util.js" flattenhtml="false" type="BINDATA" /> <include name="IDR_FILE_MANAGER_IMPORT_HISTORY_JS" file="file_manager/background/js/import_history.js" flattenhtml="false" type="BINDATA" /> <include name="IDR_FILE_MANAGER_MEDIA_SCANNER_JS" file="file_manager/background/js/media_scanner.js" flattenhtml="false" type="BINDATA" /> <include name="IDR_FILE_MANAGER_PROGRESS_CENTER_JS" file="file_manager/background/js/progress_center.js" flattenhtml="false" type="BINDATA" />
diff --git a/ui/file_manager/gallery/js/image_editor/commands.js b/ui/file_manager/gallery/js/image_editor/commands.js index b0276c9..3e24bbf9 100644 --- a/ui/file_manager/gallery/js/image_editor/commands.js +++ b/ui/file_manager/gallery/js/image_editor/commands.js
@@ -7,10 +7,11 @@ * Supports undo/redo. * Command execution is asynchronous (callback-based). * - * @param {Document} document Document to create canvases in. - * @param {HTMLCanvasElement} canvas The canvas with the original image. + * @param {!Document} document Document to create canvases in. + * @param {!HTMLCanvasElement} canvas The canvas with the original image. * @param {function(function())} saveFunction Function to save the image. * @constructor + * @struct */ function CommandQueue(document, canvas, saveFunction) { this.document_ = document; @@ -45,8 +46,8 @@ * Attach the UI elements to the command queue. * Once the UI is attached the results of image manipulations are displayed. * - * @param {ImageView} imageView The ImageView object to display the results. - * @param {ImageEditor.Prompt} prompt Prompt to use with this CommandQueue. + * @param {!ImageView} imageView The ImageView object to display the results. + * @param {!ImageEditor.Prompt} prompt Prompt to use with this CommandQueue. * @param {function(boolean)} lock Function to enable/disable buttons etc. */ CommandQueue.prototype.attachUI = function(imageView, prompt, lock) { @@ -122,8 +123,8 @@ /** * Internal function to execute the command in a given context. * - * @param {Command} command The command to execute. - * @param {Object} uiContext The UI context. + * @param {!Command} command The command to execute. + * @param {!Object} uiContext The UI context. * @param {function(number=)} callback Completion callback. * @private */ @@ -151,7 +152,7 @@ /** * Executes the command. * - * @param {Command} command Command to execute. + * @param {!Command} command Command to execute. * @param {boolean=} opt_keep_redo True if redo stack should not be cleared. */ CommandQueue.prototype.execute = function(command, opt_keep_redo) { @@ -264,6 +265,7 @@ * * @param {string} name Command name. * @constructor + * @struct */ function Command(name) { this.name_ = name; @@ -282,11 +284,11 @@ * The two actions are combined into one method because sometimes it is nice * to be able to show partial results for slower operations. * - * @param {Document} document Document on which to execute command. - * @param {HTMLCanvasElement} srcCanvas Canvas to execute on. + * @param {!Document} document Document on which to execute command. + * @param {!HTMLCanvasElement} srcCanvas Canvas to execute on. * @param {function(HTMLCanvasElement, number)} callback Callback to call on * completion. - * @param {Object} uiContext Context to work in. + * @param {!Object} uiContext Context to work in. */ Command.prototype.execute = function(document, srcCanvas, callback, uiContext) { console.error('Command.prototype.execute not implemented'); @@ -295,8 +297,8 @@ /** * Visualize reversion of the operation. * - * @param {HTMLCanvasElement} canvas Image data to use. - * @param {ImageView} imageView ImageView to revert. + * @param {!HTMLCanvasElement} canvas Image data to use. + * @param {!ImageView} imageView ImageView to revert. * @return {number} Animation duration in ms. */ Command.prototype.revertView = function(canvas, imageView) { @@ -307,16 +309,17 @@ /** * Creates canvas to render on. * - * @param {Document} document Document to create canvas in. - * @param {HTMLCanvasElement} srcCanvas to copy optional dimensions from. + * @param {!Document} document Document to create canvas in. + * @param {!HTMLCanvasElement} srcCanvas to copy optional dimensions from. * @param {number=} opt_width new canvas width. * @param {number=} opt_height new canvas height. - * @return {HTMLCanvasElement} Newly created canvas. + * @return {!HTMLCanvasElement} Newly created canvas. * @private */ Command.prototype.createCanvas_ = function( document, srcCanvas, opt_width, opt_height) { - var result = document.createElement('canvas'); + var result = assertInstanceof(document.createElement('canvas'), + HTMLCanvasElement); result.width = opt_width || srcCanvas.width; result.height = opt_height || srcCanvas.height; return result; @@ -328,6 +331,7 @@ * @param {number} rotate90 Rotation angle in 90 degree increments (signed). * @constructor * @extends {Command} + * @struct */ Command.Rotate = function(rotate90) { Command.call(this, 'rotate(' + rotate90 * 90 + 'deg)'); @@ -362,9 +366,10 @@ /** * Crop command. * - * @param {ImageRect} imageRect Crop rectangle in image coordinates. + * @param {!ImageRect} imageRect Crop rectangle in image coordinates. * @constructor * @extends {Command} + * @struct */ Command.Crop = function(imageRect) { Command.call(this, 'crop' + imageRect.toString()); @@ -378,8 +383,8 @@ document, srcCanvas, callback, uiContext) { var result = this.createCanvas_( document, srcCanvas, this.imageRect_.width, this.imageRect_.height); - ImageRect.drawImage( - result.getContext('2d'), srcCanvas, null, this.imageRect_); + var ctx = assertInstanceof(result.getContext('2d'), CanvasRenderingContext2D); + ImageRect.drawImage(ctx, srcCanvas, null, this.imageRect_); var delay; if (uiContext.imageView) { delay = uiContext.imageView.replaceAndAnimate(result, this.imageRect_, 0); @@ -401,6 +406,7 @@ * @param {?string} message Message to display when done. * @constructor * @extends {Command} + * @struct */ Command.Filter = function(name, filter, message) { Command.call(this, name); @@ -426,11 +432,12 @@ } else { var viewport = uiContext.imageView.viewport_; - var imageStrip = new ImageRect(viewport.getImageBounds()); + var imageStrip = ImageRect.createFromBounds(viewport.getImageBounds()); imageStrip.top = previousRow; imageStrip.height = updatedRow - previousRow; - var screenStrip = new ImageRect(viewport.getImageBoundsOnScreen()); + var screenStrip = ImageRect.createFromBounds( + viewport.getImageBoundsOnScreen()); screenStrip.top = Math.round(viewport.imageToScreenY(previousRow)); screenStrip.height = Math.round(viewport.imageToScreenY(updatedRow)) - screenStrip.top;
diff --git a/ui/file_manager/gallery/js/image_editor/exif_encoder.js b/ui/file_manager/gallery/js/image_editor/exif_encoder.js index 80fdef8..5874be3d 100644 --- a/ui/file_manager/gallery/js/image_editor/exif_encoder.js +++ b/ui/file_manager/gallery/js/image_editor/exif_encoder.js
@@ -87,7 +87,7 @@ var pixelCount = this.metadata_.width * this.metadata_.height; var maxEncodedSize = 5000 * Math.min(10, 1 + pixelCount / 1000000); - var DATA_URL_PREFIX = 'data:' + this.mimeType + ';base64,'; + var DATA_URL_PREFIX = 'data:' + this.metadata_.media.mimeType + ';base64,'; var BASE64_BLOAT = 4 / 3; var maxDataURLLength = DATA_URL_PREFIX.length + Math.ceil(maxEncodedSize * BASE64_BLOAT);
diff --git a/ui/file_manager/gallery/js/image_editor/filter.js b/ui/file_manager/gallery/js/image_editor/filter.js index d2fbeda1..8ec87b6 100644 --- a/ui/file_manager/gallery/js/image_editor/filter.js +++ b/ui/file_manager/gallery/js/image_editor/filter.js
@@ -34,16 +34,19 @@ * @param {!HTMLCanvasElement} srcCanvas Source canvas. * @param {function(ImageData,ImageData,number,number)} filterFunc Filter. * @param {function(number, number)} progressCallback Progress callback. - * @param {number} maxPixelsPerStrip Pixel number to process at once. + * @param {number=} opt_maxPixelsPerStrip Pixel number to process at once. */ filter.applyByStrips = function( - dstCanvas, srcCanvas, filterFunc, progressCallback, maxPixelsPerStrip) { + dstCanvas, srcCanvas, filterFunc, progressCallback, opt_maxPixelsPerStrip) { + // 1 Mpix is a reasonable default. + var maxPixelsPerStrip = opt_maxPixelsPerStrip || 1000000; + var dstContext = dstCanvas.getContext('2d'); var srcContext = srcCanvas.getContext('2d'); var source = srcContext.getImageData(0, 0, srcCanvas.width, srcCanvas.height); var stripCount = Math.ceil(srcCanvas.width * srcCanvas.height / - (maxPixelsPerStrip || 1000000)); // 1 Mpix is a reasonable default. + maxPixelsPerStrip); var strip = srcContext.getImageData(0, 0, srcCanvas.width, Math.ceil(srcCanvas.height / stripCount));
diff --git a/ui/file_manager/gallery/js/image_editor/image_editor.js b/ui/file_manager/gallery/js/image_editor/image_editor.js index aa70c00..677215bb 100644 --- a/ui/file_manager/gallery/js/image_editor/image_editor.js +++ b/ui/file_manager/gallery/js/image_editor/image_editor.js
@@ -274,6 +274,18 @@ this.name = name; this.title = title; this.message_ = 'GALLERY_ENTER_WHEN_DONE'; + + /** + * @type {ImageEditor} + * @private + */ + this.editor_ = null; + + /** + * @type {Viewport} + * @private + */ + this.viewport_ = null; }; ImageEditor.Mode.prototype = {__proto__: ImageBuffer.Overlay.prototype }; @@ -615,11 +627,15 @@ /** * Hide the tools that overlap the given rectangular frame. * - * @param {ImageRect} frame Hide the tool that overlaps this rect. - * @param {ImageRect} transparent But do not hide the tool that is completely - * inside this rect. + * @param {ImageRect=} opt_frame Hide the tool that overlaps this rect. + * @param {ImageRect=} opt_transparent But do not hide the tool that is + * completely inside this rect. */ -ImageEditor.prototype.hideOverlappingTools = function(frame, transparent) { +ImageEditor.prototype.hideOverlappingTools = function( + opt_frame, opt_transparent) { + var frame = opt_frame || null; + var transparent = opt_transparent || null; + var tools = this.rootContainer_.ownerDocument.querySelectorAll('.dimmable'); var changed = false; for (var i = 0; i != tools.length; i++) {
diff --git a/ui/file_manager/gallery/js/image_editor/image_encoder.js b/ui/file_manager/gallery/js/image_editor/image_encoder.js index 40c61be..d0c9cd00 100644 --- a/ui/file_manager/gallery/js/image_editor/image_encoder.js +++ b/ui/file_manager/gallery/js/image_editor/image_encoder.js
@@ -34,7 +34,7 @@ */ ImageEncoder.createMetadataEncoder = function(metadata) { var constructor = - (metadata && ImageEncoder.metadataEncoders[metadata.mimeType]) || + (metadata && ImageEncoder.metadataEncoders[metadata.media.mimeType]) || ImageEncoder.MetadataEncoder; return new constructor(metadata); }; @@ -76,7 +76,7 @@ // WebKit does not support canvas.toBlob yet so canvas.toDataURL is // the only way to use the Chrome built-in image encoder. var dataURL = - canvas.toDataURL(metadataEncoder.getMetadata().mimeType, quality); + canvas.toDataURL(metadataEncoder.getMetadata().media.mimeType, quality); ImageUtil.trace.reportTimer('dataurl'); var encodedImage = ImageEncoder.decodeDataURL(dataURL); @@ -105,7 +105,8 @@ appendSlice(ImageEncoder.stringToArrayBuffer( encodedImage, 0, encodedImage.length)); } - var blob = new Blob(slices, {type: metadataEncoder.getMetadata().mimeType}); + var blob = new Blob(slices, + {type: metadataEncoder.getMetadata().media.mimeType}); ImageUtil.trace.reportTimer('blob'); return blob; }; @@ -180,10 +181,10 @@ */ ImageEncoder.MetadataEncoder = function(original_metadata) { this.metadata_ = MetadataCache.cloneMetadata(original_metadata) || {}; - if (this.metadata_.mimeType != 'image/jpeg') { + if (this.metadata_.media.mimeType !== 'image/jpeg') { // Chrome can only encode JPEG and PNG. Force PNG mime type so that we // can save to file and generate a thumbnail. - this.metadata_.mimeType = 'image/png'; + this.metadata_.media.mimeType = 'image/png'; } }; @@ -211,7 +212,7 @@ ImageEncoder.MetadataEncoder.prototype.setThumbnailData = function(canvas, quality) { this.metadata_.thumbnailURL = - canvas.toDataURL(this.metadata_.mimeType, quality); + canvas.toDataURL(this.metadata_.media.mimeType, quality); delete this.metadata_.thumbnailTransform; };
diff --git a/ui/file_manager/gallery/js/image_editor/image_transform.js b/ui/file_manager/gallery/js/image_editor/image_transform.js index da2ec750..c6d372ed 100644 --- a/ui/file_manager/gallery/js/image_editor/image_transform.js +++ b/ui/file_manager/gallery/js/image_editor/image_transform.js
@@ -7,9 +7,70 @@ * * @extends {ImageEditor.Mode} * @constructor + * @struct */ ImageEditor.Mode.Crop = function() { ImageEditor.Mode.call(this, 'crop', 'GALLERY_CROP'); + + /** + * @type {HTMLDivElement} + * @private + */ + this.domOverlay_ = null; + + /** + * @type {HTMLDivElement} + * @private + */ + this.shadowTop_ = null; + + /** + * @type {HTMLDivElement} + * @private + */ + this.middleBox_ = null; + + /** + * @type {HTMLDivElement} + * @private + */ + this.shadowLeft_ = null; + + /** + * @type {HTMLDivElement} + * @private + */ + this.cropFrame_ = null; + + /** + * @type {HTMLDivElement} + * @private + */ + this.shadowRight_ = null; + + /** + * @type {HTMLDivElement} + * @private + */ + this.shadowBottom_ = null; + + /** + * @type {ImageEditor.Toolbar} + * @private + */ + this.toolbar_ = null; + + /** + * @type {?function()} + * @private + */ + this.onResizedBound_ = null; + + /** + * @type {DraggableRect} + * @private + */ + this.cropRect_ = null; }; ImageEditor.Mode.Crop.prototype = {__proto__: ImageEditor.Mode.prototype}; @@ -52,8 +113,6 @@ this.shadowBottom_.className = 'shadow'; this.domOverlay_.appendChild(this.shadowBottom_); - this.toolBar_ = null; - var cropFrame = this.cropFrame_; function addCropFrame(className) { var div = doc.createElement('div'); @@ -86,7 +145,7 @@ GALLERY_ASPECT_RATIO_7_5: 7 / 5, GALLERY_ASPECT_RATIO_16_9: 16 / 9 }; - for (name in aspects) { + for (var name in aspects) { toolbar.addButton( name, name, @@ -191,7 +250,7 @@ /** * Gets command to do the crop depending on the current state. * - * @return {Command.Crop} Crop command. + * @return {!Command.Crop} Crop command. */ ImageEditor.Mode.Crop.prototype.getCommand = function() { var cropImageRect = this.cropRect_.getRect(); @@ -202,11 +261,16 @@ * Creates default (initial) crop. */ ImageEditor.Mode.Crop.prototype.createDefaultCrop = function() { - var rect = this.getViewport().screenToImageRect( - new ImageRect(this.getViewport().getImageBoundsOnScreenClipped())); + var viewport = this.getViewport(); + assert(viewport); + + var rect = viewport.screenToImageRect( + viewport.getImageBoundsOnScreenClipped()); rect = rect.inflate( -Math.round(rect.width / 6), -Math.round(rect.height / 6)); - this.cropRect_ = new DraggableRect(rect, this.getViewport()); + + this.cropRect_ = new DraggableRect(rect, viewport); + this.positionDOM(); }; @@ -228,7 +292,7 @@ * @param {number} x Event X coordinate. * @param {number} y Event Y coordinate. * @param {boolean} touch True if it's a touch event, false if mouse. - * @return {function(number,number,boolean)} A function to be called on mouse + * @return {?function(number,number,boolean)} A function to be called on mouse * drag. It takes x coordinate value, y coordinate value, and shift key * flag. */ @@ -251,7 +315,7 @@ * * @param {number} x X coordinate of the event. * @param {number} y Y coordinate of the event. - * @return {ImageBuffer.DoubleTapAction} Action to perform as result. + * @return {!ImageBuffer.DoubleTapAction} Action to perform as result. */ ImageEditor.Mode.Crop.prototype.getDoubleTapAction = function(x, y) { return this.cropRect_.getDoubleTapAction(x, y); @@ -260,8 +324,8 @@ /** * A draggable rectangle over the image. * - * @param {ImageRect} rect Initial size of the image. - * @param {Viewport} viewport Viewport. + * @param {!ImageRect} rect Initial size of the image. + * @param {!Viewport} viewport Viewport. * @constructor */ function DraggableRect(rect, viewport) { @@ -272,17 +336,19 @@ * @type {{left: number, right: number, top: number, bottom: number}} * @private */ - this.bounds_ = {}; - this.bounds_[DraggableRect.LEFT] = rect.left; - this.bounds_[DraggableRect.RIGHT] = rect.left + rect.width; - this.bounds_[DraggableRect.TOP] = rect.top; - this.bounds_[DraggableRect.BOTTOM] = rect.top + rect.height; + this.bounds_ = { + left: rect.left, + right: rect.left + rect.width, + top: rect.top, + bottom: rect.top + rect.height + }; /** * Viewport. * - * @type {Viewport} + * @type {!Viewport} * @private + * @const */ this.viewport_ = viewport; @@ -369,10 +435,10 @@ /** * Obtains the geometry of the rectangle. - * @return {ImageRect} Geometry of the rectangle. + * @return {!ImageRect} Geometry of the rectangle. */ DraggableRect.prototype.getRect = function() { - return new ImageRect(this.bounds_); + return ImageRect.createFromBounds(this.bounds_); }; /** @@ -380,13 +446,18 @@ * * @param {number} x X coordinate for cursor. * @param {number} y Y coordinate for cursor. - * @param {boolean} touch Whether the operation is done by touch or not. - * @return {Object} Drag mode. + * @param {boolean=} opt_touch Whether the operation is done by touch or not. + * @return {{xSide: string, ySide:string, whole:boolean, newCrop:boolean}} + * Drag mode. */ -DraggableRect.prototype.getDragMode = function(x, y, touch) { +DraggableRect.prototype.getDragMode = function(x, y, opt_touch) { + var touch = opt_touch || false; + var result = { xSide: DraggableRect.NONE, - ySide: DraggableRect.NONE + ySide: DraggableRect.NONE, + whole: false, + newCrop: false }; var bounds = this.bounds_; @@ -470,7 +541,7 @@ * @param {number} initialScreenX X coordinate for cursor in the screen. * @param {number} initialScreenY Y coordinate for cursor in the screen. * @param {boolean} touch Whether the operation is done by touch or not. - * @return {function(number,number,boolean)} Drag handler that takes x + * @return {?function(number,number,boolean)} Drag handler that takes x * coordinate value, y coordinate value, and shift key flag. */ DraggableRect.prototype.getDragHandler = function( @@ -569,10 +640,9 @@ * * @param {number} x X coordinate for cursor. * @param {number} y Y coordinate for cursor. - * @param {boolean} touch Whether the operation is done by touch or not. - * @return {ImageBuffer.DoubleTapAction} Double tap action. + * @return {!ImageBuffer.DoubleTapAction} Double tap action. */ -DraggableRect.prototype.getDoubleTapAction = function(x, y, touch) { +DraggableRect.prototype.getDoubleTapAction = function(x, y) { var clipRect = this.viewport_.getImageBoundsOnScreenClipped(); if (clipRect.inside(x, y)) return ImageBuffer.DoubleTapAction.COMMIT; @@ -584,7 +654,7 @@ * Forces the aspect ratio. * * @param {number} aspectRatio Aspect ratio. - * @param {Object} clipRect Clip rect. + * @param {!Object} clipRect Clip rect. */ DraggableRect.prototype.forceAspectRatio = function(aspectRatio, clipRect) { // Get current rectangle scale.
diff --git a/ui/file_manager/gallery/js/image_editor/image_util.js b/ui/file_manager/gallery/js/image_editor/image_util.js index 7191ee4..3a767c2 100644 --- a/ui/file_manager/gallery/js/image_editor/image_util.js +++ b/ui/file_manager/gallery/js/image_editor/image_util.js
@@ -136,6 +136,16 @@ Array.apply(null, arguments)); } +/** + * Creates an image rect with a bound. + * @param {{left: number, top: number, right: number, bottom: number}} bound + * A bound. + * @return {!ImageRect} + */ +ImageRect.createFromBounds = function(bound) { + return new ImageRect(bound); +}; + ImageRect.prototype = { /** * Obtains the x coordinate of right edge. The most right pixels in the @@ -191,7 +201,7 @@ /** * @param {number} dx Difference in X. * @param {number} dy Difference in Y. - * @return {ImageRect} A rectangle inflated by (dx, dy), same center. + * @return {!ImageRect} A rectangle inflated by (dx, dy), same center. */ ImageRect.prototype.inflate = function(dx, dy) { return new ImageRect(
diff --git a/ui/file_manager/gallery/js/image_editor/viewport.js b/ui/file_manager/gallery/js/image_editor/viewport.js index 46c8b9c..f48cb1c 100644 --- a/ui/file_manager/gallery/js/image_editor/viewport.js +++ b/ui/file_manager/gallery/js/image_editor/viewport.js
@@ -273,9 +273,10 @@ /** * The image bounds on screen, which is clipped with the screen size. - * @return {ImageRect} + * @return {!ImageRect} */ Viewport.prototype.getImageBoundsOnScreenClipped = function() { + assert(this.imageBoundsOnScreenClipped_); return this.imageBoundsOnScreenClipped_; }; @@ -304,8 +305,8 @@ }; /** - * @param {ImageRect} rect Rectangle in screen coordinates. - * @return {ImageRect} Rectangle in image coordinates. + * @param {!ImageRect} rect Rectangle in screen coordinates. + * @return {!ImageRect} Rectangle in image coordinates. */ Viewport.prototype.screenToImageRect = function(rect) { return new ImageRect( @@ -401,7 +402,7 @@ zoomedHeight = ~~(this.imageBounds_.width * scale * this.zoom_); } var dx = Math.max(zoomedWidht - this.screenBounds_.width, 0) / 2; - var dy = Math.max(zoomedHeight - this.screenBounds_.height, 0) /2; + var dy = Math.max(zoomedHeight - this.screenBounds_.height, 0) / 2; this.offsetX_ = ImageUtil.clamp(-dx, this.offsetX_, dx); this.offsetY_ = ImageUtil.clamp(-dy, this.offsetY_, dy);
diff --git a/ui/gfx/font_render_params_win.cc b/ui/gfx/font_render_params_win.cc index 70b19d2..354d1b2 100644 --- a/ui/gfx/font_render_params_win.cc +++ b/ui/gfx/font_render_params_win.cc
@@ -19,7 +19,7 @@ return Singleton<CachedFontRenderParams>::get(); } - const FontRenderParams& GetParams(bool for_web_contents) { + const FontRenderParams& GetParams() { if (params_) return *params_; @@ -34,8 +34,7 @@ BOOL enabled = false; if (SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &enabled, 0) && enabled) { params_->antialiasing = true; - // Subpixel positioning is not yet implemented for UI. crbug.com/389649 - params_->subpixel_positioning = for_web_contents; + params_->subpixel_positioning = true; UINT type = 0; if (SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &type, 0) && @@ -78,8 +77,7 @@ if (family_out) NOTIMPLEMENTED(); // Customized font rendering settings are not supported, only defaults. - return CachedFontRenderParams::GetInstance()->GetParams( - query.for_web_contents); + return CachedFontRenderParams::GetInstance()->GetParams(); } } // namespace gfx
diff --git a/ui/gfx/render_text.cc b/ui/gfx/render_text.cc index 87e650b8..add661d 100644 --- a/ui/gfx/render_text.cc +++ b/ui/gfx/render_text.cc
@@ -722,7 +722,9 @@ } float RenderText::GetContentWidth() { - return GetStringSizeF().width() + (cursor_enabled_ ? 1 : 0); + // The cursor is drawn one pixel beyond the int-enclosed text bounds. + return cursor_enabled_ ? + std::ceil(GetStringSizeF().width()) + 1 : GetStringSizeF().width(); } int RenderText::GetBaseline() { @@ -1071,7 +1073,7 @@ HorizontalAlignment horizontal_alignment = GetCurrentHorizontalAlignment(); if (horizontal_alignment != ALIGN_LEFT) { #if defined(OS_WIN) - const int width = lines_[line_number].size.width() + + const int width = std::ceil(lines_[line_number].size.width()) + (cursor_enabled_ ? 1 : 0); #else const int width = GetContentWidth();
diff --git a/ui/gfx/render_text_harfbuzz.cc b/ui/gfx/render_text_harfbuzz.cc index b512355..508655b 100644 --- a/ui/gfx/render_text_harfbuzz.cc +++ b/ui/gfx/render_text_harfbuzz.cc
@@ -25,6 +25,9 @@ #include "ui/gfx/font_fallback_win.h" #endif +using gfx::internal::RangeF; +using gfx::internal::RoundRangeF; + namespace gfx { namespace { @@ -461,6 +464,11 @@ namespace internal { +Range RoundRangeF(const RangeF& range_f) { + return Range(std::floor(range_f.first + 0.5f), + std::floor(range_f.second + 0.5f)); +} + TextRunHarfBuzz::TextRunHarfBuzz() : width(0.0f), preceding_run_widths(0.0f), @@ -522,21 +530,19 @@ return missing; } -Range TextRunHarfBuzz::GetGraphemeBounds( +RangeF TextRunHarfBuzz::GetGraphemeBounds( base::i18n::BreakIterator* grapheme_iterator, size_t text_index) { DCHECK_LT(text_index, range.end()); - // TODO(msw): Support floating point grapheme bounds. - const int preceding_run_widths_int = SkScalarRoundToInt(preceding_run_widths); if (glyph_count == 0) - return Range(preceding_run_widths_int, preceding_run_widths_int + width); + return RangeF(preceding_run_widths, preceding_run_widths + width); Range chars; Range glyphs; GetClusterAt(text_index, &chars, &glyphs); - const int cluster_begin_x = SkScalarRoundToInt(positions[glyphs.start()].x()); - const int cluster_end_x = glyphs.end() < glyph_count ? - SkScalarRoundToInt(positions[glyphs.end()].x()) : width; + const float cluster_begin_x = positions[glyphs.start()].x(); + const float cluster_end_x = glyphs.end() < glyph_count ? + positions[glyphs.end()].x() : SkFloatToScalar(width); // A cluster consists of a number of code points and corresponds to a number // of glyphs that should be drawn together. A cluster can contain multiple @@ -563,13 +569,13 @@ cluster_width * before / static_cast<float>(total)); const int grapheme_end_x = cluster_begin_x + static_cast<int>(0.5f + cluster_width * (before + 1) / static_cast<float>(total)); - return Range(preceding_run_widths_int + grapheme_begin_x, - preceding_run_widths_int + grapheme_end_x); + return RangeF(preceding_run_widths + grapheme_begin_x, + preceding_run_widths + grapheme_end_x); } } - return Range(preceding_run_widths_int + cluster_begin_x, - preceding_run_widths_int + cluster_end_x); + return RangeF(preceding_run_widths + cluster_begin_x, + preceding_run_widths + cluster_end_x); } } // namespace internal @@ -596,7 +602,7 @@ EnsureLayout(); int x = ToTextPoint(point).x(); - int offset = 0; + float offset = 0; size_t run_index = GetRunContainingXCoord(x, &offset); if (run_index >= runs_.size()) return EdgeSelectionModel((x < 0) ? CURSOR_LEFT : CURSOR_RIGHT); @@ -646,8 +652,15 @@ return Range(GetStringSize().width()); const size_t layout_index = TextIndexToLayoutIndex(index); internal::TextRunHarfBuzz* run = runs_[run_index]; - Range bounds = run->GetGraphemeBounds(grapheme_iterator_.get(), layout_index); - return run->is_rtl ? Range(bounds.end(), bounds.start()) : bounds; + RangeF bounds = + run->GetGraphemeBounds(grapheme_iterator_.get(), layout_index); + // If cursor is enabled, extend the last glyph up to the rightmost cursor + // position since clients expect them to be contiguous. + if (cursor_enabled() && run_index == runs_.size() - 1 && + index == (run->is_rtl ? run->range.start() : run->range.end() - 1)) + bounds.second = std::ceil(bounds.second); + return RoundRangeF(run->is_rtl ? + RangeF(bounds.second, bounds.first) : bounds); } int RenderTextHarfBuzz::GetLayoutTextBaseline() { @@ -778,12 +791,12 @@ if (!intersection.IsValid()) continue; DCHECK(!intersection.is_reversed()); - const Range leftmost_character_x = run->GetGraphemeBounds( + const Range leftmost_character_x = RoundRangeF(run->GetGraphemeBounds( grapheme_iterator_.get(), - run->is_rtl ? intersection.end() - 1 : intersection.start()); - const Range rightmost_character_x = run->GetGraphemeBounds( + run->is_rtl ? intersection.end() - 1 : intersection.start())); + const Range rightmost_character_x = RoundRangeF(run->GetGraphemeBounds( grapheme_iterator_.get(), - run->is_rtl ? intersection.start() : intersection.end() - 1); + run->is_rtl ? intersection.start() : intersection.end() - 1)); Range range_x(leftmost_character_x.start(), rightmost_character_x.end()); DCHECK(!range_x.is_reversed()); if (range_x.is_empty()) @@ -911,7 +924,6 @@ ApplyTextShadows(&renderer); ApplyCompositionAndSelectionStyles(); - int current_x = 0; const Vector2d line_offset = GetLineOffset(0); for (size_t i = 0; i < runs_.size(); ++i) { const internal::TextRunHarfBuzz& run = *runs_[visual_to_logical_[i]]; @@ -920,11 +932,12 @@ renderer.SetFontRenderParams(run.render_params, background_is_transparent()); - Vector2d origin = line_offset + Vector2d(current_x, lines()[0].baseline); + Vector2d origin = line_offset + Vector2d(0, lines()[0].baseline); scoped_ptr<SkPoint[]> positions(new SkPoint[run.glyph_count]); for (size_t j = 0; j < run.glyph_count; ++j) { positions[j] = run.positions[j]; - positions[j].offset(SkIntToScalar(origin.x()), SkIntToScalar(origin.y())); + positions[j].offset(SkIntToScalar(origin.x()) + run.preceding_run_widths, + SkIntToScalar(origin.y())); } for (BreakList<SkColor>::const_iterator it = @@ -946,13 +959,11 @@ colored_glyphs.length()); int start_x = SkScalarRoundToInt(positions[colored_glyphs.start()].x()); int end_x = SkScalarRoundToInt((colored_glyphs.end() == run.glyph_count) ? - (run.width + SkIntToScalar(origin.x())) : + (run.width + run.preceding_run_widths + SkIntToScalar(origin.x())) : positions[colored_glyphs.end()].x()); renderer.DrawDecorations(start_x, origin.y(), end_x - start_x, run.underline, run.strike, run.diagonal_strike); } - - current_x += run.width; } renderer.EndDiagonalStrike(); @@ -972,12 +983,13 @@ return runs_.size(); } -size_t RenderTextHarfBuzz::GetRunContainingXCoord(int x, int* offset) const { +size_t RenderTextHarfBuzz::GetRunContainingXCoord(float x, + float* offset) const { DCHECK(!needs_layout_); if (x < 0) return runs_.size(); // Find the text run containing the argument point (assumed already offset). - int current_x = 0; + float current_x = 0; for (size_t i = 0; i < runs_.size(); ++i) { size_t run = visual_to_logical_[i]; current_x += runs_[run]->width; @@ -1139,7 +1151,7 @@ #endif // Try shaping with the fallback fonts. - for (auto family : fallback_families) { + for (const auto& family : fallback_families) { if (family == primary_family) continue; #if defined(OS_WIN)
diff --git a/ui/gfx/render_text_harfbuzz.h b/ui/gfx/render_text_harfbuzz.h index e71d50e8f..c87ceeb 100644 --- a/ui/gfx/render_text_harfbuzz.h +++ b/ui/gfx/render_text_harfbuzz.h
@@ -22,6 +22,12 @@ namespace internal { +// TODO(ckocagil): Make Range a template class and RangeF an instance of it. +typedef std::pair<float, float> RangeF; + +// Applies std::round to the start and end values of the given RangeF. +Range GFX_EXPORT RoundRangeF(const RangeF& range_f); + struct GFX_EXPORT TextRunHarfBuzz { TextRunHarfBuzz(); ~TextRunHarfBuzz(); @@ -42,8 +48,8 @@ void GetClusterAt(size_t pos, Range* chars, Range* glyphs) const; // Returns the grapheme bounds at |text_index|. Handles multi-grapheme glyphs. - Range GetGraphemeBounds(base::i18n::BreakIterator* grapheme_iterator, - size_t text_index); + RangeF GetGraphemeBounds(base::i18n::BreakIterator* grapheme_iterator, + size_t text_index); // Returns whether the given shaped run contains any missing glyphs. bool HasMissingGlyphs() const; @@ -116,7 +122,7 @@ // Return the run index that contains the argument; or the length of the // |runs_| vector if argument exceeds the text length or width. size_t GetRunContainingCaret(const SelectionModel& caret) const; - size_t GetRunContainingXCoord(int x, int* offset) const; + size_t GetRunContainingXCoord(float x, float* offset) const; // Given a |run|, returns the SelectionModel that contains the logical first // or last caret position inside (not at a boundary of) the run.
diff --git a/ui/gfx/render_text_unittest.cc b/ui/gfx/render_text_unittest.cc index 859689b5..774fd042 100644 --- a/ui/gfx/render_text_unittest.cc +++ b/ui/gfx/render_text_unittest.cc
@@ -2156,10 +2156,10 @@ internal::TextRunHarfBuzz* run = render_text.runs_[0]; base::i18n::BreakIterator* iter = render_text.grapheme_iterator_.get(); - Range first_grapheme_bounds = run->GetGraphemeBounds(iter, 0); + auto first_grapheme_bounds = run->GetGraphemeBounds(iter, 0); EXPECT_EQ(first_grapheme_bounds, run->GetGraphemeBounds(iter, 1)); - Range second_grapheme_bounds = run->GetGraphemeBounds(iter, 2); - EXPECT_EQ(first_grapheme_bounds.end(), second_grapheme_bounds.start()); + auto second_grapheme_bounds = run->GetGraphemeBounds(iter, 2); + EXPECT_EQ(first_grapheme_bounds.second, second_grapheme_bounds.first); } } @@ -2213,7 +2213,8 @@ for (size_t j = 0; j < 4; ++j) { SCOPED_TRACE(base::StringPrintf("Case %" PRIuS ", char %" PRIuS, i, j)); - EXPECT_EQ(cases[i].bounds[j], run.GetGraphemeBounds(iter.get(), j)); + EXPECT_EQ(cases[i].bounds[j], + internal::RoundRangeF(run.GetGraphemeBounds(iter.get(), j))); } } } @@ -2305,7 +2306,8 @@ run.range = Range(3, 8); run.glyph_count = 0; EXPECT_EQ(Range(0, 0), run.CharRangeToGlyphRange(Range(4, 5))); - EXPECT_EQ(Range(0, 0), run.GetGraphemeBounds(iter.get(), 4)); + EXPECT_EQ(Range(0, 0), + internal::RoundRangeF(run.GetGraphemeBounds(iter.get(), 4))); Range chars; Range glyphs; run.GetClusterAt(4, &chars, &glyphs); @@ -2373,4 +2375,35 @@ } #endif // defined(OS_WIN) +// Ensure that the width reported by RenderText is sufficient for drawing. Draws +// to a canvas and checks whether any pixel beyond the width is colored. +TEST_F(RenderTextTest, TextDoesntClip) { + const wchar_t* kTestStrings[] = { L"Save", L"Remove", L"TEST", L"W", L"WWW" }; + + skia::RefPtr<SkCanvas> sk_canvas = + skia::AdoptRef(SkCanvas::NewRasterN32(300, 50)); + scoped_ptr<Canvas> canvas( + Canvas::CreateCanvasWithoutScaling(sk_canvas.get(), 1.0f)); + scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); + render_text->SetDisplayRect(Rect(300, 50)); + render_text->SetHorizontalAlignment(gfx::ALIGN_LEFT); + render_text->SetColor(SK_ColorBLACK); + + for (size_t i = 0; i < arraysize(kTestStrings); ++i) { + sk_canvas->clear(SK_ColorWHITE); + render_text->SetText(WideToUTF16(kTestStrings[i])); + render_text->SetStyle(BOLD, true); + render_text->Draw(canvas.get()); + int width = render_text->GetStringSize().width(); + ASSERT_LT(width, 300); + const uint32* buffer = static_cast<const uint32*>( + sk_canvas->peekPixels(NULL, NULL)); + ASSERT_NE(nullptr, buffer); + for (int y = 0; y < 50; ++y) { + EXPECT_EQ(SK_ColorWHITE, buffer[width + y * 300]) + << "String: " << kTestStrings[i]; + } + } +} + } // namespace gfx
diff --git a/ui/gfx/win/direct_write.cc b/ui/gfx/win/direct_write.cc index 058f4be01..207b2c1 100644 --- a/ui/gfx/win/direct_write.cc +++ b/ui/gfx/win/direct_write.cc
@@ -4,11 +4,17 @@ #include "ui/gfx/win/direct_write.h" +#include <dwrite.h> + #include "base/basictypes.h" #include "base/command_line.h" #include "base/metrics/field_trial.h" #include "base/win/registry.h" +#include "base/win/scoped_comptr.h" #include "base/win/windows_version.h" +#include "skia/ext/fontmgr_default_win.h" +#include "third_party/skia/include/ports/SkTypeface_win.h" +#include "ui/gfx/platform_font_win.h" #include "ui/gfx/switches.h" #include "ui/gfx/win/dpi.h" @@ -59,5 +65,49 @@ return group_name != "Disabled"; } +void MaybeInitializeDirectWrite() { + static bool tried_dwrite_initialize = false; + if (tried_dwrite_initialize) + return; + tried_dwrite_initialize = true; + + if (!ShouldUseDirectWrite() || + CommandLine::ForCurrentProcess()->HasSwitch( + switches::kDisableDirectWriteForUI) || + CommandLine::ForCurrentProcess()->HasSwitch( + switches::kDisableHarfBuzzRenderText)) { + return; + } + + using DWriteCreateFactoryProc = decltype(DWriteCreateFactory)*; + HMODULE dwrite_dll = LoadLibraryW(L"dwrite.dll"); + if (!dwrite_dll) + return; + + DWriteCreateFactoryProc dwrite_create_factory_proc = + reinterpret_cast<DWriteCreateFactoryProc>( + GetProcAddress(dwrite_dll, "DWriteCreateFactory")); + // Not finding the DWriteCreateFactory function indicates a corrupt dll. + CHECK(dwrite_create_factory_proc); + + base::win::ScopedComPtr<IDWriteFactory> factory; + + CHECK(SUCCEEDED( + dwrite_create_factory_proc( + DWRITE_FACTORY_TYPE_SHARED, + __uuidof(IDWriteFactory), + reinterpret_cast<IUnknown**>(factory.Receive())))); + // The skia call to create a new DirectWrite font manager instance can fail + // if we are unable to get the system font collection from the DirectWrite + // factory. The GetSystemFontCollection method in the IDWriteFactory + // interface fails with E_INVALIDARG on certain Windows 7 gold versions + // (6.1.7600.*). We should just use GDI in these cases. + SkFontMgr* direct_write_font_mgr = SkFontMgr_New_DirectWrite(factory.get()); + if (direct_write_font_mgr) { + SetDefaultSkiaFactory(direct_write_font_mgr); + gfx::PlatformFontWin::SetDirectWriteFactory(factory.get()); + } +} + } // namespace win } // namespace gfx
diff --git a/ui/gfx/win/direct_write.h b/ui/gfx/win/direct_write.h index b621bf8..b69161ee 100644 --- a/ui/gfx/win/direct_write.h +++ b/ui/gfx/win/direct_write.h
@@ -13,6 +13,8 @@ // Returns whether DirectWrite font rendering should be used. GFX_EXPORT bool ShouldUseDirectWrite(); +GFX_EXPORT void MaybeInitializeDirectWrite(); + } // namespace win } // namespace gfx
diff --git a/ui/gfx/win/window_impl.cc b/ui/gfx/win/window_impl.cc index b0c4fa7a..5b1159e3 100644 --- a/ui/gfx/win/window_impl.cc +++ b/ui/gfx/win/window_impl.cc
@@ -33,10 +33,12 @@ struct ClassInfo { UINT style; HICON icon; + HICON small_icon; - ClassInfo(int style, HICON icon) + ClassInfo(int style, HICON icon, HICON small_icon) : style(style), - icon(icon) {} + icon(icon), + small_icon(small_icon) {} // Compares two ClassInfos. Returns true if all members match. bool Equals(const ClassInfo& other) const { @@ -135,7 +137,7 @@ reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH)), NULL, class_info.icon, - class_info.icon, + class_info.small_icon, &window_class); HMODULE instance = window_class.hInstance; ATOM atom = RegisterClassEx(&window_class); @@ -259,6 +261,10 @@ return NULL; } +HICON WindowImpl::GetSmallWindowIcon() const { + return NULL; +} + LRESULT WindowImpl::OnWndProc(UINT message, WPARAM w_param, LPARAM l_param) { LRESULT result = 0; @@ -305,7 +311,8 @@ ATOM WindowImpl::GetWindowClassAtom() { HICON icon = GetDefaultWindowIcon(); - ClassInfo class_info(initial_class_style(), icon); + HICON small_icon = GetSmallWindowIcon(); + ClassInfo class_info(initial_class_style(), icon, small_icon); return ClassRegistrar::GetInstance()->RetrieveClassAtom(class_info); }
diff --git a/ui/gfx/win/window_impl.h b/ui/gfx/win/window_impl.h index 34825367..2682d183 100644 --- a/ui/gfx/win/window_impl.h +++ b/ui/gfx/win/window_impl.h
@@ -51,6 +51,7 @@ // Returns the default window icon to use for windows of this type. virtual HICON GetDefaultWindowIcon() const; + virtual HICON GetSmallWindowIcon() const; // Returns the HWND associated with this Window. HWND hwnd() const { return hwnd_; }
diff --git a/ui/gl/gl_bindings.h b/ui/gl/gl_bindings.h index 595a31f8..0d25bbe 100644 --- a/ui/gl/gl_bindings.h +++ b/ui/gl/gl_bindings.h
@@ -272,6 +272,14 @@ #define GL_CONTEXT_LOST_KHR 0x0507 #endif /* GL_KHR_robustness */ +#ifndef GL_EXT_texture_rg +#define GL_EXT_texture_rg 1 +#define GL_RED_EXT 0x1903 +#define GL_RG_EXT 0x8227 +#define GL_R8_EXT 0x8229 +#define GL_RG8_EXT 0x822B +#endif /* GL_EXT_texture_rg */ + #define GL_GLEXT_PROTOTYPES 1 #if defined(OS_WIN)
diff --git a/ui/ozone/BUILD.gn b/ui/ozone/BUILD.gn index ec5a3a7..538f43cd 100644 --- a/ui/ozone/BUILD.gn +++ b/ui/ozone/BUILD.gn
@@ -92,6 +92,7 @@ "common/gpu/ozone_gpu_messages.h", "common/native_display_delegate_ozone.cc", "common/native_display_delegate_ozone.h", + "public/input_controller.h", "public/ozone_platform.cc", "public/ozone_platform.h", "public/ozone_switches.cc",
diff --git a/ui/ozone/ozone.gyp b/ui/ozone/ozone.gyp index e94e69d..556b43b 100644 --- a/ui/ozone/ozone.gyp +++ b/ui/ozone/ozone.gyp
@@ -101,6 +101,7 @@ 'common/gpu/ozone_gpu_messages.h', 'common/native_display_delegate_ozone.cc', 'common/native_display_delegate_ozone.h', + 'public/input_controller.h', 'public/ozone_platform.cc', 'public/ozone_platform.h', 'public/ozone_switches.cc',
diff --git a/ui/ozone/platform/caca/ozone_platform_caca.cc b/ui/ozone/platform/caca/ozone_platform_caca.cc index 6c7bdab..ecade63 100644 --- a/ui/ozone/platform/caca/ozone_platform_caca.cc +++ b/ui/ozone/platform/caca/ozone_platform_caca.cc
@@ -28,6 +28,9 @@ CursorFactoryOzone* GetCursorFactoryOzone() override { return cursor_factory_ozone_.get(); } + InputController* GetInputController() override { + return nullptr; // no input setting need + } GpuPlatformSupport* GetGpuPlatformSupport() override { return NULL; // no GPU support }
diff --git a/ui/ozone/platform/dri/dri_cursor.cc b/ui/ozone/platform/dri/dri_cursor.cc index 66a26e7a..49815e4 100644 --- a/ui/ozone/platform/dri/dri_cursor.cc +++ b/ui/ozone/platform/dri/dri_cursor.cc
@@ -108,6 +108,11 @@ return cursor_window_; } +void DriCursor::Reset() { + cursor_window_ = gfx::kNullAcceleratedWidget; + cursor_ = nullptr; +} + bool DriCursor::IsCursorVisible() { return cursor_.get(); }
diff --git a/ui/ozone/platform/dri/dri_cursor.h b/ui/ozone/platform/dri/dri_cursor.h index a3ea0d02..4eb14d4 100644 --- a/ui/ozone/platform/dri/dri_cursor.h +++ b/ui/ozone/platform/dri/dri_cursor.h
@@ -38,6 +38,7 @@ void ShowCursor(); void HideCursor(); gfx::AcceleratedWidget GetCursorWindow(); + void Reset(); // CursorDelegateEvdev: void MoveCursorTo(gfx::AcceleratedWidget widget,
diff --git a/ui/ozone/platform/dri/dri_window.cc b/ui/ozone/platform/dri/dri_window.cc index 373c05e9..05e23cc6 100644 --- a/ui/ozone/platform/dri/dri_window.cc +++ b/ui/ozone/platform/dri/dri_window.cc
@@ -77,9 +77,13 @@ return bounds_; } -void DriWindow::SetCapture() {} +void DriWindow::SetCapture() { + window_manager_->GrabEvents(widget_); +} -void DriWindow::ReleaseCapture() {} +void DriWindow::ReleaseCapture() { + window_manager_->UngrabEvents(widget_); +} void DriWindow::ToggleFullscreen() {} @@ -102,6 +106,11 @@ DCHECK(ne); Event* event = static_cast<Event*>(ne); + // If there is a grab, capture events here. + gfx::AcceleratedWidget grabber = window_manager_->event_grabber(); + if (grabber != gfx::kNullAcceleratedWidget) + return grabber == widget_; + if (event->IsLocatedEvent()) { LocatedEvent* located_event = static_cast<LocatedEvent*>(event); return bounds_.Contains(
diff --git a/ui/ozone/platform/dri/dri_window_manager.cc b/ui/ozone/platform/dri/dri_window_manager.cc index a20d115f..8bae641 100644 --- a/ui/ozone/platform/dri/dri_window_manager.cc +++ b/ui/ozone/platform/dri/dri_window_manager.cc
@@ -20,7 +20,9 @@ } // namespace DriWindowManager::DriWindowManager(DriGpuPlatformSupportHost* sender) - : last_allocated_widget_(0), cursor_(new DriCursor(this, sender)) { + : last_allocated_widget_(0), + cursor_(new DriCursor(this, sender)), + event_grabber_(gfx::kNullAcceleratedWidget) { } DriWindowManager::~DriWindowManager() { @@ -51,6 +53,8 @@ if (cursor_->GetCursorWindow() == widget) ResetCursorLocation(); + if (event_grabber_ == widget) + event_grabber_ = gfx::kNullAcceleratedWidget; } DriWindow* DriWindowManager::GetWindow(gfx::AcceleratedWidget widget) { @@ -71,15 +75,29 @@ } void DriWindowManager::ResetCursorLocation() { - gfx::AcceleratedWidget cursor_widget = gfx::kNullAcceleratedWidget; - gfx::PointF location; - if (!window_map_.empty()) { - WidgetToWindowMap::iterator it = window_map_.begin(); - cursor_widget = it->first; - location = GetDefaultCursorLocation(it->second); + if (window_map_.empty()) { + // When there is no more window left, reset the cursor to avoid + // sending incorrect messages to the gpu process. + cursor_->Reset(); + return; } + WidgetToWindowMap::iterator it = window_map_.begin(); + gfx::AcceleratedWidget cursor_widget = it->first; + gfx::PointF location = GetDefaultCursorLocation(it->second); cursor_->MoveCursorTo(cursor_widget, location); } +void DriWindowManager::GrabEvents(gfx::AcceleratedWidget widget) { + if (event_grabber_ != gfx::kNullAcceleratedWidget) + return; + event_grabber_ = widget; +} + +void DriWindowManager::UngrabEvents(gfx::AcceleratedWidget widget) { + if (event_grabber_ != widget) + return; + event_grabber_ = gfx::kNullAcceleratedWidget; +} + } // namespace ui
diff --git a/ui/ozone/platform/dri/dri_window_manager.h b/ui/ozone/platform/dri/dri_window_manager.h index 04c056d..cf768ae2 100644 --- a/ui/ozone/platform/dri/dri_window_manager.h +++ b/ui/ozone/platform/dri/dri_window_manager.h
@@ -46,6 +46,16 @@ DriCursor* cursor() const { return cursor_.get(); } + // Tries to set a given widget as the recipient for events. It will + // fail if there is already another widget as recipient. + void GrabEvents(gfx::AcceleratedWidget widget); + + // Unsets a given widget as the recipient for events. + void UngrabEvents(gfx::AcceleratedWidget widget); + + // Gets the current widget recipient of mouse events. + gfx::AcceleratedWidget event_grabber() const { return event_grabber_; } + private: // Reset the cursor location based on the list of active windows. void ResetCursorLocation(); @@ -57,6 +67,8 @@ scoped_ptr<DriCursor> cursor_; + gfx::AcceleratedWidget event_grabber_; + DISALLOW_COPY_AND_ASSIGN(DriWindowManager); };
diff --git a/ui/ozone/platform/dri/gbm.gypi b/ui/ozone/platform/dri/gbm.gypi index 6e4e22c..da0d96f 100644 --- a/ui/ozone/platform/dri/gbm.gypi +++ b/ui/ozone/platform/dri/gbm.gypi
@@ -24,6 +24,7 @@ '../base/ui_base.gyp:ui_base', '../events/events.gyp:events', '../events/ozone/events_ozone.gyp:events_ozone', + '../events/ozone/events_ozone.gyp:events_ozone_evdev', '../gfx/gfx.gyp:gfx', ], 'defines': [
diff --git a/ui/ozone/platform/dri/ozone_platform_dri.cc b/ui/ozone/platform/dri/ozone_platform_dri.cc index 4a2be7e..6b3a6a1 100644 --- a/ui/ozone/platform/dri/ozone_platform_dri.cc +++ b/ui/ozone/platform/dri/ozone_platform_dri.cc
@@ -55,6 +55,9 @@ CursorFactoryOzone* GetCursorFactoryOzone() override { return cursor_factory_ozone_.get(); } + InputController* GetInputController() override { + return event_factory_ozone_->input_controller(); + } GpuPlatformSupport* GetGpuPlatformSupport() override { return gpu_platform_support_.get(); }
diff --git a/ui/ozone/platform/dri/ozone_platform_gbm.cc b/ui/ozone/platform/dri/ozone_platform_gbm.cc index 541608f..ed88f89 100644 --- a/ui/ozone/platform/dri/ozone_platform_gbm.cc +++ b/ui/ozone/platform/dri/ozone_platform_gbm.cc
@@ -89,6 +89,9 @@ CursorFactoryOzone* GetCursorFactoryOzone() override { return cursor_factory_ozone_.get(); } + InputController* GetInputController() override { + return event_factory_ozone_->input_controller(); + } GpuPlatformSupport* GetGpuPlatformSupport() override { return gpu_platform_support_.get(); }
diff --git a/ui/ozone/platform/egltest/ozone_platform_egltest.cc b/ui/ozone/platform/egltest/ozone_platform_egltest.cc index 9d0745c1..d6d0850 100644 --- a/ui/ozone/platform/egltest/ozone_platform_egltest.cc +++ b/ui/ozone/platform/egltest/ozone_platform_egltest.cc
@@ -322,6 +322,9 @@ CursorFactoryOzone* GetCursorFactoryOzone() override { return cursor_factory_ozone_.get(); } + InputController* GetInputController() override { + return event_factory_ozone_->input_controller(); + } GpuPlatformSupport* GetGpuPlatformSupport() override { return gpu_platform_support_.get(); }
diff --git a/ui/ozone/platform/test/BUILD.gn b/ui/ozone/platform/test/BUILD.gn index d1ff717..fdbc934 100644 --- a/ui/ozone/platform/test/BUILD.gn +++ b/ui/ozone/platform/test/BUILD.gn
@@ -4,6 +4,8 @@ source_set("test") { sources = [ + "input_controller_test.cc", + "input_controller_test.h", "ozone_platform_test.cc", "ozone_platform_test.h", "test_window.cc",
diff --git a/ui/ozone/platform/test/input_controller_test.cc b/ui/ozone/platform/test/input_controller_test.cc new file mode 100644 index 0000000..9346b7d --- /dev/null +++ b/ui/ozone/platform/test/input_controller_test.cc
@@ -0,0 +1,53 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/ozone/platform/test/input_controller_test.h" + +#include "base/compiler_specific.h" + +namespace ui { + +InputControllerTest::InputControllerTest() { +} + +InputControllerTest::~InputControllerTest() { +} + +bool InputControllerTest::HasMouse() { + return false; +} + +bool InputControllerTest::HasTouchpad() { + return false; +} + +void InputControllerTest::SetTouchpadSensitivity(int value) { + ALLOW_UNUSED_LOCAL(value); +} + +void InputControllerTest::SetTapToClick(bool enabled) { + ALLOW_UNUSED_LOCAL(enabled); +} + +void InputControllerTest::SetThreeFingerClick(bool enabled) { + ALLOW_UNUSED_LOCAL(enabled); +} + +void InputControllerTest::SetTapDragging(bool enabled) { + ALLOW_UNUSED_LOCAL(enabled); +} + +void InputControllerTest::SetNaturalScroll(bool enabled) { + ALLOW_UNUSED_LOCAL(enabled); +} + +void InputControllerTest::SetMouseSensitivity(int value) { + ALLOW_UNUSED_LOCAL(value); +} + +void InputControllerTest::SetPrimaryButtonRight(bool right) { + ALLOW_UNUSED_LOCAL(right); +} + +} // namespace ui
diff --git a/ui/ozone/platform/test/input_controller_test.h b/ui/ozone/platform/test/input_controller_test.h new file mode 100644 index 0000000..4b72e2b --- /dev/null +++ b/ui/ozone/platform/test/input_controller_test.h
@@ -0,0 +1,38 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_OZONE_PLATFORM_TEST_INPUT_CONTROLLER_TEST_H_ +#define UI_OZONE_PLATFORM_TEST_INPUT_CONTROLLER_TEST_H_ + +#include "base/basictypes.h" +#include "ui/ozone/public/input_controller.h" + +namespace ui { + +// Ozone InputController implementation for test. +class InputControllerTest : public InputController { + public: + InputControllerTest(); + virtual ~InputControllerTest(); + + // InputController overrides: + // + // Interfaces for configuring input devices. + bool HasMouse() override; + bool HasTouchpad() override; + void SetTouchpadSensitivity(int value) override; + void SetTapToClick(bool enabled) override; + void SetThreeFingerClick(bool enabled) override; + void SetTapDragging(bool enabled) override; + void SetNaturalScroll(bool enabled) override; + void SetMouseSensitivity(int value) override; + void SetPrimaryButtonRight(bool right) override; + + private: + DISALLOW_COPY_AND_ASSIGN(InputControllerTest); +}; + +} // namespace ui + +#endif // UI_OZONE_PLATFORM_TEST_INPUT_CONTROLLER_TEST_H_
diff --git a/ui/ozone/platform/test/ozone_platform_test.cc b/ui/ozone/platform/test/ozone_platform_test.cc index 4e6a19f..9a5d373 100644 --- a/ui/ozone/platform/test/ozone_platform_test.cc +++ b/ui/ozone/platform/test/ozone_platform_test.cc
@@ -9,6 +9,7 @@ #include "ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h" #include "ui/events/platform/platform_event_source.h" #include "ui/ozone/common/native_display_delegate_ozone.h" +#include "ui/ozone/platform/test/input_controller_test.h" #include "ui/ozone/platform/test/test_window.h" #include "ui/ozone/platform/test/test_window_manager.h" #include "ui/ozone/public/cursor_factory_ozone.h" @@ -37,6 +38,9 @@ CursorFactoryOzone* GetCursorFactoryOzone() override { return cursor_factory_ozone_.get(); } + InputController* GetInputController() override { + return input_controller_.get(); + } GpuPlatformSupport* GetGpuPlatformSupport() override { return gpu_platform_support_.get(); } @@ -63,6 +67,7 @@ if (!PlatformEventSource::GetInstance()) platform_event_source_ = PlatformEventSource::CreateDefault(); + input_controller_.reset(new InputControllerTest); cursor_factory_ozone_.reset(new BitmapCursorFactoryOzone); gpu_platform_support_host_.reset(CreateStubGpuPlatformSupportHost()); } @@ -75,6 +80,7 @@ scoped_ptr<TestWindowManager> window_manager_; scoped_ptr<PlatformEventSource> platform_event_source_; scoped_ptr<CursorFactoryOzone> cursor_factory_ozone_; + scoped_ptr<InputControllerTest> input_controller_; scoped_ptr<GpuPlatformSupport> gpu_platform_support_; scoped_ptr<GpuPlatformSupportHost> gpu_platform_support_host_; base::FilePath file_path_;
diff --git a/ui/ozone/platform/test/test.gypi b/ui/ozone/platform/test/test.gypi index 785a8a34..e641abd 100644 --- a/ui/ozone/platform/test/test.gypi +++ b/ui/ozone/platform/test/test.gypi
@@ -25,6 +25,8 @@ '../gfx/gfx.gyp:gfx', ], 'sources': [ + 'input_controller_test.cc', + 'input_controller_test.h', 'ozone_platform_test.cc', 'ozone_platform_test.h', 'test_window.cc',
diff --git a/ui/ozone/public/input_controller.h b/ui/ozone/public/input_controller.h new file mode 100644 index 0000000..df5fd3b --- /dev/null +++ b/ui/ozone/public/input_controller.h
@@ -0,0 +1,44 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_OZONE_PUBLIC_INPUT_CONTROLLER_H_ +#define UI_OZONE_PUBLIC_INPUT_CONTROLLER_H_ + +#include "base/macros.h" +#include "ui/ozone/ozone_export.h" + +namespace ui { + +// Platform-specific interface for controlling input devices. +// +// The object provides methods for the preference page to configure input +// devices w.r.t. the user setting. On ChromeOS, this replaces the inputcontrol +// script that is originally located at /opt/google/chrome/. +class OZONE_EXPORT InputController { + public: + InputController() {} + virtual ~InputController() {} + + // Functions for checking devices existence. + virtual bool HasMouse() = 0; + virtual bool HasTouchpad() = 0; + + // Functions for changing device settings. + // + // See c/b/c/system/input_device_settings.h for more context. + virtual void SetTouchpadSensitivity(int value) = 0; + virtual void SetTapToClick(bool enabled) = 0; + virtual void SetThreeFingerClick(bool enabled) = 0; + virtual void SetTapDragging(bool enabled) = 0; + virtual void SetNaturalScroll(bool enabled) = 0; + virtual void SetMouseSensitivity(int value) = 0; + virtual void SetPrimaryButtonRight(bool right) = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(InputController); +}; + +} // namespace ui + +#endif // UI_OZONE_PUBLIC_INPUT_CONTROLLER_H_
diff --git a/ui/ozone/public/ozone_platform.h b/ui/ozone/public/ozone_platform.h index a4cd99ab..d27709a9 100644 --- a/ui/ozone/public/ozone_platform.h +++ b/ui/ozone/public/ozone_platform.h
@@ -15,6 +15,7 @@ namespace ui { class CursorFactoryOzone; +class InputController; class GpuPlatformSupport; class GpuPlatformSupportHost; class NativeDisplayDelegate; @@ -56,6 +57,7 @@ // inject these objects themselves. Ownership is retained by OzonePlatform. virtual ui::SurfaceFactoryOzone* GetSurfaceFactoryOzone() = 0; virtual ui::CursorFactoryOzone* GetCursorFactoryOzone() = 0; + virtual ui::InputController* GetInputController() = 0; virtual ui::GpuPlatformSupport* GetGpuPlatformSupport() = 0; virtual ui::GpuPlatformSupportHost* GetGpuPlatformSupportHost() = 0; virtual scoped_ptr<SystemInputInjector> CreateSystemInputInjector() = 0;
diff --git a/ui/resources/default_100_percent/common/app_list_apps_icon.png b/ui/resources/default_100_percent/common/app_list_apps_icon.png deleted file mode 100644 index 78f53cc..0000000 --- a/ui/resources/default_100_percent/common/app_list_apps_icon.png +++ /dev/null Binary files differ
diff --git a/ui/resources/default_100_percent/common/app_list_notifications_icon.png b/ui/resources/default_100_percent/common/app_list_notifications_icon.png deleted file mode 100644 index 81ad50c..0000000 --- a/ui/resources/default_100_percent/common/app_list_notifications_icon.png +++ /dev/null Binary files differ
diff --git a/ui/resources/default_100_percent/common/app_list_search_icon.png b/ui/resources/default_100_percent/common/app_list_search_icon.png deleted file mode 100644 index 9bd6c04..0000000 --- a/ui/resources/default_100_percent/common/app_list_search_icon.png +++ /dev/null Binary files differ
diff --git a/ui/resources/default_200_percent/common/app_list_apps_icon.png b/ui/resources/default_200_percent/common/app_list_apps_icon.png deleted file mode 100644 index 94f9507..0000000 --- a/ui/resources/default_200_percent/common/app_list_apps_icon.png +++ /dev/null Binary files differ
diff --git a/ui/resources/default_200_percent/common/app_list_notifications_icon.png b/ui/resources/default_200_percent/common/app_list_notifications_icon.png deleted file mode 100644 index 1bc5926..0000000 --- a/ui/resources/default_200_percent/common/app_list_notifications_icon.png +++ /dev/null Binary files differ
diff --git a/ui/resources/default_200_percent/common/app_list_search_icon.png b/ui/resources/default_200_percent/common/app_list_search_icon.png deleted file mode 100644 index 86b5c2f1..0000000 --- a/ui/resources/default_200_percent/common/app_list_search_icon.png +++ /dev/null Binary files differ
diff --git a/ui/resources/ui_resources.grd b/ui/resources/ui_resources.grd index a2d067d4..8976eb5 100644 --- a/ui/resources/ui_resources.grd +++ b/ui/resources/ui_resources.grd
@@ -16,18 +16,15 @@ BECAUSE YOUR RESOURCES ARE FUNCTIONALLY RELATED OR FALL UNDER THE SAME CONDITIONALS. --> <if expr="enable_app_list"> - <structure type="chrome_scaled_image" name="IDR_APP_LIST_APPS_ICON" file="common/app_list_apps_icon.png" /> <structure type="chrome_scaled_image" name="IDR_APP_LIST_EXPERIMENTAL_ICON" file="common/app_list_experimental_icon.png" /> <structure type="chrome_scaled_image" name="IDR_APP_LIST_ITEM_PROGRESS_BACKGROUND" file="common/app_list_progress_bar_background.png" /> <structure type="chrome_scaled_image" name="IDR_APP_LIST_ITEM_PROGRESS_LEFT" file="common/app_list_progress_bar_left.png" /> <structure type="chrome_scaled_image" name="IDR_APP_LIST_ITEM_PROGRESS_CENTER" file="common/app_list_progress_bar_center.png" /> <structure type="chrome_scaled_image" name="IDR_APP_LIST_ITEM_PROGRESS_RIGHT" file="common/app_list_progress_bar_right.png" /> - <structure type="chrome_scaled_image" name="IDR_APP_LIST_NOTIFICATIONS_ICON" file="common/app_list_notifications_icon.png" /> <structure type="chrome_scaled_image" name="IDR_APP_LIST_TOOLS_HOVER" file="common/app_list_tools_hover.png" /> <structure type="chrome_scaled_image" name="IDR_APP_LIST_TOOLS_NORMAL" file="common/app_list_tools_normal.png" /> <structure type="chrome_scaled_image" name="IDR_APP_LIST_TOOLS_PRESSED" file="common/app_list_tools_pressed.png" /> <structure type="chrome_scaled_image" name="IDR_APP_LIST_FOLDER_BACK_NORMAL" file="common/app_list_folder_back_normal.png" /> - <structure type="chrome_scaled_image" name="IDR_APP_LIST_SEARCH_ICON" file="common/app_list_search_icon.png" /> <structure type="chrome_scaled_image" name="IDR_APP_LIST_SPEECH_MIC_ON" file="common/app_list_mic_on.png" /> <structure type="chrome_scaled_image" name="IDR_APP_LIST_SPEECH_MIC_OFF" file="common/app_list_mic_off.png" /> <structure type="chrome_scaled_image" name="IDR_APP_LIST_SPEECH_MIC_RECORDING" file="common/app_list_mic_recording.png" />
diff --git a/ui/views/cocoa/bridged_native_widget.h b/ui/views/cocoa/bridged_native_widget.h index 4ebfaa07..c5730be 100644 --- a/ui/views/cocoa/bridged_native_widget.h +++ b/ui/views/cocoa/bridged_native_widget.h
@@ -34,6 +34,14 @@ class VIEWS_EXPORT BridgedNativeWidget : public internal::InputMethodDelegate, public FocusChangeListener { public: + // Ways of changing the visibility of the bridged NSWindow. + enum WindowVisibilityState { + HIDE_WINDOW, // Hides with -[NSWindow orderOut:]. + SHOW_AND_ACTIVATE_WINDOW, // Shows with -[NSWindow makeKeyAndOrderFront:]. + SHOW_INACTIVE, // Shows with -[NSWindow orderWindow:..]. Orders + // the window above its parent if it has one. + }; + // Creates one side of the bridge. |parent| must not be NULL. explicit BridgedNativeWidget(NativeWidgetMac* parent); virtual ~BridgedNativeWidget(); @@ -53,6 +61,10 @@ // take ownership of |view|. void SetRootView(views::View* view); + // Sets the desired visibility of the window and updates the visibility of + // descendant windows where necessary. + void SetVisibilityState(WindowVisibilityState new_state); + // Called internally by the NSWindowDelegate when the window is closing. void OnWindowWillClose(); @@ -72,6 +84,11 @@ // Called by the NSWindowDelegate when the size of the window changes. void OnSizeChanged(); + // Called by the NSWindowDelegate when the visibility of the window may have + // changed. For example, due to a (de)miniaturize operation, or the window + // being reordered in (or out of) the screen list. + void OnVisibilityChanged(); + // See widget.h for documentation. InputMethod* CreateInputMethod(); ui::InputMethod* GetHostInputMethod(); @@ -104,6 +121,9 @@ // Remove the given |child| from |child_windows_|. void RemoveChildWindow(BridgedNativeWidget* child); + // Notify descendants of a visibility change. + void NotifyVisibilityChangeDown(); + // Overridden from FocusChangeListener: void OnWillChangeFocus(View* focused_before, View* focused_now) override; @@ -133,6 +153,13 @@ // can not currently be changed. bool in_fullscreen_transition_; + // Stores the value last read from -[NSWindow isVisible], to detect visibility + // changes. + bool window_visible_; + + // If true, the window is either visible, or wants to be visible but is + // currently hidden due to having a hidden parent. + bool wants_to_be_visible_; DISALLOW_COPY_AND_ASSIGN(BridgedNativeWidget); };
diff --git a/ui/views/cocoa/bridged_native_widget.mm b/ui/views/cocoa/bridged_native_widget.mm index 9563237..98bdaea 100644 --- a/ui/views/cocoa/bridged_native_widget.mm +++ b/ui/views/cocoa/bridged_native_widget.mm
@@ -26,7 +26,9 @@ focus_manager_(NULL), parent_(nullptr), target_fullscreen_state_(false), - in_fullscreen_transition_(false) { + in_fullscreen_transition_(false), + window_visible_(false), + wants_to_be_visible_(false) { DCHECK(parent); window_delegate_.reset( [[ViewsNSWindowDelegate alloc] initWithBridgedNativeWidget:this]); @@ -52,6 +54,18 @@ window_.swap(window); [window_ setDelegate:window_delegate_]; + // Register for application hide notifications so that visibility can be + // properly tracked. This is not done in the delegate so that the lifetime is + // tied to the C++ object, rather than the delegate (which may be reference + // counted). This is required since the application hides do not send an + // orderOut: to individual windows. Unhide, however, does send an order + // message. + [[NSNotificationCenter defaultCenter] + addObserver:window_delegate_ + selector:@selector(onWindowOrderChanged:) + name:NSApplicationDidHideNotification + object:nil]; + // Validate the window's initial state, otherwise the bridge's initial // tracking state will be incorrect. DCHECK(![window_ isVisible]); @@ -69,6 +83,10 @@ parent_ = parent; parent->child_windows_.push_back(this); } + + // Widgets for UI controls (usually layered above web contents) start visible. + if (params.type == Widget::InitParams::TYPE_CONTROL) + SetVisibilityState(SHOW_INACTIVE); } void BridgedNativeWidget::SetFocusManager(FocusManager* focus_manager) { @@ -109,10 +127,54 @@ [window_ setContentView:bridged_view_]; } +void BridgedNativeWidget::SetVisibilityState(WindowVisibilityState new_state) { + // Ensure that: + // - A window with an invisible parent is not made visible. + // - A parent changing visibility updates child window visibility. + // * But only when changed via this function - ignore changes via the + // NSWindow API, or changes propagating out from here. + wants_to_be_visible_ = new_state != HIDE_WINDOW; + + if (new_state == HIDE_WINDOW) { + [window_ orderOut:nil]; + DCHECK(!window_visible_); + NotifyVisibilityChangeDown(); + return; + } + + DCHECK(wants_to_be_visible_); + + // If there's a hidden ancestor, return and wait for it to become visible. + for (BridgedNativeWidget* ancestor = parent(); + ancestor; + ancestor = ancestor->parent()) { + if (!ancestor->window_visible_) + return; + } + + if (new_state == SHOW_AND_ACTIVATE_WINDOW) { + [window_ makeKeyAndOrderFront:nil]; + [NSApp activateIgnoringOtherApps:YES]; + } else { + // ui::SHOW_STATE_INACTIVE is typically used to avoid stealing focus from a + // parent window. So, if there's a parent, order above that. Otherwise, this + // will order above all windows at the same level. + NSInteger parent_window_number = 0; + if (parent()) + parent_window_number = [parent()->ns_window() windowNumber]; + + [window_ orderWindow:NSWindowAbove + relativeTo:parent_window_number]; + } + DCHECK(window_visible_); + NotifyVisibilityChangeDown(); +} + void BridgedNativeWidget::OnWindowWillClose() { if (parent_) parent_->RemoveChildWindow(this); [window_ setDelegate:nil]; + [[NSNotificationCenter defaultCenter] removeObserver:window_delegate_]; native_widget_mac_->OnWindowWillClose(); } @@ -178,6 +240,23 @@ // TODO(tapted): If there's a layer, resize it here. } +void BridgedNativeWidget::OnVisibilityChanged() { + if (window_visible_ == [window_ isVisible]) + return; + + window_visible_ = [window_ isVisible]; + + // If arriving via SetVisible(), |wants_to_be_visible_| should already be set. + // If made visible externally (e.g. Cmd+H), just roll with it. Don't try (yet) + // to distinguish being *hidden* externally from being hidden by a parent + // window - we might not need that. + if (window_visible_) + wants_to_be_visible_ = true; + + native_widget_mac_->GetWidget()->OnNativeWidgetVisibilityChanged( + window_visible_); +} + InputMethod* BridgedNativeWidget::CreateInputMethod() { if (switches::IsTextInputFocusManagerEnabled()) return new NullInputMethod(); @@ -250,4 +329,34 @@ child->parent_ = nullptr; } +void BridgedNativeWidget::NotifyVisibilityChangeDown() { + // Child windows sometimes like to close themselves in response to visibility + // changes. That's supported, but only with the asynchronous Widget::Close(). + // Perform a heuristic to detect child removal that would break these loops. + const size_t child_count = child_windows_.size(); + if (!window_visible_) { + for (BridgedNativeWidget* child : child_windows_) { + if (child->window_visible_) { + [child->ns_window() orderOut:nil]; + child->NotifyVisibilityChangeDown(); + CHECK_EQ(child_count, child_windows_.size()); + } + } + return; + } + + NSInteger parent_window_number = [window_ windowNumber]; + for (BridgedNativeWidget* child: child_windows_) { + // Note: order the child windows on top, regardless of whether or not they + // are currently visible. They probably aren't, since the parent was hidden + // prior to this, but they could have been made visible in other ways. + if (child->wants_to_be_visible_) { + [child->ns_window() orderWindow:NSWindowAbove + relativeTo:parent_window_number]; + child->NotifyVisibilityChangeDown(); + CHECK_EQ(child_count, child_windows_.size()); + } + } +} + } // namespace views
diff --git a/ui/views/cocoa/bridged_native_widget_unittest.mm b/ui/views/cocoa/bridged_native_widget_unittest.mm index 911bf9c..41a97f53 100644 --- a/ui/views/cocoa/bridged_native_widget_unittest.mm +++ b/ui/views/cocoa/bridged_native_widget_unittest.mm
@@ -17,6 +17,7 @@ #import "testing/gtest_mac.h" #import "ui/gfx/test/ui_cocoa_test_helper.h" #import "ui/views/cocoa/bridged_content_view.h" +#import "ui/views/cocoa/native_widget_mac_nswindow.h" #include "ui/views/controls/textfield/textfield.h" #include "ui/views/ime/input_method.h" #include "ui/views/view.h" @@ -132,7 +133,7 @@ // NSWindow's behavior when attempting to toggle fullscreen state again, when // the last attempt failed but Cocoa has not yet sent // windowDidFailToEnterFullScreen:. -@interface BridgedNativeWidgetTestFullScreenWindow : NSWindow { +@interface BridgedNativeWidgetTestFullScreenWindow : NativeWidgetMacNSWindow { @private int ignoredToggleFullScreenCount_; }
diff --git a/ui/views/cocoa/native_widget_mac_nswindow.h b/ui/views/cocoa/native_widget_mac_nswindow.h new file mode 100644 index 0000000..943c3e2 --- /dev/null +++ b/ui/views/cocoa/native_widget_mac_nswindow.h
@@ -0,0 +1,18 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_VIEWS_COCOA_NATIVE_WIDGET_MAC_NSWINDOW_H_ +#define UI_VIEWS_COCOA_NATIVE_WIDGET_MAC_NSWINDOW_H_ + +#import <Cocoa/Cocoa.h> + +#include "ui/views/views_export.h" + +// The NSWindow used by BridgedNativeWidget. Provides hooks into AppKit that +// can only be accomplished by overriding methods. +VIEWS_EXPORT +@interface NativeWidgetMacNSWindow : NSWindow +@end + +#endif // UI_VIEWS_COCOA_NATIVE_WIDGET_MAC_NSWINDOW_H_
diff --git a/ui/views/cocoa/native_widget_mac_nswindow.mm b/ui/views/cocoa/native_widget_mac_nswindow.mm new file mode 100644 index 0000000..79f0d24c --- /dev/null +++ b/ui/views/cocoa/native_widget_mac_nswindow.mm
@@ -0,0 +1,39 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ui/views/cocoa/native_widget_mac_nswindow.h" + +#include "base/mac/foundation_util.h" +#import "ui/views/cocoa/views_nswindow_delegate.h" + +@interface NativeWidgetMacNSWindow () +- (ViewsNSWindowDelegate*)viewsNSWindowDelegate; +@end + +@implementation NativeWidgetMacNSWindow + +- (ViewsNSWindowDelegate*)viewsNSWindowDelegate { + return base::mac::ObjCCastStrict<ViewsNSWindowDelegate>([self delegate]); +} + +// Override canBecome{Key,Main}Window to always return YES, otherwise Windows +// with a styleMask of NSBorderlessWindowMask default to NO. +- (BOOL)canBecomeKeyWindow { + return YES; +} + +- (BOOL)canBecomeMainWindow { + return YES; +} + +// Override window order functions to intercept visibility changes, since there +// is no way to observe these changes via NSWindowDelegate. +- (void)orderWindow:(NSWindowOrderingMode)orderingMode + relativeTo:(NSInteger)otherWindowNumber { + [[self viewsNSWindowDelegate] onWindowOrderWillChange:orderingMode]; + [super orderWindow:orderingMode relativeTo:otherWindowNumber]; + [[self viewsNSWindowDelegate] onWindowOrderChanged:nil]; +} + +@end
diff --git a/ui/views/cocoa/views_nswindow_delegate.h b/ui/views/cocoa/views_nswindow_delegate.h index 2f1104c..ea89f41 100644 --- a/ui/views/cocoa/views_nswindow_delegate.h +++ b/ui/views/cocoa/views_nswindow_delegate.h
@@ -33,8 +33,9 @@ // Notify that the window has been reordered in (or removed from) the window // server's screen list. This is a substitute for -[NSWindowDelegate // windowDidExpose:], which is only sent for nonretained windows (those without -// a backing store). -- (void)onWindowOrderChanged; +// a backing store). |notification| is optional and can be set when redirecting +// a notification such as NSApplicationDidHideNotification. +- (void)onWindowOrderChanged:(NSNotification*)notification; @end
diff --git a/ui/views/cocoa/views_nswindow_delegate.mm b/ui/views/cocoa/views_nswindow_delegate.mm index 0d1d9a2..846ae806 100644 --- a/ui/views/cocoa/views_nswindow_delegate.mm +++ b/ui/views/cocoa/views_nswindow_delegate.mm
@@ -28,8 +28,9 @@ [parent_->ns_view() setWillShow:YES]; } -- (void)onWindowOrderChanged { +- (void)onWindowOrderChanged:(NSNotification*)notification { [parent_->ns_view() setWillShow:NO]; + parent_->OnVisibilityChanged(); } // NSWindowDelegate implementation.
diff --git a/ui/views/controls/button/menu_button_unittest.cc b/ui/views/controls/button/menu_button_unittest.cc index a537c1f..d3fbb1beb 100644 --- a/ui/views/controls/button/menu_button_unittest.cc +++ b/ui/views/controls/button/menu_button_unittest.cc
@@ -4,11 +4,9 @@ #include "ui/views/controls/button/menu_button.h" -#include "base/command_line.h" #include "base/memory/scoped_ptr.h" #include "base/strings/utf_string_conversions.h" #include "ui/base/dragdrop/drag_drop_types.h" -#include "ui/base/ui_base_switches.h" #include "ui/events/test/event_generator.h" #include "ui/views/controls/button/menu_button_listener.h" #include "ui/views/drag_controller.h" @@ -29,12 +27,6 @@ MenuButtonTest() : widget_(nullptr), button_(nullptr) {} ~MenuButtonTest() override {} - void SetUp() override { - CommandLine::ForCurrentProcess()->AppendSwitch( - switches::kEnableTouchFeedback); - ViewsTestBase::SetUp(); - } - void TearDown() override { if (widget_ && !widget_->IsClosed()) widget_->Close();
diff --git a/ui/views/controls/textfield/textfield_unittest.cc b/ui/views/controls/textfield/textfield_unittest.cc index 84da7d4e..73bf9f3 100644 --- a/ui/views/controls/textfield/textfield_unittest.cc +++ b/ui/views/controls/textfield/textfield_unittest.cc
@@ -31,7 +31,6 @@ #include "ui/views/test/test_views_delegate.h" #include "ui/views/test/views_test_base.h" #include "ui/views/widget/widget.h" -#include "ui/wm/core/default_screen_position_client.h" #include "url/gurl.h" #if defined(OS_WIN) @@ -160,14 +159,6 @@ } // ::testing::Test: - void SetUp() override { - ViewsTestBase::SetUp(); -#if defined(USE_AURA) - aura::client::SetScreenPositionClient(GetContext(), - &screen_position_client_); -#endif // !defined(USE_AURA) - } - void TearDown() override { if (widget_) widget_->Close(); @@ -384,7 +375,6 @@ private: ui::ClipboardType copied_to_clipboard_; - wm::DefaultScreenPositionClient screen_position_client_; DISALLOW_COPY_AND_ASSIGN(TextfieldTest); }; @@ -1451,12 +1441,12 @@ SendKeyEvent(0x05E1); EXPECT_EQ(WideToUTF16(L"ab\x05E1"), textfield_->text()); x = GetCursorBounds().x(); - EXPECT_EQ(prev_x, x); + EXPECT_GE(1, std::abs(x - prev_x)); SendKeyEvent(0x05E2); EXPECT_EQ(WideToUTF16(L"ab\x05E1\x5E2"), textfield_->text()); x = GetCursorBounds().x(); - EXPECT_EQ(prev_x, x); + EXPECT_GE(1, std::abs(x - prev_x)); // Clear text. SendKeyEvent(ui::VKEY_A, false, true); @@ -1472,7 +1462,7 @@ SendKeyEvent(0x05E2); EXPECT_EQ(WideToUTF16(L"\x05E1\x05E2"), textfield_->text()); x = GetCursorBounds().x(); - EXPECT_EQ(prev_x, x); + EXPECT_GE(1, std::abs(x - prev_x)); SendKeyEvent('a'); EXPECT_EQ(WideToUTF16(L"\x05E1\x5E2" L"a"), textfield_->text()); @@ -1501,7 +1491,7 @@ SendKeyEvent('b'); EXPECT_STR_EQ("ab", textfield_->text()); x = GetCursorBounds().x(); - EXPECT_EQ(prev_x, x); + EXPECT_GE(1, std::abs(x - prev_x)); SendKeyEvent(0x05E1); EXPECT_EQ(WideToUTF16(L"ab\x05E1"), textfield_->text()); @@ -1532,7 +1522,7 @@ SendKeyEvent('a'); EXPECT_EQ(WideToUTF16(L"\x05E1\x5E2" L"a"), textfield_->text()); x = GetCursorBounds().x(); - EXPECT_EQ(prev_x, x); + EXPECT_GE(1, std::abs(x - prev_x)); prev_x = x; SendKeyEvent('b');
diff --git a/ui/views/examples/examples_main.cc b/ui/views/examples/examples_main.cc index 5baf7029..b46f9a1 100644 --- a/ui/views/examples/examples_main.cc +++ b/ui/views/examples/examples_main.cc
@@ -30,6 +30,7 @@ #if defined(OS_WIN) #include "ui/base/win/scoped_ole_initializer.h" +#include "ui/gfx/win/direct_write.h" #endif #if defined(USE_X11) @@ -68,6 +69,10 @@ DCHECK(PathService::Get(ui::UI_TEST_PAK, &ui_test_pak_path)); ui::ResourceBundle::InitSharedInstanceWithPakPath(ui_test_pak_path); +#if defined(OS_WIN) + gfx::win::MaybeInitializeDirectWrite(); +#endif + #if defined(USE_AURA) aura::Env::CreateInstance(true); aura::Env::GetInstance()->set_context_factory(context_factory.get());
diff --git a/ui/views/test/test_views_delegate.h b/ui/views/test/test_views_delegate.h index 3e2b96f2..556ddc70 100644 --- a/ui/views/test/test_views_delegate.h +++ b/ui/views/test/test_views_delegate.h
@@ -36,6 +36,9 @@ } // ViewsDelegate: +#if defined(OS_WIN) + HICON GetSmallWindowIcon() const override { return nullptr; } +#endif void OnBeforeWidgetInit(Widget::InitParams* params, internal::NativeWidgetDelegate* delegate) override; ui::ContextFactory* GetContextFactory() override;
diff --git a/ui/views/test/views_test_helper_aura.cc b/ui/views/test/views_test_helper_aura.cc index 5bc83d39..9f5b877 100644 --- a/ui/views/test/views_test_helper_aura.cc +++ b/ui/views/test/views_test_helper_aura.cc
@@ -4,9 +4,11 @@ #include "ui/views/test/views_test_helper_aura.h" +#include "ui/aura/client/screen_position_client.h" #include "ui/aura/test/aura_test_helper.h" #include "ui/wm/core/capture_controller.h" #include "ui/wm/core/default_activation_client.h" +#include "ui/wm/core/default_screen_position_client.h" #include "ui/wm/core/wm_state.h" namespace views { @@ -28,11 +30,22 @@ void ViewsTestHelperAura::SetUp() { aura_test_helper_->SetUp(context_factory_); - new wm::DefaultActivationClient(aura_test_helper_->root_window()); + gfx::NativeWindow root_window = GetContext(); + new wm::DefaultActivationClient(root_window); wm_state_.reset(new wm::WMState); + + if (!aura::client::GetScreenPositionClient(root_window)) { + screen_position_client_.reset(new wm::DefaultScreenPositionClient); + aura::client::SetScreenPositionClient(root_window, + screen_position_client_.get()); + } } void ViewsTestHelperAura::TearDown() { + if (screen_position_client_.get() == + aura::client::GetScreenPositionClient(GetContext())) + aura::client::SetScreenPositionClient(GetContext(), nullptr); + aura_test_helper_->TearDown(); wm_state_.reset(); CHECK(!wm::ScopedCaptureClient::IsActive());
diff --git a/ui/views/test/views_test_helper_aura.h b/ui/views/test/views_test_helper_aura.h index fe79c89..96a26eb2 100644 --- a/ui/views/test/views_test_helper_aura.h +++ b/ui/views/test/views_test_helper_aura.h
@@ -11,6 +11,9 @@ #include "ui/views/test/views_test_helper.h" namespace aura { +namespace client { +class ScreenPositionClient; +} namespace test { class AuraTestHelper; } @@ -41,6 +44,7 @@ ui::ContextFactory* context_factory_; scoped_ptr<aura::test::AuraTestHelper> aura_test_helper_; scoped_ptr<wm::WMState> wm_state_; + scoped_ptr<aura::client::ScreenPositionClient> screen_position_client_; DISALLOW_COPY_AND_ASSIGN(ViewsTestHelperAura); };
diff --git a/ui/views/touchui/OWNERS b/ui/views/touchui/OWNERS index b8e32c10..8842bb9 100644 --- a/ui/views/touchui/OWNERS +++ b/ui/views/touchui/OWNERS
@@ -1 +1,2 @@ +mohsen@chromium.org sadrul@chromium.org
diff --git a/ui/views/touchui/touch_selection_controller_impl_unittest.cc b/ui/views/touchui/touch_selection_controller_impl_unittest.cc index 3fa7666f..5d0c693 100644 --- a/ui/views/touchui/touch_selection_controller_impl_unittest.cc +++ b/ui/views/touchui/touch_selection_controller_impl_unittest.cc
@@ -22,7 +22,6 @@ #include "ui/views/touchui/touch_selection_controller_impl.h" #include "ui/views/views_touch_selection_controller_factory.h" #include "ui/views/widget/widget.h" -#include "ui/wm/core/default_screen_position_client.h" using base::ASCIIToUTF16; using base::UTF16ToUTF8; @@ -77,7 +76,7 @@ void SetUp() override { ViewsTestBase::SetUp(); - SetUpRootWindowClients(GetContext()); + test_cursor_client_.reset(new aura::test::TestCursorClient(GetContext())); } void TearDown() override { @@ -277,19 +276,9 @@ Textfield* textfield_; scoped_ptr<TextfieldTestApi> textfield_test_api_; scoped_ptr<ViewsTouchSelectionControllerFactory> views_tsc_factory_; - scoped_ptr<wm::DefaultScreenPositionClient> screen_position_client_; scoped_ptr<aura::test::TestCursorClient> test_cursor_client_; private: - void SetUpRootWindowClients(aura::Window* root_window) { - if (!screen_position_client_) { - screen_position_client_.reset(new wm::DefaultScreenPositionClient()); - aura::client::SetScreenPositionClient(root_window, - screen_position_client_.get()); - test_cursor_client_.reset(new aura::test::TestCursorClient(root_window)); - } - } - DISALLOW_COPY_AND_ASSIGN(TouchSelectionControllerImplTest); };
diff --git a/ui/views/views.gyp b/ui/views/views.gyp index 01c2684b..8d32c84a 100644 --- a/ui/views/views.gyp +++ b/ui/views/views.gyp
@@ -32,6 +32,8 @@ 'cocoa/bridged_content_view.mm', 'cocoa/bridged_native_widget.h', 'cocoa/bridged_native_widget.mm', + 'cocoa/native_widget_mac_nswindow.h', + 'cocoa/native_widget_mac_nswindow.mm', 'cocoa/views_nswindow_delegate.h', 'cocoa/views_nswindow_delegate.mm', 'color_chooser/color_chooser_listener.h', @@ -549,6 +551,7 @@ 'view_unittest.cc', 'view_unittest_aura.cc', 'widget/native_widget_aura_unittest.cc', + 'widget/native_widget_mac_unittest.mm', 'widget/native_widget_unittest.cc', 'widget/root_view_unittest.cc', 'widget/widget_unittest.cc',
diff --git a/ui/views/views_delegate.h b/ui/views/views_delegate.h index b3dd4bbb..fea426f0 100644 --- a/ui/views/views_delegate.h +++ b/ui/views/views_delegate.h
@@ -95,6 +95,8 @@ #if defined(OS_WIN) // Retrieves the default window icon to use for windows if none is specified. virtual HICON GetDefaultWindowIcon() const; + // Retrieves the small window icon to use for windows if none is specified. + virtual HICON GetSmallWindowIcon() const = 0; // Returns true if the window passed in is in the Windows 8 metro // environment. virtual bool IsWindowInMetro(gfx::NativeWindow window) const;
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc index 8fac698..3752373d 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
@@ -941,7 +941,7 @@ void DesktopWindowTreeHostWin::HandleWindowSizeChanging() { if (compositor() && need_synchronous_paint_) { - compositor()->FinishAllRendering(); + compositor()->DisableSwapUntilResize(); // If we received the window size changing notification due to a restore or // maximize operation, then we can reset the need_synchronous_paint_ flag // here. For a sizing operation, the flag will be reset at the end of the
diff --git a/ui/views/widget/native_widget_mac.mm b/ui/views/widget/native_widget_mac.mm index 61e4320bd..d4984aa 100644 --- a/ui/views/widget/native_widget_mac.mm +++ b/ui/views/widget/native_widget_mac.mm
@@ -14,40 +14,10 @@ #include "ui/native_theme/native_theme.h" #import "ui/views/cocoa/bridged_content_view.h" #import "ui/views/cocoa/bridged_native_widget.h" +#import "ui/views/cocoa/native_widget_mac_nswindow.h" #import "ui/views/cocoa/views_nswindow_delegate.h" #include "ui/views/window/native_frame_view.h" -@interface NativeWidgetMacNSWindow : NSWindow -- (ViewsNSWindowDelegate*)viewsNSWindowDelegate; -@end - -@implementation NativeWidgetMacNSWindow - -- (ViewsNSWindowDelegate*)viewsNSWindowDelegate { - return base::mac::ObjCCastStrict<ViewsNSWindowDelegate>([self delegate]); -} - -// Override canBecome{Key,Main}Window to always return YES, otherwise Windows -// with a styleMask of NSBorderlessWindowMask default to NO. -- (BOOL)canBecomeKeyWindow { - return YES; -} - -- (BOOL)canBecomeMainWindow { - return YES; -} - -// Override orderWindow to intercept visibility changes, since there is no way -// to observe these changes via NSWindowDelegate. -- (void)orderWindow:(NSWindowOrderingMode)orderingMode - relativeTo:(NSInteger)otherWindowNumber { - [[self viewsNSWindowDelegate] onWindowOrderWillChange:orderingMode]; - [super orderWindow:orderingMode relativeTo:otherWindowNumber]; - [[self viewsNSWindowDelegate] onWindowOrderChanged]; -} - -@end - namespace views { namespace { @@ -346,7 +316,10 @@ } void NativeWidgetMac::Hide() { - NOTIMPLEMENTED(); + if (!bridge_) + return; + + bridge_->SetVisibilityState(BridgedNativeWidget::HIDE_WINDOW); } void NativeWidgetMac::ShowMaximizedWithBounds( @@ -355,6 +328,9 @@ } void NativeWidgetMac::ShowWithWindowState(ui::WindowShowState state) { + if (!bridge_) + return; + switch (state) { case ui::SHOW_STATE_DEFAULT: case ui::SHOW_STATE_NORMAL: @@ -369,12 +345,9 @@ NOTREACHED(); break; } - if (state == ui::SHOW_STATE_INACTIVE) { - if (!IsVisible()) - [GetNativeWindow() orderBack:nil]; - } else { - Activate(); - } + bridge_->SetVisibilityState(state == ui::SHOW_STATE_INACTIVE + ? BridgedNativeWidget::SHOW_INACTIVE + : BridgedNativeWidget::SHOW_AND_ACTIVATE_WINDOW); } bool NativeWidgetMac::IsVisible() const { @@ -382,8 +355,10 @@ } void NativeWidgetMac::Activate() { - [GetNativeWindow() makeKeyAndOrderFront:nil]; - [NSApp activateIgnoringOtherApps:YES]; + if (!bridge_) + return; + + bridge_->SetVisibilityState(BridgedNativeWidget::SHOW_AND_ACTIVATE_WINDOW); } void NativeWidgetMac::Deactivate() {
diff --git a/ui/views/widget/native_widget_mac_unittest.mm b/ui/views/widget/native_widget_mac_unittest.mm new file mode 100644 index 0000000..eaf69aa --- /dev/null +++ b/ui/views/widget/native_widget_mac_unittest.mm
@@ -0,0 +1,112 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ui/views/widget/native_widget_mac.h" + +#import <Cocoa/Cocoa.h> + +#include "ui/views/test/test_widget_observer.h" +#include "ui/views/test/widget_test.h" + +namespace views { +namespace test { + +// Tests for parts of NativeWidgetMac not covered by BridgedNativeWidget, which +// need access to Cocoa APIs. +typedef WidgetTest NativeWidgetMacTest; + +class WidgetChangeObserver : public TestWidgetObserver { + public: + WidgetChangeObserver(Widget* widget) + : TestWidgetObserver(widget), + gained_visible_count_(0), + lost_visible_count_(0) {} + + int gained_visible_count() const { return gained_visible_count_; } + int lost_visible_count() const { return lost_visible_count_; } + + private: + // WidgetObserver: + void OnWidgetVisibilityChanged(Widget* widget, + bool visible) override { + ++(visible ? gained_visible_count_ : lost_visible_count_); + } + + int gained_visible_count_; + int lost_visible_count_; + + DISALLOW_COPY_AND_ASSIGN(WidgetChangeObserver); +}; + +// Test visibility states triggered externally. +TEST_F(NativeWidgetMacTest, HideAndShowExternally) { + Widget* widget = CreateTopLevelPlatformWidget(); + NSWindow* ns_window = widget->GetNativeWindow(); + WidgetChangeObserver observer(widget); + + // Should initially be hidden. + EXPECT_FALSE(widget->IsVisible()); + EXPECT_FALSE([ns_window isVisible]); + EXPECT_EQ(0, observer.gained_visible_count()); + EXPECT_EQ(0, observer.lost_visible_count()); + + widget->Show(); + EXPECT_TRUE(widget->IsVisible()); + EXPECT_TRUE([ns_window isVisible]); + EXPECT_EQ(1, observer.gained_visible_count()); + EXPECT_EQ(0, observer.lost_visible_count()); + + widget->Hide(); + EXPECT_FALSE(widget->IsVisible()); + EXPECT_FALSE([ns_window isVisible]); + EXPECT_EQ(1, observer.gained_visible_count()); + EXPECT_EQ(1, observer.lost_visible_count()); + + widget->Show(); + EXPECT_TRUE(widget->IsVisible()); + EXPECT_TRUE([ns_window isVisible]); + EXPECT_EQ(2, observer.gained_visible_count()); + EXPECT_EQ(1, observer.lost_visible_count()); + + // Test when hiding individual windows. + [ns_window orderOut:nil]; + EXPECT_FALSE(widget->IsVisible()); + EXPECT_FALSE([ns_window isVisible]); + EXPECT_EQ(2, observer.gained_visible_count()); + EXPECT_EQ(2, observer.lost_visible_count()); + + [ns_window orderFront:nil]; + EXPECT_TRUE(widget->IsVisible()); + EXPECT_TRUE([ns_window isVisible]); + EXPECT_EQ(3, observer.gained_visible_count()); + EXPECT_EQ(2, observer.lost_visible_count()); + + // Test when hiding the entire application. This doesn't send an orderOut: + // to the NSWindow. + [NSApp hide:nil]; + EXPECT_FALSE(widget->IsVisible()); + EXPECT_FALSE([ns_window isVisible]); + EXPECT_EQ(3, observer.gained_visible_count()); + EXPECT_EQ(3, observer.lost_visible_count()); + + [NSApp unhideWithoutActivation]; + EXPECT_TRUE(widget->IsVisible()); + EXPECT_TRUE([ns_window isVisible]); + EXPECT_EQ(4, observer.gained_visible_count()); + EXPECT_EQ(3, observer.lost_visible_count()); + + // Hide again to test unhiding with an activation. + [NSApp hide:nil]; + EXPECT_EQ(4, observer.lost_visible_count()); + [NSApp unhide:nil]; + EXPECT_EQ(5, observer.gained_visible_count()); + + // No change when closing. + widget->CloseNow(); + EXPECT_EQ(4, observer.lost_visible_count()); + EXPECT_EQ(5, observer.gained_visible_count()); +} + +} // namespace test +} // namespace views
diff --git a/ui/views/widget/widget_interactive_uitest.cc b/ui/views/widget/widget_interactive_uitest.cc index ff00ed1..c37236e 100644 --- a/ui/views/widget/widget_interactive_uitest.cc +++ b/ui/views/widget/widget_interactive_uitest.cc
@@ -24,7 +24,6 @@ #include "ui/views/touchui/touch_selection_controller_impl.h" #include "ui/views/widget/widget.h" #include "ui/views/window/dialog_delegate.h" -#include "ui/wm/core/default_screen_position_client.h" #include "ui/wm/public/activation_client.h" #if defined(OS_WIN) @@ -765,7 +764,6 @@ views_delegate().set_use_desktop_native_widgets(true); #endif // !defined(OS_WIN) - wm::DefaultScreenPositionClient screen_position_client; Widget widget; Widget::InitParams init_params = CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS); @@ -782,10 +780,6 @@ textfield->RequestFocus(); textfield->SelectAll(true); TextfieldTestApi textfield_test_api(textfield); -#if defined(USE_AURA) - aura::client::SetScreenPositionClient(widget.GetNativeView()->GetRootWindow(), - &screen_position_client); -#endif // !defined(USE_AURA) RunPendingMessages(); @@ -798,8 +792,6 @@ EXPECT_TRUE(widget.IsActive()); EXPECT_TRUE(IsQuickMenuVisible(static_cast<TouchSelectionControllerImpl*>( textfield_test_api.touch_selection_controller()))); - aura::client::SetScreenPositionClient(widget.GetNativeView()->GetRootWindow(), - nullptr); } TEST_F(WidgetTestInteractive, DisableViewDoesNotActivateWidget) {
diff --git a/ui/views/widget/widget_unittest.cc b/ui/views/widget/widget_unittest.cc index d4b5cb9..f0d352a 100644 --- a/ui/views/widget/widget_unittest.cc +++ b/ui/views/widget/widget_unittest.cc
@@ -24,6 +24,7 @@ #include "ui/views/bubble/bubble_delegate.h" #include "ui/views/controls/textfield/textfield.h" #include "ui/views/test/test_views_delegate.h" +#include "ui/views/test/test_widget_observer.h" #include "ui/views/test/widget_test.h" #include "ui/views/views_delegate.h" #include "ui/views/widget/native_widget_delegate.h" @@ -287,16 +288,28 @@ EXPECT_FALSE(toplevel->IsVisible()); EXPECT_FALSE(child->IsVisible()); + // Showing a child with a hidden parent keeps the child hidden. child->Show(); - EXPECT_FALSE(toplevel->IsVisible()); EXPECT_FALSE(child->IsVisible()); + // Showing a hidden parent with a visible child shows both. toplevel->Show(); - EXPECT_TRUE(toplevel->IsVisible()); EXPECT_TRUE(child->IsVisible()); + // Hiding a parent hides both parent and child. + toplevel->Hide(); + EXPECT_FALSE(toplevel->IsVisible()); + EXPECT_FALSE(child->IsVisible()); + + // Hiding a child while the parent is hidden keeps the child hidden when the + // parent is shown. + child->Hide(); + toplevel->Show(); + EXPECT_TRUE(toplevel->IsVisible()); + EXPECT_FALSE(child->IsVisible()); + toplevel->CloseNow(); // |child| should be automatically destroyed with |toplevel|. } @@ -695,20 +708,26 @@ class WidgetObserverTest : public WidgetTest, public WidgetObserver { public: WidgetObserverTest() - : active_(NULL), - widget_closed_(NULL), - widget_activated_(NULL), - widget_shown_(NULL), - widget_hidden_(NULL), - widget_bounds_changed_(NULL) { + : active_(nullptr), + widget_closed_(nullptr), + widget_activated_(nullptr), + widget_shown_(nullptr), + widget_hidden_(nullptr), + widget_bounds_changed_(nullptr), + widget_to_close_on_hide_(nullptr) { } ~WidgetObserverTest() override {} + // Set a widget to Close() the next time the Widget being observed is hidden. + void CloseOnNextHide(Widget* widget) { + widget_to_close_on_hide_ = widget; + } + // Overridden from WidgetObserver: void OnWidgetDestroying(Widget* widget) override { if (active_ == widget) - active_ = NULL; + active_ = nullptr; widget_closed_ = widget; } @@ -720,16 +739,21 @@ active_ = widget; } else { if (widget_activated_ == widget) - widget_activated_ = NULL; + widget_activated_ = nullptr; widget_deactivated_ = widget; } } void OnWidgetVisibilityChanged(Widget* widget, bool visible) override { - if (visible) + if (visible) { widget_shown_ = widget; - else - widget_hidden_ = widget; + return; + } + widget_hidden_ = widget; + if (widget_to_close_on_hide_) { + widget_to_close_on_hide_->Close(); + widget_to_close_on_hide_ = nullptr; + } } void OnWidgetBoundsChanged(Widget* widget, @@ -738,13 +762,13 @@ } void reset() { - active_ = NULL; - widget_closed_ = NULL; - widget_activated_ = NULL; - widget_deactivated_ = NULL; - widget_shown_ = NULL; - widget_hidden_ = NULL; - widget_bounds_changed_ = NULL; + active_ = nullptr; + widget_closed_ = nullptr; + widget_activated_ = nullptr; + widget_deactivated_ = nullptr; + widget_shown_ = nullptr; + widget_hidden_ = nullptr; + widget_bounds_changed_ = nullptr; } Widget* NewWidget() { @@ -770,6 +794,8 @@ Widget* widget_shown_; Widget* widget_hidden_; Widget* widget_bounds_changed_; + + Widget* widget_to_close_on_hide_; }; TEST_F(WidgetObserverTest, DISABLED_ActivationChange) { @@ -902,6 +928,33 @@ EXPECT_FALSE(widget_bounds_changed()); } +// Test correct behavior when widgets close themselves in response to visibility +// changes. +TEST_F(WidgetObserverTest, ClosingOnHiddenParent) { + Widget* parent = NewWidget(); + Widget* child = CreateChildPlatformWidget(parent->GetNativeView()); + + TestWidgetObserver child_observer(child); + + EXPECT_FALSE(parent->IsVisible()); + EXPECT_FALSE(child->IsVisible()); + + // Note |child| is TYPE_CONTROL, which start shown. So no need to show the + // child separately. + parent->Show(); + EXPECT_TRUE(parent->IsVisible()); + EXPECT_TRUE(child->IsVisible()); + + // Simulate a child widget that closes itself when the parent is hidden. + CloseOnNextHide(child); + EXPECT_FALSE(child_observer.widget_closed()); + parent->Hide(); + RunPendingMessages(); + EXPECT_TRUE(child_observer.widget_closed()); + + parent->CloseNow(); +} + // Tests that SetBounds() and GetWindowBoundsInScreen() is symmetric when the // widget is visible and not maximized or fullscreen. TEST_F(WidgetTest, GetWindowBoundsInScreen) {
diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc index f35b155..322a21ef 100644 --- a/ui/views/win/hwnd_message_handler.cc +++ b/ui/views/win/hwnd_message_handler.cc
@@ -597,6 +597,9 @@ case ui::SHOW_STATE_MINIMIZED: native_show_state = SW_SHOWMINIMIZED; break; + case ui::SHOW_STATE_NORMAL: + native_show_state = SW_SHOWNORMAL; + break; default: native_show_state = delegate_->GetInitialShowState(); break; @@ -632,6 +635,11 @@ placement.showCmd = SW_SHOWMAXIMIZED; placement.rcNormalPosition = bounds.ToRECT(); SetWindowPlacement(hwnd(), &placement); + + // We need to explicitly activate the window, because if we're opened from a + // desktop shortcut while an existing window is already running it doesn't + // seem to be enough to use SW_SHOWMAXIMIZED to activate the window. + Activate(); } void HWNDMessageHandler::Hide() { @@ -905,9 +913,16 @@ HICON HWNDMessageHandler::GetDefaultWindowIcon() const { if (use_system_default_icon_) - return NULL; + return nullptr; return ViewsDelegate::views_delegate ? - ViewsDelegate::views_delegate->GetDefaultWindowIcon() : NULL; + ViewsDelegate::views_delegate->GetDefaultWindowIcon() : nullptr; +} + +HICON HWNDMessageHandler::GetSmallWindowIcon() const { + if (use_system_default_icon_) + return nullptr; + return ViewsDelegate::views_delegate ? + ViewsDelegate::views_delegate->GetSmallWindowIcon() : nullptr; } LRESULT HWNDMessageHandler::OnWndProc(UINT message, @@ -2286,8 +2301,15 @@ } } - if (DidClientAreaSizeChange(window_pos)) + RECT window_rect; + gfx::Size old_size; + if (GetWindowRect(hwnd(), &window_rect)) + old_size = gfx::Rect(window_rect).size(); + gfx::Size new_size = gfx::Size(window_pos->cx, window_pos->cy); + if ((old_size != new_size && !(window_pos->flags & SWP_NOSIZE)) || + window_pos->flags & SWP_FRAMECHANGED) { delegate_->HandleWindowSizeChanging(); + } if (ScopedFullscreenVisibility::IsHiddenForFullscreen(hwnd())) { // Prevent the window from being made visible if we've been asked to do so.
diff --git a/ui/views/win/hwnd_message_handler.h b/ui/views/win/hwnd_message_handler.h index 86d3d52..5270a5d 100644 --- a/ui/views/win/hwnd_message_handler.h +++ b/ui/views/win/hwnd_message_handler.h
@@ -216,6 +216,7 @@ // Overridden from WindowImpl: virtual HICON GetDefaultWindowIcon() const override; + virtual HICON GetSmallWindowIcon() const override; virtual LRESULT OnWndProc(UINT message, WPARAM w_param, LPARAM l_param) override;
diff --git a/ui/webui/resources/css/widgets.css b/ui/webui/resources/css/widgets.css index 320e7863..9504abd 100644 --- a/ui/webui/resources/css/widgets.css +++ b/ui/webui/resources/css/widgets.css
@@ -288,11 +288,15 @@ :-webkit-any(.checkbox, .radio) label { /* Don't expand horizontally: <http://crbug.com/112091>. */ - display: -webkit-inline-box; + display: inline-flex; padding-bottom: 7px; padding-top: 7px; } +:-webkit-any(.checkbox, .radio) label input { + flex-shrink: 0; +} + :-webkit-any(.checkbox, .radio) label input ~ span { -webkit-margin-start: 0.6em; -webkit-user-select: none;
diff --git a/ui/wm/core/transient_window_manager_unittest.cc b/ui/wm/core/transient_window_manager_unittest.cc index 93f7bc77..9473edc 100644 --- a/ui/wm/core/transient_window_manager_unittest.cc +++ b/ui/wm/core/transient_window_manager_unittest.cc
@@ -4,9 +4,7 @@ #include "ui/wm/core/transient_window_manager.h" -#include "ui/aura/client/visibility_client.h" #include "ui/aura/client/window_tree_client.h" -#include "ui/aura/layout_manager.h" #include "ui/aura/test/aura_test_base.h" #include "ui/aura/test/test_windows.h" #include "ui/aura/window.h" @@ -379,29 +377,6 @@ EXPECT_EQ("parent", destruction_order[1]); } -TEST_F(TransientWindowManagerTest, StackTransientsWhoseLayersHaveNoDelegate) { - // Create a window with several transients, then a couple windows on top. - scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window())); - scoped_ptr<Window> window11(CreateTransientChild(11, window1.get())); - scoped_ptr<Window> window12(CreateTransientChild(12, window1.get())); - scoped_ptr<Window> window13(CreateTransientChild(13, window1.get())); - scoped_ptr<Window> window2(CreateTestWindowWithId(2, root_window())); - scoped_ptr<Window> window3(CreateTestWindowWithId(3, root_window())); - - EXPECT_EQ("1 11 12 13 2 3", ChildWindowIDsAsString(root_window())); - - // Remove the delegates of a couple of transients, as if they are closing - // and animating out. - window11->layer()->set_delegate(NULL); - window13->layer()->set_delegate(NULL); - - // Move window1 to the front. All transients should move with it, and their - // order should be preserved. - root_window()->StackChildAtTop(window1.get()); - - EXPECT_EQ("2 3 1 11 12 13", ChildWindowIDsAsString(root_window())); -} - TEST_F(TransientWindowManagerTest, StackTransientsLayersRelativeToOtherTransients) { // Create a window with several transients, then a couple windows on top. @@ -429,256 +404,6 @@ EXPECT_EQ("1 11 12 13", ChildWindowIDsAsString(root_window())); } -TEST_F(TransientWindowManagerTest, - StackTransientsLayersRelativeToOtherTransientsNoLayerDelegate) { - // Create a window with several transients, then a couple windows on top. - scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window())); - scoped_ptr<Window> window11(CreateTransientChild(11, window1.get())); - scoped_ptr<Window> window12(CreateTransientChild(12, window1.get())); - scoped_ptr<Window> window13(CreateTransientChild(13, window1.get())); - scoped_ptr<Window> window2(CreateTestWindowWithId(2, root_window())); - scoped_ptr<Window> window3(CreateTestWindowWithId(3, root_window())); - - EXPECT_EQ("1 11 12 13 2 3", ChildWindowIDsAsString(root_window())); - - window1->layer()->set_delegate(NULL); - - // Stack 1 at top. - root_window()->StackChildAtTop(window1.get()); - EXPECT_EQ("2 3 1 11 12 13", ChildWindowIDsAsString(root_window())); -} - -class StackingMadrigalLayoutManager : public aura::LayoutManager { - public: - explicit StackingMadrigalLayoutManager(Window* root_window) - : root_window_(root_window) { - root_window_->SetLayoutManager(this); - } - ~StackingMadrigalLayoutManager() override {} - - private: - // Overridden from LayoutManager: - void OnWindowResized() override {} - void OnWindowAddedToLayout(Window* child) override {} - void OnWillRemoveWindowFromLayout(Window* child) override {} - void OnWindowRemovedFromLayout(Window* child) override {} - void OnChildWindowVisibilityChanged(Window* child, bool visible) override { - Window::Windows::const_iterator it = root_window_->children().begin(); - Window* last_window = NULL; - for (; it != root_window_->children().end(); ++it) { - if (*it == child && last_window) { - if (!visible) - root_window_->StackChildAbove(last_window, *it); - else - root_window_->StackChildAbove(*it, last_window); - break; - } - last_window = *it; - } - } - void SetChildBounds(Window* child, - const gfx::Rect& requested_bounds) override { - SetChildBoundsDirect(child, requested_bounds); - } - - Window* root_window_; - - DISALLOW_COPY_AND_ASSIGN(StackingMadrigalLayoutManager); -}; - -class StackingMadrigalVisibilityClient : public aura::client::VisibilityClient { - public: - explicit StackingMadrigalVisibilityClient(Window* root_window) - : ignored_window_(NULL) { - aura::client::SetVisibilityClient(root_window, this); - } - ~StackingMadrigalVisibilityClient() override {} - - void set_ignored_window(Window* ignored_window) { - ignored_window_ = ignored_window; - } - - private: - // Overridden from client::VisibilityClient: - void UpdateLayerVisibility(Window* window, bool visible) override { - if (!visible) { - if (window == ignored_window_) - window->layer()->set_delegate(NULL); - else - window->layer()->SetVisible(visible); - } else { - window->layer()->SetVisible(visible); - } - } - - Window* ignored_window_; - - DISALLOW_COPY_AND_ASSIGN(StackingMadrigalVisibilityClient); -}; - -// This test attempts to reconstruct a circumstance that can happen when the -// aura client attempts to manipulate the visibility and delegate of a layer -// independent of window visibility. -// A use case is where the client attempts to keep a window visible onscreen -// even after code has called Hide() on the window. The use case for this would -// be that window hides are animated (e.g. the window fades out). To prevent -// spurious updating the client code may also clear window's layer's delegate, -// so that the window cannot attempt to paint or update it further. The window -// uses the presence of a NULL layer delegate as a signal in stacking to note -// that the window is being manipulated by such a use case and its stacking -// should not be adjusted. -// One issue that can arise when a window opens two transient children, and the -// first is hidden. Subsequent attempts to activate the transient parent can -// result in the transient parent being stacked above the second transient -// child. A fix is made to Window::StackAbove to prevent this, and this test -// verifies this fix. -TEST_F(TransientWindowManagerTest, StackingMadrigal) { - new StackingMadrigalLayoutManager(root_window()); - StackingMadrigalVisibilityClient visibility_client(root_window()); - - scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window())); - scoped_ptr<Window> window11(CreateTransientChild(11, window1.get())); - - visibility_client.set_ignored_window(window11.get()); - - window11->Show(); - window11->Hide(); - - // As a transient, window11 should still be stacked above window1, even when - // hidden. - EXPECT_TRUE(aura::test::WindowIsAbove(window11.get(), window1.get())); - EXPECT_TRUE(aura::test::LayerIsAbove(window11.get(), window1.get())); - - // A new transient should still be above window1. It will appear behind - // window11 because we don't stack windows on top of targets with NULL - // delegates. - scoped_ptr<Window> window12(CreateTransientChild(12, window1.get())); - window12->Show(); - - EXPECT_TRUE(aura::test::WindowIsAbove(window12.get(), window1.get())); - EXPECT_TRUE(aura::test::LayerIsAbove(window12.get(), window1.get())); - - // In earlier versions of the StackChildAbove() method, attempting to stack - // window1 above window12 at this point would actually restack the layers - // resulting in window12's layer being below window1's layer (though the - // windows themselves would still be correctly stacked, so events would pass - // through.) - root_window()->StackChildAbove(window1.get(), window12.get()); - - // Both window12 and its layer should be stacked above window1. - EXPECT_TRUE(aura::test::WindowIsAbove(window12.get(), window1.get())); - EXPECT_TRUE(aura::test::LayerIsAbove(window12.get(), window1.get())); -} - -// Test for an issue where attempting to stack a primary window on top of a -// transient with a NULL layer delegate causes that primary window to be moved, -// but the layer order not changed to match. http://crbug.com/112562 -TEST_F(TransientWindowManagerTest, StackOverClosingTransient) { - scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window())); - scoped_ptr<Window> transient1(CreateTransientChild(11, window1.get())); - scoped_ptr<Window> window2(CreateTestWindowWithId(2, root_window())); - scoped_ptr<Window> transient2(CreateTransientChild(21, window2.get())); - - // Both windows and layers are stacked in creation order. - Window* root = root_window(); - ASSERT_EQ(4u, root->children().size()); - EXPECT_EQ(root->children()[0], window1.get()); - EXPECT_EQ(root->children()[1], transient1.get()); - EXPECT_EQ(root->children()[2], window2.get()); - EXPECT_EQ(root->children()[3], transient2.get()); - ASSERT_EQ(4u, root->layer()->children().size()); - EXPECT_EQ(root->layer()->children()[0], window1->layer()); - EXPECT_EQ(root->layer()->children()[1], transient1->layer()); - EXPECT_EQ(root->layer()->children()[2], window2->layer()); - EXPECT_EQ(root->layer()->children()[3], transient2->layer()); - EXPECT_EQ("1 11 2 21", ChildWindowIDsAsString(root_window())); - - // This brings window1 and its transient to the front. - root->StackChildAtTop(window1.get()); - EXPECT_EQ("2 21 1 11", ChildWindowIDsAsString(root_window())); - - EXPECT_EQ(root->children()[0], window2.get()); - EXPECT_EQ(root->children()[1], transient2.get()); - EXPECT_EQ(root->children()[2], window1.get()); - EXPECT_EQ(root->children()[3], transient1.get()); - EXPECT_EQ(root->layer()->children()[0], window2->layer()); - EXPECT_EQ(root->layer()->children()[1], transient2->layer()); - EXPECT_EQ(root->layer()->children()[2], window1->layer()); - EXPECT_EQ(root->layer()->children()[3], transient1->layer()); - - // Pretend we're closing the top-most transient, then bring window2 to the - // front. This mimics activating a browser window while the status bubble - // is fading out. The transient should stay topmost. - transient1->layer()->set_delegate(NULL); - root->StackChildAtTop(window2.get()); - - EXPECT_EQ(root->children()[0], window1.get()); - EXPECT_EQ(root->children()[1], window2.get()); - EXPECT_EQ(root->children()[2], transient2.get()); - EXPECT_EQ(root->children()[3], transient1.get()); - EXPECT_EQ(root->layer()->children()[0], window1->layer()); - EXPECT_EQ(root->layer()->children()[1], window2->layer()); - EXPECT_EQ(root->layer()->children()[2], transient2->layer()); - EXPECT_EQ(root->layer()->children()[3], transient1->layer()); - - // Close the transient. Remaining windows are stable. - transient1.reset(); - - ASSERT_EQ(3u, root->children().size()); - EXPECT_EQ(root->children()[0], window1.get()); - EXPECT_EQ(root->children()[1], window2.get()); - EXPECT_EQ(root->children()[2], transient2.get()); - ASSERT_EQ(3u, root->layer()->children().size()); - EXPECT_EQ(root->layer()->children()[0], window1->layer()); - EXPECT_EQ(root->layer()->children()[1], window2->layer()); - EXPECT_EQ(root->layer()->children()[2], transient2->layer()); - - // Open another window on top. - scoped_ptr<Window> window3(CreateTestWindowWithId(3, root_window())); - - ASSERT_EQ(4u, root->children().size()); - EXPECT_EQ(root->children()[0], window1.get()); - EXPECT_EQ(root->children()[1], window2.get()); - EXPECT_EQ(root->children()[2], transient2.get()); - EXPECT_EQ(root->children()[3], window3.get()); - ASSERT_EQ(4u, root->layer()->children().size()); - EXPECT_EQ(root->layer()->children()[0], window1->layer()); - EXPECT_EQ(root->layer()->children()[1], window2->layer()); - EXPECT_EQ(root->layer()->children()[2], transient2->layer()); - EXPECT_EQ(root->layer()->children()[3], window3->layer()); - - // Pretend we're closing the topmost non-transient window, then bring - // window2 to the top. It should not move. - window3->layer()->set_delegate(NULL); - root->StackChildAtTop(window2.get()); - - ASSERT_EQ(4u, root->children().size()); - EXPECT_EQ(root->children()[0], window1.get()); - EXPECT_EQ(root->children()[1], window2.get()); - EXPECT_EQ(root->children()[2], transient2.get()); - EXPECT_EQ(root->children()[3], window3.get()); - ASSERT_EQ(4u, root->layer()->children().size()); - EXPECT_EQ(root->layer()->children()[0], window1->layer()); - EXPECT_EQ(root->layer()->children()[1], window2->layer()); - EXPECT_EQ(root->layer()->children()[2], transient2->layer()); - EXPECT_EQ(root->layer()->children()[3], window3->layer()); - - // Bring window1 to the top. It should move ahead of window2, but not - // ahead of window3 (with NULL delegate). - root->StackChildAtTop(window1.get()); - - ASSERT_EQ(4u, root->children().size()); - EXPECT_EQ(root->children()[0], window2.get()); - EXPECT_EQ(root->children()[1], transient2.get()); - EXPECT_EQ(root->children()[2], window1.get()); - EXPECT_EQ(root->children()[3], window3.get()); - ASSERT_EQ(4u, root->layer()->children().size()); - EXPECT_EQ(root->layer()->children()[0], window2->layer()); - EXPECT_EQ(root->layer()->children()[1], transient2->layer()); - EXPECT_EQ(root->layer()->children()[2], window1->layer()); - EXPECT_EQ(root->layer()->children()[3], window3->layer()); -} - // Verifies TransientWindowObserver is notified appropriately. TEST_F(TransientWindowManagerTest, TransientWindowObserverNotified) { scoped_ptr<Window> parent(CreateTestWindowWithId(0, root_window()));
diff --git a/ui/wm/core/transient_window_stacking_client.cc b/ui/wm/core/transient_window_stacking_client.cc index f8dc42c..740fe99 100644 --- a/ui/wm/core/transient_window_stacking_client.cc +++ b/ui/wm/core/transient_window_stacking_client.cc
@@ -53,29 +53,6 @@ } } -// Adjusts |target| so that we don't attempt to stack on top of a window with a -// NULL delegate. -void SkipNullDelegates(Window::StackDirection direction, Window** target) { - const Window::Windows& children((*target)->parent()->children()); - size_t target_i = - std::find(children.begin(), children.end(), *target) - - children.begin(); - - // By convention we don't stack on top of windows with layers with NULL - // delegates. Walk backward to find a valid target window. See tests - // TransientWindowManagerTest.StackingMadrigal and StackOverClosingTransient - // for an explanation of this. - while (target_i > 0) { - const size_t index = direction == Window::STACK_ABOVE ? - target_i : target_i - 1; - if (!children[index]->layer() || - children[index]->layer()->delegate() != NULL) - break; - --target_i; - } - *target = children[target_i]; -} - } // namespace // static @@ -117,8 +94,6 @@ *target = siblings[target_i]; } - SkipNullDelegates(*direction, target); - // If we couldn't find a valid target position, don't move anything. if (*direction == Window::STACK_ABOVE && ((*target)->layer() && (*target)->layer()->delegate() == NULL)) {
diff --git a/ui/wm/core/transient_window_stacking_client_unittest.cc b/ui/wm/core/transient_window_stacking_client_unittest.cc index 23a99e72..7b8c127c 100644 --- a/ui/wm/core/transient_window_stacking_client_unittest.cc +++ b/ui/wm/core/transient_window_stacking_client_unittest.cc
@@ -174,42 +174,4 @@ EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get())); } -TEST_F(TransientWindowStackingClientTest, - StackWindowsWhoseLayersHaveNoDelegate) { - scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window())); - window1->layer()->set_name("1"); - scoped_ptr<Window> window2(CreateTestWindowWithId(2, root_window())); - window2->layer()->set_name("2"); - scoped_ptr<Window> window3(CreateTestWindowWithId(3, root_window())); - window3->layer()->set_name("3"); - - // This brings |window1| (and its layer) to the front. - root_window()->StackChildAbove(window1.get(), window3.get()); - EXPECT_EQ("2 3 1", ChildWindowIDsAsString(root_window())); - EXPECT_EQ("2 3 1", - ui::test::ChildLayerNamesAsString(*root_window()->layer())); - - // Since |window1| does not have a delegate, |window2| should not move in - // front of it, nor should its layer. - window1->layer()->set_delegate(NULL); - root_window()->StackChildAbove(window2.get(), window1.get()); - EXPECT_EQ("3 2 1", ChildWindowIDsAsString(root_window())); - EXPECT_EQ("3 2 1", - ui::test::ChildLayerNamesAsString(*root_window()->layer())); - - // It should still be possible to stack |window3| immediately below |window1|. - root_window()->StackChildBelow(window3.get(), window1.get()); - EXPECT_EQ("2 3 1", ChildWindowIDsAsString(root_window())); - EXPECT_EQ("2 3 1", - ui::test::ChildLayerNamesAsString(*root_window()->layer())); - - // Since neither |window3| nor |window1| have a delegate, |window2| should - // not move in front of either. - window3->layer()->set_delegate(NULL); - root_window()->StackChildBelow(window2.get(), window1.get()); - EXPECT_EQ("2 3 1", ChildWindowIDsAsString(root_window())); - EXPECT_EQ("2 3 1", - ui::test::ChildLayerNamesAsString(*root_window()->layer())); -} - } // namespace wm